aboutsummaryrefslogtreecommitdiffstats
path: root/old
diff options
context:
space:
mode:
authorThomas Duval <thomas.duval@orange.com>2020-06-03 10:06:52 +0200
committerThomas Duval <thomas.duval@orange.com>2020-06-03 10:06:52 +0200
commit7bb53c64da2dcf88894bfd31503accdd81498f3d (patch)
tree4310e12366818af27947b5e2c80cb162da93a4b5 /old
parentcbea4e360e9bfaa9698cf7c61c83c96a1ba89b8c (diff)
Update to new version 5.4HEADstable/jermamaster
Signed-off-by: Thomas Duval <thomas.duval@orange.com> Change-Id: Idcd868133d75928a1ffd74d749ce98503e0555ea
Diffstat (limited to 'old')
-rw-r--r--old/external_policy_checker/Changelog13
-rw-r--r--old/external_policy_checker/Dockerfile8
-rw-r--r--old/external_policy_checker/README.md46
-rw-r--r--old/external_policy_checker/conf/templates/cinder.policy.json99
-rw-r--r--old/external_policy_checker/conf/templates/glance.policy.json61
-rw-r--r--old/external_policy_checker/conf/templates/keystone.policy.json250
-rw-r--r--old/external_policy_checker/conf/templates/neutron.policy.json235
-rw-r--r--old/external_policy_checker/conf/templates/nova.policy.json488
-rw-r--r--old/external_policy_checker/external_policy_checker/__init__.py1
-rw-r--r--old/external_policy_checker/external_policy_checker/__main__.py9
-rw-r--r--old/external_policy_checker/external_policy_checker/conf_installer.py83
-rw-r--r--old/external_policy_checker/external_policy_checker/server.py135
-rw-r--r--old/external_policy_checker/requirements.txt1
-rw-r--r--old/external_policy_checker/setup.cfg2
-rw-r--r--old/external_policy_checker/setup.py47
-rw-r--r--old/moon_authz/Changelog39
-rw-r--r--old/moon_authz/Dockerfile15
-rw-r--r--old/moon_authz/LICENSE202
-rw-r--r--old/moon_authz/MANIFEST.in9
-rw-r--r--old/moon_authz/README.md8
-rw-r--r--old/moon_authz/moon_authz/__init__.py6
-rw-r--r--old/moon_authz/moon_authz/__main__.py4
-rw-r--r--old/moon_authz/moon_authz/api/__init__.py0
-rw-r--r--old/moon_authz/moon_authz/api/authorization.py397
-rw-r--r--old/moon_authz/moon_authz/api/update.py42
-rw-r--r--old/moon_authz/moon_authz/http_server.py142
-rw-r--r--old/moon_authz/moon_authz/server.py56
-rw-r--r--old/moon_authz/requirements.txt5
-rw-r--r--old/moon_authz/setup.py47
-rw-r--r--old/moon_authz/tests/unit_python/conftest.py29
-rw-r--r--old/moon_authz/tests/unit_python/mock_pods.py545
-rw-r--r--old/moon_authz/tests/unit_python/requirements.txt5
-rw-r--r--old/moon_authz/tests/unit_python/test_authz.py116
-rw-r--r--old/moon_authz/tests/unit_python/utilities.py182
-rw-r--r--old/moon_bouchon/Dockerfile8
-rw-r--r--old/moon_bouchon/README.md42
-rw-r--r--old/moon_bouchon/moon_bouchon/__init__.py7
-rw-r--r--old/moon_bouchon/moon_bouchon/__main__.py9
-rw-r--r--old/moon_bouchon/moon_bouchon/server.py138
-rw-r--r--old/moon_bouchon/requirements.txt1
-rw-r--r--old/moon_bouchon/setup.cfg2
-rw-r--r--old/moon_bouchon/setup.py47
-rw-r--r--old/moon_bouchon/tests/test_interface.py61
-rw-r--r--old/moon_bouchon/tests/test_wrapper.py38
-rw-r--r--old/moon_dashboard/.gitignore1
-rw-r--r--old/moon_dashboard/.gitlab-ci.yml64
-rw-r--r--old/moon_dashboard/Dockerfile38
-rw-r--r--old/moon_dashboard/LICENSE0
-rw-r--r--old/moon_dashboard/MANIFEST.in3
-rw-r--r--old/moon_dashboard/README.md40
-rw-r--r--old/moon_dashboard/README.rst39
-rw-r--r--old/moon_dashboard/babel-django.cfg5
-rw-r--r--old/moon_dashboard/babel-djangojs.cfg14
-rw-r--r--old/moon_dashboard/moon/__init__.py0
-rw-r--r--old/moon_dashboard/moon/api/__init__.py0
-rw-r--r--old/moon_dashboard/moon/api/moon_api.py0
-rw-r--r--old/moon_dashboard/moon/dashboard.py13
-rw-r--r--old/moon_dashboard/moon/enabled/_32000_moon.py19
-rw-r--r--old/moon_dashboard/moon/model/__init__.py0
-rw-r--r--old/moon_dashboard/moon/model/panel.py23
-rw-r--r--old/moon_dashboard/moon/model/templates/model/index.html16
-rw-r--r--old/moon_dashboard/moon/model/tests.py19
-rw-r--r--old/moon_dashboard/moon/model/urls.py20
-rw-r--r--old/moon_dashboard/moon/model/views.py22
-rw-r--r--old/moon_dashboard/moon/pdp/__init__.py0
-rw-r--r--old/moon_dashboard/moon/pdp/panel.py23
-rw-r--r--old/moon_dashboard/moon/pdp/templates/pdp/index.html16
-rw-r--r--old/moon_dashboard/moon/pdp/tests.py19
-rw-r--r--old/moon_dashboard/moon/pdp/urls.py20
-rw-r--r--old/moon_dashboard/moon/pdp/views.py22
-rw-r--r--old/moon_dashboard/moon/policy/__init__.py0
-rw-r--r--old/moon_dashboard/moon/policy/panel.py23
-rw-r--r--old/moon_dashboard/moon/policy/templates/policy/index.html16
-rw-r--r--old/moon_dashboard/moon/policy/tests.py19
-rw-r--r--old/moon_dashboard/moon/policy/urls.py20
-rw-r--r--old/moon_dashboard/moon/policy/views.py22
-rw-r--r--old/moon_dashboard/moon/static/moon/js/angular-resource.js863
-rwxr-xr-xold/moon_dashboard/moon/static/moon/js/import.service.js27
-rwxr-xr-xold/moon_dashboard/moon/static/moon/js/moon.module.js29
-rwxr-xr-xold/moon_dashboard/moon/static/moon/js/util.service.js140
-rwxr-xr-xold/moon_dashboard/moon/static/moon/js/util.service.spec.js86
-rw-r--r--old/moon_dashboard/moon/static/moon/model/model.controller.js316
-rw-r--r--old/moon_dashboard/moon/static/moon/model/model.html139
-rwxr-xr-xold/moon_dashboard/moon/static/moon/model/model.service.js291
-rwxr-xr-xold/moon_dashboard/moon/static/moon/model/model.service.spec.js288
-rw-r--r--old/moon_dashboard/moon/static/moon/pdp/pdp.controller.js125
-rw-r--r--old/moon_dashboard/moon/static/moon/pdp/pdp.html41
-rwxr-xr-xold/moon_dashboard/moon/static/moon/pdp/pdp.service.js123
-rwxr-xr-xold/moon_dashboard/moon/static/moon/pdp/pdp.service.spec.js143
-rw-r--r--old/moon_dashboard/moon/static/moon/policy/policy.controller.js341
-rw-r--r--old/moon_dashboard/moon/static/moon/policy/policy.html214
-rwxr-xr-xold/moon_dashboard/moon/static/moon/policy/policy.service.js428
-rwxr-xr-xold/moon_dashboard/moon/static/moon/policy/policy.service.spec.js487
-rw-r--r--old/moon_dashboard/moon/static/moon/scss/moon.scss58
-rw-r--r--old/moon_dashboard/moon/templates/moon/base.html11
-rw-r--r--old/moon_dashboard/run.sh42
-rw-r--r--old/moon_dashboard/setup.cfg24
-rw-r--r--old/moon_dashboard/setup.py14
-rw-r--r--old/moon_forming/.gitignore105
-rw-r--r--old/moon_forming/Changelog11
-rw-r--r--old/moon_forming/Dockerfile17
-rw-r--r--old/moon_forming/README.md47
-rw-r--r--old/moon_forming/conf2consul.py104
-rw-r--r--old/moon_forming/config_moon.sh39
-rw-r--r--old/moon_gui/.gitignore4
-rw-r--r--old/moon_gui/.jshintrc59
-rw-r--r--old/moon_gui/DEV.md49
-rw-r--r--old/moon_gui/Dockerfile18
-rw-r--r--old/moon_gui/README.md71
-rw-r--r--old/moon_gui/delivery/assets/css/main.css10
-rw-r--r--old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.eotbin0 -> 20335 bytes
-rw-r--r--old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.svg229
-rw-r--r--old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.ttfbin0 -> 41280 bytes
-rw-r--r--old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.woffbin0 -> 23320 bytes
-rwxr-xr-xold/moon_gui/delivery/assets/i18n/en.json1357
-rwxr-xr-xold/moon_gui/delivery/assets/i18n/fr.json1357
-rwxr-xr-xold/moon_gui/delivery/assets/img/ajax-loader.gifbin0 -> 673 bytes
-rwxr-xr-xold/moon_gui/delivery/assets/img/ajax-waiting.gifbin0 -> 10819 bytes
-rwxr-xr-xold/moon_gui/delivery/assets/img/arrow-link.gifbin0 -> 87 bytes
-rw-r--r--old/moon_gui/delivery/assets/img/et.jpgbin0 -> 31641 bytes
-rwxr-xr-xold/moon_gui/delivery/assets/img/favicon.icobin0 -> 318 bytes
-rwxr-xr-xold/moon_gui/delivery/assets/img/logo-openstack.pngbin0 -> 3180 bytes
-rwxr-xr-xold/moon_gui/delivery/assets/img/logo-orange.gifbin0 -> 981 bytes
-rw-r--r--old/moon_gui/delivery/html/authentication/authentication.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/common/404/404.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/common/compatibility/compatibility.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/common/footer/footer.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/common/header/header.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/common/loader/loader.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/common/waiting/waiting.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/dashboard/dashboard.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/logs/logs.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/model/action/model-add.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/model/action/model-delete.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/model/action/model-view.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/model/edit/metadata/metadata-edit.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/model/edit/metadata/metadata-list.tpl.html88
-rw-r--r--old/moon_gui/delivery/html/model/edit/metarules/action/mapping/metarules-add.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/model/edit/metarules/action/mapping/metarules-map.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/model/edit/metarules/action/mapping/metarules-unmap.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/model/edit/metarules/action/metarules-edit-basic.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/model/edit/metarules/action/metarules-edit.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/model/edit/metarules/metarules-list.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/model/edit/model-edit-basic.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/model/edit/model-edit.tpl.html4
-rw-r--r--old/moon_gui/delivery/html/model/model-list.tpl.html6
-rw-r--r--old/moon_gui/delivery/html/pdp/action/pdp-add.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/pdp/action/pdp-delete.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/pdp/edit/pdp-edit-basic.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/pdp/edit/pdp-edit.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/pdp/pdp-list.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/policy/action/mapping/policy-map.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/policy/action/mapping/policy-unmap.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/policy/action/policy-add.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/policy/action/policy-delete.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/policy/edit/parameter/assignments/assignments-edit.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/policy/edit/parameter/assignments/assignments-list.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/policy/edit/parameter/data/data-edit.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/policy/edit/parameter/data/data-list.tpl.html113
-rw-r--r--old/moon_gui/delivery/html/policy/edit/parameter/perimeter/perimeter-edit.tpl.html11
-rw-r--r--old/moon_gui/delivery/html/policy/edit/parameter/perimeter/perimeter-list.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/policy/edit/parameter/rules/rules-edit.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/policy/edit/parameter/rules/rules-list.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/policy/edit/policy-edit-basic.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/policy/edit/policy-edit.tpl.html13
-rw-r--r--old/moon_gui/delivery/html/policy/policy-list.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/policy/policy-mapped-list.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/project/action/mapping/project-map.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/project/action/mapping/project-unmap.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/project/action/project-add.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/project/action/project-delete.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/project/action/project-view.tpl.html1
-rw-r--r--old/moon_gui/delivery/html/project/project-list.tpl.html1
-rw-r--r--old/moon_gui/delivery/index.html34
-rw-r--r--old/moon_gui/delivery/js/app.js4
-rw-r--r--old/moon_gui/delivery/js/modules.js20
-rwxr-xr-xold/moon_gui/delivery/version.json1
-rw-r--r--old/moon_gui/gulpfile.js213
-rw-r--r--old/moon_gui/package.json54
-rw-r--r--old/moon_gui/run.sh17
-rwxr-xr-xold/moon_gui/static/app/authentication/authentication.controller.js58
-rwxr-xr-xold/moon_gui/static/app/authentication/authentication.tpl.html28
-rwxr-xr-xold/moon_gui/static/app/common/404/404.tpl.html3
-rwxr-xr-xold/moon_gui/static/app/common/compatibility/compatibility.tpl.html26
-rwxr-xr-xold/moon_gui/static/app/common/footer/footer.controller.js54
-rwxr-xr-xold/moon_gui/static/app/common/footer/footer.tpl.html7
-rwxr-xr-xold/moon_gui/static/app/common/header/header.controller.js56
-rwxr-xr-xold/moon_gui/static/app/common/header/header.tpl.html52
-rwxr-xr-xold/moon_gui/static/app/common/loader/loader.dir.js19
-rwxr-xr-xold/moon_gui/static/app/common/loader/loader.tpl.html1
-rwxr-xr-xold/moon_gui/static/app/common/waiting/waiting.tpl.html15
-rwxr-xr-xold/moon_gui/static/app/dashboard/dashboard.tpl.html14
-rwxr-xr-xold/moon_gui/static/app/logs/logs.controller.js16
-rwxr-xr-xold/moon_gui/static/app/logs/logs.tpl.html3
-rwxr-xr-xold/moon_gui/static/app/model/action/model-add.tpl.html66
-rwxr-xr-xold/moon_gui/static/app/model/action/model-delete.tpl.html39
-rwxr-xr-xold/moon_gui/static/app/model/action/model-view.tpl.html41
-rwxr-xr-xold/moon_gui/static/app/model/action/model.controller.add.js71
-rwxr-xr-xold/moon_gui/static/app/model/action/model.controller.delete.js72
-rwxr-xr-xold/moon_gui/static/app/model/action/model.controller.view.js53
-rwxr-xr-xold/moon_gui/static/app/model/edit/metadata/metadata-edit.tpl.html99
-rwxr-xr-xold/moon_gui/static/app/model/edit/metadata/metadata-list.tpl.html491
-rwxr-xr-xold/moon_gui/static/app/model/edit/metadata/metadata.edit.dir.js332
-rwxr-xr-xold/moon_gui/static/app/model/edit/metadata/metadata.list.dir.js374
-rwxr-xr-xold/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-add.tpl.html50
-rwxr-xr-xold/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-map.tpl.html102
-rwxr-xr-xold/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-unmap.tpl.html35
-rwxr-xr-xold/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.controller.add.js99
-rwxr-xr-xold/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.map.controller.js213
-rwxr-xr-xold/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.unmap.controller.js74
-rwxr-xr-xold/moon_gui/static/app/model/edit/metarules/action/metarules-edit-basic.tpl.html67
-rwxr-xr-xold/moon_gui/static/app/model/edit/metarules/action/metarules-edit.tpl.html62
-rwxr-xr-xold/moon_gui/static/app/model/edit/metarules/action/metarules.controller.edit.js49
-rwxr-xr-xold/moon_gui/static/app/model/edit/metarules/action/metarules.edit.basic.dir.js100
-rwxr-xr-xold/moon_gui/static/app/model/edit/metarules/metarules-list.tpl.html138
-rwxr-xr-xold/moon_gui/static/app/model/edit/metarules/metarules.list.dir.js241
-rwxr-xr-xold/moon_gui/static/app/model/edit/model-edit-basic.tpl.html65
-rwxr-xr-xold/moon_gui/static/app/model/edit/model-edit.tpl.html70
-rwxr-xr-xold/moon_gui/static/app/model/edit/model.controller.edit.js61
-rwxr-xr-xold/moon_gui/static/app/model/edit/model.edit.basic.dir.js97
-rwxr-xr-xold/moon_gui/static/app/model/model-list.tpl.html123
-rwxr-xr-xold/moon_gui/static/app/model/model.controller.list.js195
-rw-r--r--old/moon_gui/static/app/moon.constants.js79
-rwxr-xr-xold/moon_gui/static/app/moon.module.js362
-rwxr-xr-xold/moon_gui/static/app/pdp/action/pdp-add.tpl.html88
-rwxr-xr-xold/moon_gui/static/app/pdp/action/pdp-delete.tpl.html35
-rwxr-xr-xold/moon_gui/static/app/pdp/action/pdp.controller.add.js108
-rwxr-xr-xold/moon_gui/static/app/pdp/action/pdp.controller.delete.js66
-rwxr-xr-xold/moon_gui/static/app/pdp/edit/pdp-edit-basic.tpl.html65
-rwxr-xr-xold/moon_gui/static/app/pdp/edit/pdp-edit.tpl.html64
-rwxr-xr-xold/moon_gui/static/app/pdp/edit/pdp.controller.edit.js50
-rwxr-xr-xold/moon_gui/static/app/pdp/edit/pdp.edit.basic.dir.js97
-rwxr-xr-xold/moon_gui/static/app/pdp/pdp-list.tpl.html133
-rwxr-xr-xold/moon_gui/static/app/pdp/pdp.controller.list.js284
-rwxr-xr-xold/moon_gui/static/app/policy/action/mapping/policy-map.tpl.html64
-rwxr-xr-xold/moon_gui/static/app/policy/action/mapping/policy-unmap.tpl.html33
-rwxr-xr-xold/moon_gui/static/app/policy/action/mapping/policy.controller.map.js106
-rwxr-xr-xold/moon_gui/static/app/policy/action/mapping/policy.controller.unmap.js74
-rwxr-xr-xold/moon_gui/static/app/policy/action/policy-add.tpl.html113
-rwxr-xr-xold/moon_gui/static/app/policy/action/policy-delete.tpl.html40
-rwxr-xr-xold/moon_gui/static/app/policy/action/policy.controller.add.js113
-rwxr-xr-xold/moon_gui/static/app/policy/action/policy.controller.delete.js69
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/assignments/assignments-edit.tpl.html165
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/assignments/assignments-list.tpl.html335
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/assignments/assignments.edit.dir.js439
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/assignments/assignments.list.dir.js393
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/data/data-edit.tpl.html83
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/data/data-list.tpl.html390
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/data/data.edit.dir.js258
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/data/data.list.dir.js293
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-edit.tpl.html166
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-list.tpl.html240
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.edit.dir.js437
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.list.dir.js284
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/rules/rules-edit.tpl.html341
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/rules/rules-list.tpl.html134
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/rules/rules.edit.dir.js537
-rwxr-xr-xold/moon_gui/static/app/policy/edit/parameter/rules/rules.list.dir.js302
-rwxr-xr-xold/moon_gui/static/app/policy/edit/policy-edit-basic.tpl.html89
-rwxr-xr-xold/moon_gui/static/app/policy/edit/policy-edit.tpl.html202
-rwxr-xr-xold/moon_gui/static/app/policy/edit/policy.controller.edit.js88
-rwxr-xr-xold/moon_gui/static/app/policy/edit/policy.edit.basic.dir.js134
-rwxr-xr-xold/moon_gui/static/app/policy/policy-list.tpl.html131
-rwxr-xr-xold/moon_gui/static/app/policy/policy-mapped-list.tpl.html88
-rwxr-xr-xold/moon_gui/static/app/policy/policy.controller.list.js175
-rwxr-xr-xold/moon_gui/static/app/policy/policy.mapped.list.dir.js202
-rwxr-xr-xold/moon_gui/static/app/project/action/mapping/project-map.tpl.html62
-rwxr-xr-xold/moon_gui/static/app/project/action/mapping/project-unmap.tpl.html33
-rwxr-xr-xold/moon_gui/static/app/project/action/mapping/project.controller.map.js107
-rwxr-xr-xold/moon_gui/static/app/project/action/mapping/project.controller.unmap.js74
-rwxr-xr-xold/moon_gui/static/app/project/action/project-add.tpl.html89
-rwxr-xr-xold/moon_gui/static/app/project/action/project-delete.tpl.html45
-rwxr-xr-xold/moon_gui/static/app/project/action/project-view.tpl.html194
-rwxr-xr-xold/moon_gui/static/app/project/action/project.controller.add.js78
-rwxr-xr-xold/moon_gui/static/app/project/action/project.controller.delete.js134
-rwxr-xr-xold/moon_gui/static/app/project/action/project.controller.view.js216
-rwxr-xr-xold/moon_gui/static/app/project/project-list.tpl.html157
-rwxr-xr-xold/moon_gui/static/app/project/project.controller.list.js310
-rwxr-xr-xold/moon_gui/static/app/services/gui/alert.service.js39
-rwxr-xr-xold/moon_gui/static/app/services/gui/browser.service.js47
-rwxr-xr-xold/moon_gui/static/app/services/gui/form.service.js47
-rwxr-xr-xold/moon_gui/static/app/services/gui/menu.service.js49
-rwxr-xr-xold/moon_gui/static/app/services/gui/security.pipeline.service.js29
-rwxr-xr-xold/moon_gui/static/app/services/gui/util.service.js66
-rwxr-xr-xold/moon_gui/static/app/services/gui/version.service.js27
-rwxr-xr-xold/moon_gui/static/app/services/moon/model/model.service.js105
-rwxr-xr-xold/moon_gui/static/app/services/moon/pdp.service.js128
-rwxr-xr-xold/moon_gui/static/app/services/moon/policy/parameters/assignements.service.js133
-rwxr-xr-xold/moon_gui/static/app/services/moon/policy/parameters/data.service.js249
-rwxr-xr-xold/moon_gui/static/app/services/moon/policy/parameters/perimeter.service.js460
-rw-r--r--old/moon_gui/static/app/services/moon/policy/parameters/rule.service.js49
-rwxr-xr-xold/moon_gui/static/app/services/moon/policy/parameters/rules.service.js56
-rwxr-xr-xold/moon_gui/static/app/services/moon/policy/policy.service.js108
-rwxr-xr-xold/moon_gui/static/app/services/moon/rule/metadata.service.js354
-rwxr-xr-xold/moon_gui/static/app/services/moon/rule/metarule.service.js208
-rwxr-xr-xold/moon_gui/static/app/services/partner/authentication.service.js106
-rwxr-xr-xold/moon_gui/static/app/services/partner/nova.service.js35
-rwxr-xr-xold/moon_gui/static/app/services/partner/project.service.js60
-rwxr-xr-xold/moon_gui/static/favicon.icobin0 -> 318 bytes
-rwxr-xr-xold/moon_gui/static/i18n/en.json1357
-rwxr-xr-xold/moon_gui/static/i18n/fr.json1357
-rwxr-xr-xold/moon_gui/static/img/ajax-loader.gifbin0 -> 673 bytes
-rwxr-xr-xold/moon_gui/static/img/ajax-waiting.gifbin0 -> 10819 bytes
-rwxr-xr-xold/moon_gui/static/img/arrow-link.gifbin0 -> 87 bytes
-rw-r--r--old/moon_gui/static/img/et.jpgbin0 -> 31641 bytes
-rwxr-xr-xold/moon_gui/static/img/logo-openstack.pngbin0 -> 3180 bytes
-rwxr-xr-xold/moon_gui/static/img/logo-orange.gifbin0 -> 981 bytes
-rw-r--r--old/moon_gui/static/styles/main.css173
-rwxr-xr-xold/moon_gui/static/version.json3
-rw-r--r--old/moon_gui/templates/index.html31
-rw-r--r--old/moon_interface/Changelog36
-rw-r--r--old/moon_interface/Dockerfile15
-rw-r--r--old/moon_interface/LICENSE202
-rw-r--r--old/moon_interface/MANIFEST.in9
-rw-r--r--old/moon_interface/README.md9
-rw-r--r--old/moon_interface/moon_interface/__init__.py6
-rw-r--r--old/moon_interface/moon_interface/__main__.py4
-rw-r--r--old/moon_interface/moon_interface/api/__init__.py0
-rw-r--r--old/moon_interface/moon_interface/api/authz.py162
-rw-r--r--old/moon_interface/moon_interface/api/generic.py96
-rw-r--r--old/moon_interface/moon_interface/api/update.py49
-rw-r--r--old/moon_interface/moon_interface/authz_requests.py163
-rw-r--r--old/moon_interface/moon_interface/http_server.py146
-rw-r--r--old/moon_interface/moon_interface/server.py43
-rw-r--r--old/moon_interface/requirements.txt5
-rw-r--r--old/moon_interface/setup.py47
-rw-r--r--old/moon_interface/tests/unit_python/api/__init__.py0
-rw-r--r--old/moon_interface/tests/unit_python/api/test_authz.py83
-rw-r--r--old/moon_interface/tests/unit_python/conftest.py689
-rw-r--r--old/moon_interface/tests/unit_python/requirements.txt5
-rw-r--r--old/moon_manager/.gitignore104
-rw-r--r--old/moon_manager/Changelog73
-rw-r--r--old/moon_manager/Dockerfile15
-rw-r--r--old/moon_manager/LICENSE202
-rw-r--r--old/moon_manager/MANIFEST.in9
-rw-r--r--old/moon_manager/README.md8
-rw-r--r--old/moon_manager/moon_manager/__init__.py6
-rw-r--r--old/moon_manager/moon_manager/__main__.py4
-rw-r--r--old/moon_manager/moon_manager/api/__init__.py0
-rw-r--r--old/moon_manager/moon_manager/api/assignments.py391
-rw-r--r--old/moon_manager/moon_manager/api/base_exception.py17
-rw-r--r--old/moon_manager/moon_manager/api/data.py311
-rw-r--r--old/moon_manager/moon_manager/api/generic.py144
-rw-r--r--old/moon_manager/moon_manager/api/json_export.py279
-rw-r--r--old/moon_manager/moon_manager/api/json_import.py584
-rw-r--r--old/moon_manager/moon_manager/api/json_utils.py282
-rw-r--r--old/moon_manager/moon_manager/api/meta_data.py246
-rw-r--r--old/moon_manager/moon_manager/api/meta_rules.py152
-rw-r--r--old/moon_manager/moon_manager/api/models.py117
-rw-r--r--old/moon_manager/moon_manager/api/pdp.py214
-rw-r--r--old/moon_manager/moon_manager/api/perimeter.py375
-rw-r--r--old/moon_manager/moon_manager/api/policies.py125
-rw-r--r--old/moon_manager/moon_manager/api/rules.py135
-rw-r--r--old/moon_manager/moon_manager/api/slaves.py111
-rw-r--r--old/moon_manager/moon_manager/http_server.py162
-rw-r--r--old/moon_manager/moon_manager/server.py39
-rw-r--r--old/moon_manager/requirements.txt5
-rw-r--r--old/moon_manager/setup.py47
-rw-r--r--old/moon_manager/tests/functional_pod/conftest.py12
-rw-r--r--old/moon_manager/tests/functional_pod/json/mls.json89
-rw-r--r--old/moon_manager/tests/functional_pod/json/rbac.json85
-rw-r--r--old/moon_manager/tests/functional_pod/run_functional_tests.sh11
-rw-r--r--old/moon_manager/tests/functional_pod/test_manager.py116
-rw-r--r--old/moon_manager/tests/functional_pod/test_models.py79
-rw-r--r--old/moon_manager/tests/unit_python/api/import_export_utilities.py202
-rw-r--r--old/moon_manager/tests/unit_python/api/meta_data_test.py238
-rw-r--r--old/moon_manager/tests/unit_python/api/meta_rules_test.py162
-rw-r--r--old/moon_manager/tests/unit_python/api/test_assignement.py280
-rw-r--r--old/moon_manager/tests/unit_python/api/test_assignemnt.py270
-rw-r--r--old/moon_manager/tests/unit_python/api/test_data.py239
-rw-r--r--old/moon_manager/tests/unit_python/api/test_export.py282
-rw-r--r--old/moon_manager/tests/unit_python/api/test_import.py510
-rw-r--r--old/moon_manager/tests/unit_python/api/test_meta_data.py305
-rw-r--r--old/moon_manager/tests/unit_python/api/test_meta_rules.py415
-rw-r--r--old/moon_manager/tests/unit_python/api/test_pdp.py164
-rw-r--r--old/moon_manager/tests/unit_python/api/test_perimeter.py1028
-rw-r--r--old/moon_manager/tests/unit_python/api/test_policies.py342
-rw-r--r--old/moon_manager/tests/unit_python/api/test_rules.py129
-rw-r--r--old/moon_manager/tests/unit_python/api/test_unit_models.py352
-rw-r--r--old/moon_manager/tests/unit_python/api/utilities.py26
-rw-r--r--old/moon_manager/tests/unit_python/conftest.py254
-rw-r--r--old/moon_manager/tests/unit_python/helpers/__init__.py0
-rw-r--r--old/moon_manager/tests/unit_python/helpers/assignment_helper.py49
-rw-r--r--old/moon_manager/tests/unit_python/helpers/category_helper.py40
-rw-r--r--old/moon_manager/tests/unit_python/helpers/data_builder.py260
-rw-r--r--old/moon_manager/tests/unit_python/helpers/data_helper.py99
-rw-r--r--old/moon_manager/tests/unit_python/helpers/meta_rule_helper.py49
-rw-r--r--old/moon_manager/tests/unit_python/helpers/model_helper.py48
-rw-r--r--old/moon_manager/tests/unit_python/helpers/pdp_helper.py23
-rw-r--r--old/moon_manager/tests/unit_python/helpers/policy_helper.py63
-rw-r--r--old/moon_manager/tests/unit_python/requirements.txt5
-rw-r--r--old/moon_orchestrator/Changelog36
-rw-r--r--old/moon_orchestrator/Dockerfile15
-rw-r--r--old/moon_orchestrator/LICENSE202
-rw-r--r--old/moon_orchestrator/MANIFEST.in10
-rw-r--r--old/moon_orchestrator/README.md4
-rw-r--r--old/moon_orchestrator/moon_orchestrator/__init__.py6
-rw-r--r--old/moon_orchestrator/moon_orchestrator/__main__.py4
-rw-r--r--old/moon_orchestrator/moon_orchestrator/api/__init__.py0
-rw-r--r--old/moon_orchestrator/moon_orchestrator/api/generic.py99
-rw-r--r--old/moon_orchestrator/moon_orchestrator/api/pods.py174
-rw-r--r--old/moon_orchestrator/moon_orchestrator/api/slaves.py46
-rw-r--r--old/moon_orchestrator/moon_orchestrator/drivers.py487
-rw-r--r--old/moon_orchestrator/moon_orchestrator/http_server.py167
-rw-r--r--old/moon_orchestrator/moon_orchestrator/server.py39
-rw-r--r--old/moon_orchestrator/requirements.txt7
-rw-r--r--old/moon_orchestrator/setup.py50
-rw-r--r--old/moon_orchestrator/tests/unit_python/conftest.py18
-rw-r--r--old/moon_orchestrator/tests/unit_python/mock_pods.py417
-rw-r--r--old/moon_orchestrator/tests/unit_python/requirements.txt5
-rw-r--r--old/moon_orchestrator/tests/unit_python/test_pods.py287
-rw-r--r--old/moon_orchestrator/tests/unit_python/test_slaves.py17
-rw-r--r--old/moon_orchestrator/tests/unit_python/utilities.py171
-rw-r--r--old/moon_pythonfunctest/Dockerfile9
-rw-r--r--old/moon_pythonfunctest/README.md8
-rwxr-xr-xold/moon_pythonfunctest/run_func_test.sh15
-rw-r--r--old/moon_pythonunittest/Dockerfile8
-rw-r--r--old/moon_pythonunittest/README.md8
-rw-r--r--old/moon_pythonunittest/requirements.txt11
-rw-r--r--old/moon_pythonunittest/run_tests.sh19
-rw-r--r--old/moon_wrapper/Changelog47
-rw-r--r--old/moon_wrapper/Dockerfile15
-rw-r--r--old/moon_wrapper/LICENSE202
-rw-r--r--old/moon_wrapper/MANIFEST.in9
-rw-r--r--old/moon_wrapper/README.md8
-rw-r--r--old/moon_wrapper/moon_wrapper/__init__.py6
-rw-r--r--old/moon_wrapper/moon_wrapper/__main__.py4
-rw-r--r--old/moon_wrapper/moon_wrapper/api/__init__.py0
-rw-r--r--old/moon_wrapper/moon_wrapper/api/generic.py134
-rw-r--r--old/moon_wrapper/moon_wrapper/api/oslowrapper.py127
-rw-r--r--old/moon_wrapper/moon_wrapper/api/slaveupdate.py87
-rw-r--r--old/moon_wrapper/moon_wrapper/http_server.py144
-rw-r--r--old/moon_wrapper/moon_wrapper/server.py32
-rw-r--r--old/moon_wrapper/requirements.txt5
-rw-r--r--old/moon_wrapper/setup.py47
-rw-r--r--old/moon_wrapper/tests/README.md35
-rw-r--r--old/moon_wrapper/tests/unit_python/api/__init__.py0
-rw-r--r--old/moon_wrapper/tests/unit_python/api/test_wrapper.py72
-rw-r--r--old/moon_wrapper/tests/unit_python/conftest.py722
-rw-r--r--old/moon_wrapper/tests/unit_python/requirements.txt5
-rw-r--r--old/python_moonclient/.gitignore106
-rw-r--r--old/python_moonclient/Changelog78
-rw-r--r--old/python_moonclient/LICENSE202
-rw-r--r--old/python_moonclient/MANIFEST.in10
-rw-r--r--old/python_moonclient/README.md33
-rw-r--r--old/python_moonclient/python_moonclient/__init__.py6
-rw-r--r--old/python_moonclient/python_moonclient/cli/__init__.py0
-rw-r--r--old/python_moonclient/python_moonclient/cli/authz.py55
-rw-r--r--old/python_moonclient/python_moonclient/cli/export.py32
-rw-r--r--old/python_moonclient/python_moonclient/cli/import.py28
-rw-r--r--old/python_moonclient/python_moonclient/cli/models.py159
-rw-r--r--old/python_moonclient/python_moonclient/cli/parser.py98
-rw-r--r--old/python_moonclient/python_moonclient/cli/pdps.py190
-rw-r--r--old/python_moonclient/python_moonclient/cli/policies.py264
-rw-r--r--old/python_moonclient/python_moonclient/cli/projects.py54
-rw-r--r--old/python_moonclient/python_moonclient/cli/slaves.py120
-rw-r--r--old/python_moonclient/python_moonclient/core/__init__.py0
-rw-r--r--old/python_moonclient/python_moonclient/core/authz.py180
-rw-r--r--old/python_moonclient/python_moonclient/core/check_tools.py458
-rw-r--r--old/python_moonclient/python_moonclient/core/cli_exceptions.py4
-rw-r--r--old/python_moonclient/python_moonclient/core/config.py64
-rw-r--r--old/python_moonclient/python_moonclient/core/json_export.py26
-rw-r--r--old/python_moonclient/python_moonclient/core/json_import.py29
-rw-r--r--old/python_moonclient/python_moonclient/core/models.py279
-rw-r--r--old/python_moonclient/python_moonclient/core/pdp.py194
-rw-r--r--old/python_moonclient/python_moonclient/core/policies.py673
-rw-r--r--old/python_moonclient/python_moonclient/core/slaves.py59
-rw-r--r--old/python_moonclient/python_moonclient/moon.py37
-rw-r--r--old/python_moonclient/requirements.txt4
-rw-r--r--old/python_moonclient/setup.py75
-rw-r--r--old/python_moonclient/tests/unit_python/__init__.py0
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_action_assignments.py51
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_action_categories.py32
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_action_data.py66
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_actions.py111
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_all.py1
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_meta_rules.py44
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_models.py94
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_object_assignments.py51
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_object_categories.py31
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_object_data.py67
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_objects.py112
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_pdps.py95
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_policies.py78
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_projects.py44
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_rules.py46
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_subject_assignments.py51
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_subject_categories.py30
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_subject_data.py67
-rw-r--r--old/python_moonclient/tests/unit_python/conf/conf_subjects.py112
-rw-r--r--old/python_moonclient/tests/unit_python/conftest.py52
-rw-r--r--old/python_moonclient/tests/unit_python/mock_config.py64
-rw-r--r--old/python_moonclient/tests/unit_python/requirements.txt2
-rw-r--r--old/python_moonclient/tests/unit_python/test_config.py8
-rw-r--r--old/python_moonclient/tests/unit_python/test_models.py38
-rw-r--r--old/python_moonclient/tests/unit_python/test_pdp.py17
-rw-r--r--old/python_moonclient/tests/unit_python/test_policies.py161
-rw-r--r--old/python_moonclient/tests/unit_python/utilities.py153
-rw-r--r--old/python_moondb/.gitignore106
-rw-r--r--old/python_moondb/Changelog128
-rw-r--r--old/python_moondb/LICENSE202
-rw-r--r--old/python_moondb/MANIFEST.in10
-rw-r--r--old/python_moondb/README.md32
-rw-r--r--old/python_moondb/bin/drop_tables.sql18
-rw-r--r--old/python_moondb/python_moondb/__init__.py6
-rw-r--r--old/python_moondb/python_moondb/api/__init__.py0
-rw-r--r--old/python_moondb/python_moondb/api/keystone.py105
-rw-r--r--old/python_moondb/python_moondb/api/managers.py16
-rw-r--r--old/python_moondb/python_moondb/api/model.py338
-rw-r--r--old/python_moondb/python_moondb/api/pdp.py51
-rw-r--r--old/python_moondb/python_moondb/api/policy.py751
-rw-r--r--old/python_moondb/python_moondb/backends/__init__.py96
-rw-r--r--old/python_moondb/python_moondb/backends/sql.py1884
-rw-r--r--old/python_moondb/python_moondb/core.py228
-rw-r--r--old/python_moondb/python_moondb/db_manager.py82
-rw-r--r--old/python_moondb/python_moondb/migrate_repo/__init__.py0
-rw-r--r--old/python_moondb/python_moondb/migrate_repo/versions/001_moon.py267
-rw-r--r--old/python_moondb/python_moondb/migrate_repo/versions/__init__.py0
-rw-r--r--old/python_moondb/requirements.txt4
-rw-r--r--old/python_moondb/setup.py54
-rw-r--r--old/python_moondb/tests/unit_python/conftest.py145
-rw-r--r--old/python_moondb/tests/unit_python/helpers/__init__.py0
-rw-r--r--old/python_moondb/tests/unit_python/helpers/assignment_helper.py49
-rw-r--r--old/python_moondb/tests/unit_python/helpers/category_helper.py54
-rw-r--r--old/python_moondb/tests/unit_python/helpers/data_helper.py98
-rw-r--r--old/python_moondb/tests/unit_python/helpers/meta_rule_helper.py48
-rw-r--r--old/python_moondb/tests/unit_python/helpers/mock_data.py156
-rw-r--r--old/python_moondb/tests/unit_python/helpers/model_helper.py47
-rw-r--r--old/python_moondb/tests/unit_python/helpers/pdp_helper.py23
-rw-r--r--old/python_moondb/tests/unit_python/helpers/policy_helper.py72
-rw-r--r--old/python_moondb/tests/unit_python/mock_components.py27
-rw-r--r--old/python_moondb/tests/unit_python/mock_keystone.py33
-rwxr-xr-xold/python_moondb/tests/unit_python/models/__init__.py0
-rw-r--r--old/python_moondb/tests/unit_python/models/test_categories.py111
-rw-r--r--old/python_moondb/tests/unit_python/models/test_meta_rules.py403
-rw-r--r--old/python_moondb/tests/unit_python/models/test_models.py622
-rw-r--r--old/python_moondb/tests/unit_python/policies/__init__.py0
-rw-r--r--old/python_moondb/tests/unit_python/policies/mock_data.py74
-rwxr-xr-xold/python_moondb/tests/unit_python/policies/test_assignments.py235
-rwxr-xr-xold/python_moondb/tests/unit_python/policies/test_data.py707
-rwxr-xr-xold/python_moondb/tests/unit_python/policies/test_policies.py643
-rw-r--r--old/python_moondb/tests/unit_python/requirements.txt4
-rw-r--r--old/python_moondb/tests/unit_python/test_keystone.py53
-rwxr-xr-xold/python_moondb/tests/unit_python/test_pdp.py149
-rw-r--r--old/python_moondb/tests/unit_python/utilities.py136
-rw-r--r--old/python_moonutilities/.gitignore105
-rw-r--r--old/python_moonutilities/Changelog157
-rw-r--r--old/python_moonutilities/Jenkinsfile10
-rw-r--r--old/python_moonutilities/LICENSE202
-rw-r--r--old/python_moonutilities/MANIFEST.in10
-rw-r--r--old/python_moonutilities/README.md33
-rw-r--r--old/python_moonutilities/python_moonutilities/__init__.py6
-rw-r--r--old/python_moonutilities/python_moonutilities/cache.py703
-rw-r--r--old/python_moonutilities/python_moonutilities/configuration.py124
-rw-r--r--old/python_moonutilities/python_moonutilities/context.py353
-rw-r--r--old/python_moonutilities/python_moonutilities/exceptions.py833
-rw-r--r--old/python_moonutilities/python_moonutilities/misc.py116
-rw-r--r--old/python_moonutilities/python_moonutilities/request_wrapper.py22
-rw-r--r--old/python_moonutilities/python_moonutilities/security_functions.py331
-rw-r--r--old/python_moonutilities/requirements.txt3
-rw-r--r--old/python_moonutilities/setup.py42
-rw-r--r--old/python_moonutilities/tests/unit_python/conftest.py14
-rw-r--r--old/python_moonutilities/tests/unit_python/mock_repo/__init__.py42
-rw-r--r--old/python_moonutilities/tests/unit_python/mock_repo/components_utilities.py136
-rw-r--r--old/python_moonutilities/tests/unit_python/mock_repo/data.py315
-rw-r--r--old/python_moonutilities/tests/unit_python/mock_repo/urls.py150
-rw-r--r--old/python_moonutilities/tests/unit_python/requirements.txt1
-rw-r--r--old/python_moonutilities/tests/unit_python/test_cache.py452
-rw-r--r--old/python_moonutilities/tests/unit_python/test_configuration.py166
-rw-r--r--old/python_moonutilities/tests/unit_python/test_validated_input.py154
-rw-r--r--old/tests/functional/README.md27
-rwxr-xr-xold/tests/functional/run_tests.sh18
-rw-r--r--old/tests/functional/run_tests_for_component.sh27
-rw-r--r--old/tests/functional/scenario_available/delegation.py40
-rw-r--r--old/tests/functional/scenario_available/mls.py59
-rw-r--r--old/tests/functional/scenario_available/rbac.py61
-rw-r--r--old/tests/functional/scenario_available/rbac_custom_100.py89
-rw-r--r--old/tests/functional/scenario_available/rbac_custom_1000.py89
-rw-r--r--old/tests/functional/scenario_available/rbac_custom_50.py89
-rw-r--r--old/tests/functional/scenario_available/rbac_large.py233
-rw-r--r--old/tests/functional/scenario_available/rbac_mls.py50
-rw-r--r--old/tests/functional/scenario_available/session.py60
-rw-r--r--old/tests/functional/scenario_available/session_large.py389
l---------old/tests/functional/scenario_enabled/mls.py1
l---------old/tests/functional/scenario_enabled/rbac.py1
-rw-r--r--old/tests/functional/scenario_tests/mls.py59
-rw-r--r--old/tests/functional/scenario_tests/rbac.py61
-rw-r--r--old/tests/performance/README.md80
-rw-r--r--old/tests/python_unit/README.md5
-rw-r--r--old/tests/python_unit/run_tests.sh17
-rw-r--r--old/tools/bin/README.md8
-rw-r--r--old/tools/bin/api2rst.py145
-rw-r--r--old/tools/bin/bootstrap.py235
-rw-r--r--old/tools/bin/build_all.sh36
-rw-r--r--old/tools/bin/build_all_pip.sh16
-rw-r--r--old/tools/bin/delete_orchestrator.sh61
-rw-r--r--old/tools/bin/get_keystone_token.py71
-rw-r--r--old/tools/bin/moon_lib_upload.sh27
-rw-r--r--old/tools/bin/set_auth.src7
-rwxr-xr-xold/tools/bin/start.sh39
-rw-r--r--old/tools/moon_jenkins/Dockerfile8
-rw-r--r--old/tools/moon_jenkins/README.md37
-rw-r--r--old/tools/moon_jenkins/docker-compose.yml20
-rw-r--r--old/tools/moon_jenkins/images/Create Multibranch Pipeline.pngbin0 -> 55639 bytes
-rw-r--r--old/tools/moon_jenkins/images/Git Source Multibranch Pipeline.pngbin0 -> 31054 bytes
-rw-r--r--old/tools/moon_jenkins/images/Multibranch Pipeline Log.pngbin0 -> 55231 bytes
-rw-r--r--old/tools/moon_jenkins/images/Select Source Multibranch Pipeline.pngbin0 -> 23375 bytes
-rw-r--r--old/tools/moon_jenkins/plugins.txt100
-rw-r--r--old/tools/moon_jenkins/security.groovy20
-rw-r--r--old/tools/moon_keystone/Dockerfile25
-rw-r--r--old/tools/moon_keystone/README.md26
-rw-r--r--old/tools/moon_keystone/run.sh81
-rw-r--r--old/tools/moon_kubernetes/README.md141
-rw-r--r--old/tools/moon_kubernetes/conf/moon.conf90
-rw-r--r--old/tools/moon_kubernetes/conf/password_moon.txt1
-rw-r--r--old/tools/moon_kubernetes/conf/password_root.txt1
-rw-r--r--old/tools/moon_kubernetes/init_k8s_moon.sh280
-rw-r--r--old/tools/moon_kubernetes/templates/consul.yaml33
-rw-r--r--old/tools/moon_kubernetes/templates/db.yaml55
-rw-r--r--old/tools/moon_kubernetes/templates/keystone.yaml39
-rw-r--r--old/tools/moon_kubernetes/templates/kube-dns.yaml183
-rw-r--r--old/tools/moon_kubernetes/templates/moon_forming.yaml30
-rw-r--r--old/tools/moon_kubernetes/templates/moon_functest.yaml27
-rw-r--r--old/tools/moon_kubernetes/templates/moon_gui.yaml42
-rw-r--r--old/tools/moon_kubernetes/templates/moon_manager.yaml33
-rw-r--r--old/tools/moon_kubernetes/templates/moon_orchestrator.yaml40
-rw-r--r--old/tools/openstack/README.md73
-rw-r--r--old/tools/openstack/glance/policy.json62
-rw-r--r--old/tools/openstack/nova/policy.json488
-rw-r--r--old/tools/policies/generate_opst_policy.py167
-rw-r--r--old/tools/policies/policy.json.d/cinder.policy.json104
-rw-r--r--old/tools/policies/policy.json.d/glance.policy.json63
-rw-r--r--old/tools/policies/policy.json.d/keystone.policy.json260
-rw-r--r--old/tools/policies/policy.json.d/neutron.policy.json235
-rw-r--r--old/tools/policies/policy.json.d/nova.policy.json485
635 files changed, 70583 insertions, 0 deletions
diff --git a/old/external_policy_checker/Changelog b/old/external_policy_checker/Changelog
new file mode 100644
index 00000000..cd4ffb7e
--- /dev/null
+++ b/old/external_policy_checker/Changelog
@@ -0,0 +1,13 @@
+# Copyright 2018 Orange
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+CHANGES
+=======
+
+1.0.0
+-----
+- First version of the external_policy_checker
+
diff --git a/old/external_policy_checker/Dockerfile b/old/external_policy_checker/Dockerfile
new file mode 100644
index 00000000..ed013935
--- /dev/null
+++ b/old/external_policy_checker/Dockerfile
@@ -0,0 +1,8 @@
+FROM python:3
+
+ADD . /root
+RUN pip install -r /root/requirements.txt --upgrade
+WORKDIR /root
+RUN pip install .
+
+CMD ["python", "-m", "moon_bouchon"] \ No newline at end of file
diff --git a/old/external_policy_checker/README.md b/old/external_policy_checker/README.md
new file mode 100644
index 00000000..ac44af0e
--- /dev/null
+++ b/old/external_policy_checker/README.md
@@ -0,0 +1,46 @@
+#External Policy Checker
+
+OpenStack component (like Nova, Glance, Cinder, ...) must populate 3 attributes to allow computing an authorization.
+Those 3 attributes are:
+- target
+- credentials
+- rule
+In all those attributes, we must find the following information:
+- In the 'credentials' attribute:
+ - the user ID: this is given in general by Keystone
+ - the project ID: this is given in general by Keystone
+ - as a proposal, the domain ID: this is given in general by Keystone
+- In the 'target' attribute:
+ - the resource ID (ie nova virtual machine ID, Glance image ID, ...): this must come from the component source of the request (Nova, Glance, …)
+- In the 'rule' attribute:
+ - the action name: this must come from the component source of the request (Nova, Glance, )
+
+This server must be used to verify that all information given from OpenStack components can be retrieved in those attributes.
+
+
+## Usage:
+
+### server
+
+To start the server locally:
+
+ cd external_policy_checker
+ python3 server.py
+
+To start the server as a docker container:
+
+ docker run -ti -p 8080:8080 moon_platform/external_policy_checker:latest
+
+### API
+
+Here are the API, you can request:
+
+ POST /policy_checker
+ POST /authz/grant
+ POST /authz/deny
+
+The `/policy_checker` allows to check if all information can be retrieve.
+The `/authz/grant` will always send a "True" response.
+The `/authz/deny` will always send a "False" response.
+
+
diff --git a/old/external_policy_checker/conf/templates/cinder.policy.json b/old/external_policy_checker/conf/templates/cinder.policy.json
new file mode 100644
index 00000000..7716e00b
--- /dev/null
+++ b/old/external_policy_checker/conf/templates/cinder.policy.json
@@ -0,0 +1,99 @@
+{
+
+ "volume:create": "{{wrapper}}",
+ "volume:delete": "{{wrapper}}",
+ "volume:get": "{{wrapper}}",
+ "volume:get_all": "{{wrapper}}",
+ "volume:get_volume_metadata": "{{wrapper}}",
+ "volume:delete_volume_metadata": "{{wrapper}}",
+ "volume:update_volume_metadata": "{{wrapper}}",
+ "volume:get_volume_admin_metadata": "{{wrapper}}",
+ "volume:update_volume_admin_metadata": "{{wrapper}}",
+ "volume:get_snapshot": "{{wrapper}}",
+ "volume:get_all_snapshots": "{{wrapper}}",
+ "volume:create_snapshot": "{{wrapper}}",
+ "volume:delete_snapshot": "{{wrapper}}",
+ "volume:update_snapshot": "{{wrapper}}",
+ "volume:extend": "{{wrapper}}",
+ "volume:update_readonly_flag": "{{wrapper}}",
+ "volume:retype": "{{wrapper}}",
+ "volume:update": "{{wrapper}}",
+
+ "volume_extension:types_manage": "{{wrapper}}",
+ "volume_extension:types_extra_specs": "{{wrapper}}",
+ "volume_extension:access_types_qos_specs_id": "{{wrapper}}",
+ "volume_extension:access_types_extra_specs": "{{wrapper}}",
+ "volume_extension:volume_type_access": "{{wrapper}}",
+ "volume_extension:volume_type_access:addProjectAccess": "{{wrapper}}",
+ "volume_extension:volume_type_access:removeProjectAccess": "{{wrapper}}",
+ "volume_extension:volume_type_encryption": "{{wrapper}}",
+ "volume_extension:volume_encryption_metadata": "{{wrapper}}",
+ "volume_extension:extended_snapshot_attributes": "{{wrapper}}",
+ "volume_extension:volume_image_metadata": "{{wrapper}}",
+
+ "volume_extension:quotas:show": "{{wrapper}}",
+ "volume_extension:quotas:update": "{{wrapper}}",
+ "volume_extension:quotas:delete": "{{wrapper}}",
+ "volume_extension:quota_classes": "{{wrapper}}",
+ "volume_extension:quota_classes:validate_setup_for_nested_quota_use": "{{wrapper}}",
+
+ "volume_extension:volume_admin_actions:reset_status": "{{wrapper}}",
+ "volume_extension:snapshot_admin_actions:reset_status": "{{wrapper}}",
+ "volume_extension:backup_admin_actions:reset_status": "{{wrapper}}",
+ "volume_extension:volume_admin_actions:force_delete": "{{wrapper}}",
+ "volume_extension:volume_admin_actions:force_detach": "{{wrapper}}",
+ "volume_extension:snapshot_admin_actions:force_delete": "{{wrapper}}",
+ "volume_extension:backup_admin_actions:force_delete": "{{wrapper}}",
+ "volume_extension:volume_admin_actions:migrate_volume": "{{wrapper}}",
+ "volume_extension:volume_admin_actions:migrate_volume_completion": "{{wrapper}}",
+
+ "volume_extension:volume_host_attribute": "{{wrapper}}",
+ "volume_extension:volume_tenant_attribute": "{{wrapper}}",
+ "volume_extension:volume_mig_status_attribute": "{{wrapper}}",
+ "volume_extension:hosts": "{{wrapper}}",
+ "volume_extension:services:index": "{{wrapper}}",
+ "volume_extension:services:update" : "{{wrapper}}",
+
+ "volume_extension:volume_manage": "{{wrapper}}",
+ "volume_extension:volume_unmanage": "{{wrapper}}",
+
+ "volume_extension:capabilities": "{{wrapper}}",
+
+ "volume:create_transfer": "{{wrapper}}",
+ "volume:accept_transfer": "{{wrapper}}",
+ "volume:delete_transfer": "{{wrapper}}",
+ "volume:get_all_transfers": "{{wrapper}}",
+
+ "volume_extension:replication:promote": "{{wrapper}}",
+ "volume_extension:replication:reenable": "{{wrapper}}",
+
+ "volume:enable_replication": "{{wrapper}}",
+ "volume:disable_replication": "{{wrapper}}",
+ "volume:failover_replication": "{{wrapper}}",
+ "volume:list_replication_targets": "{{wrapper}}",
+
+ "backup:create" : "{{wrapper}}",
+ "backup:delete": "{{wrapper}}",
+ "backup:get": "{{wrapper}}",
+ "backup:get_all": "{{wrapper}}",
+ "backup:restore": "{{wrapper}}",
+ "backup:backup-import": "{{wrapper}}",
+ "backup:backup-export": "{{wrapper}}",
+
+ "snapshot_extension:snapshot_actions:update_snapshot_status": "{{wrapper}}",
+ "snapshot_extension:snapshot_manage": "{{wrapper}}",
+ "snapshot_extension:snapshot_unmanage": "{{wrapper}}",
+
+ "consistencygroup:create" : "{{wrapper}}",
+ "consistencygroup:delete": "{{wrapper}}",
+ "consistencygroup:update": "{{wrapper}}",
+ "consistencygroup:get": "{{wrapper}}",
+ "consistencygroup:get_all": "{{wrapper}}",
+
+ "consistencygroup:create_cgsnapshot" : "{{wrapper}}",
+ "consistencygroup:delete_cgsnapshot": "{{wrapper}}",
+ "consistencygroup:get_cgsnapshot": "{{wrapper}}",
+ "consistencygroup:get_all_cgsnapshots": "{{wrapper}}",
+
+ "scheduler_extension:scheduler_stats:get_pools" : "{{wrapper}}"
+}
diff --git a/old/external_policy_checker/conf/templates/glance.policy.json b/old/external_policy_checker/conf/templates/glance.policy.json
new file mode 100644
index 00000000..ec79d381
--- /dev/null
+++ b/old/external_policy_checker/conf/templates/glance.policy.json
@@ -0,0 +1,61 @@
+{
+
+ "add_image": "{{wrapper}}",
+ "delete_image": "{{wrapper}}",
+ "get_image": "{{wrapper}}",
+ "get_images": "{{wrapper}}",
+ "modify_image": "{{wrapper}}",
+ "publicize_image": "{{wrapper}}",
+ "communitize_image": "{{wrapper}}",
+ "copy_from": "{{wrapper}}",
+
+ "download_image": "{{wrapper}}",
+ "upload_image": "{{wrapper}}",
+
+ "delete_image_location": "{{wrapper}}",
+ "get_image_location": "{{wrapper}}",
+ "set_image_location": "{{wrapper}}",
+
+ "add_member": "{{wrapper}}",
+ "delete_member": "{{wrapper}}",
+ "get_member": "{{wrapper}}",
+ "get_members": "{{wrapper}}",
+ "modify_member": "{{wrapper}}",
+
+ "manage_image_cache": "{{wrapper}}",
+
+ "get_task": "{{wrapper}}",
+ "get_tasks": "{{wrapper}}",
+ "add_task": "{{wrapper}}",
+ "modify_task": "{{wrapper}}",
+ "tasks_api_access": "{{wrapper}}",
+
+ "deactivate": "{{wrapper}}",
+ "reactivate": "{{wrapper}}",
+
+ "get_metadef_namespace": "{{wrapper}}",
+ "get_metadef_namespaces":"{{wrapper}}",
+ "modify_metadef_namespace":"{{wrapper}}",
+ "add_metadef_namespace":"{{wrapper}}",
+
+ "get_metadef_object":"{{wrapper}}",
+ "get_metadef_objects":"{{wrapper}}",
+ "modify_metadef_object":"{{wrapper}}",
+ "add_metadef_object":"{{wrapper}}",
+
+ "list_metadef_resource_types":"{{wrapper}}",
+ "get_metadef_resource_type":"{{wrapper}}",
+ "add_metadef_resource_type_association":"{{wrapper}}",
+
+ "get_metadef_property":"{{wrapper}}",
+ "get_metadef_properties":"{{wrapper}}",
+ "modify_metadef_property":"{{wrapper}}",
+ "add_metadef_property":"{{wrapper}}",
+
+ "get_metadef_tag":"{{wrapper}}",
+ "get_metadef_tags":"{{wrapper}}",
+ "modify_metadef_tag":"{{wrapper}}",
+ "add_metadef_tag":"{{wrapper}}",
+ "add_metadef_tags":"{{wrapper}}"
+
+}
diff --git a/old/external_policy_checker/conf/templates/keystone.policy.json b/old/external_policy_checker/conf/templates/keystone.policy.json
new file mode 100644
index 00000000..7fc967d5
--- /dev/null
+++ b/old/external_policy_checker/conf/templates/keystone.policy.json
@@ -0,0 +1,250 @@
+{
+
+ "identity:get_region": "{{wrapper}}",
+ "identity:list_regions": "{{wrapper}}",
+ "identity:create_region": "{{wrapper}}",
+ "identity:update_region": "{{wrapper}}",
+ "identity:delete_region": "{{wrapper}}",
+
+ "identity:get_service": "{{wrapper}}",
+ "identity:list_services": "{{wrapper}}",
+ "identity:create_service": "{{wrapper}}",
+ "identity:update_service": "{{wrapper}}",
+ "identity:delete_service": "{{wrapper}}",
+
+ "identity:get_endpoint": "{{wrapper}}",
+ "identity:list_endpoints": "{{wrapper}}",
+ "identity:create_endpoint": "{{wrapper}}",
+ "identity:update_endpoint": "{{wrapper}}",
+ "identity:delete_endpoint": "{{wrapper}}",
+
+ "identity:get_registered_limit": "{{wrapper}}",
+ "identity:list_registered_limits": "{{wrapper}}",
+ "identity:create_registered_limits": "{{wrapper}}",
+ "identity:update_registered_limits": "{{wrapper}}",
+ "identity:delete_registered_limit": "{{wrapper}}",
+
+ "identity:get_limit": "{{wrapper}}",
+ "identity:list_limits": "{{wrapper}}",
+ "identity:create_limits": "{{wrapper}}",
+ "identity:update_limits": "{{wrapper}}",
+ "identity:delete_limit": "{{wrapper}}",
+
+ "identity:get_domain": "{{wrapper}}",
+ "identity:list_domains": "{{wrapper}}",
+ "identity:create_domain": "{{wrapper}}",
+ "identity:update_domain": "{{wrapper}}",
+ "identity:delete_domain": "{{wrapper}}",
+
+ "admin_and_matching_target_project_domain_id": "{{wrapper}}",
+ "admin_and_matching_project_domain_id": "{{wrapper}}",
+ "identity:get_project": "{{wrapper}}",
+ "identity:list_projects": "{{wrapper}}",
+ "identity:list_user_projects": "{{wrapper}}",
+ "identity:create_project": "{{wrapper}}",
+ "identity:update_project": "{{wrapper}}",
+ "identity:delete_project": "{{wrapper}}",
+ "identity:create_project_tag": "{{wrapper}}",
+ "identity:delete_project_tag": "{{wrapper}}",
+ "identity:get_project_tag": "{{wrapper}}",
+ "identity:list_project_tags": "{{wrapper}}",
+ "identity:delete_project_tags": "{{wrapper}}",
+ "identity:update_project_tags": "{{wrapper}}",
+
+ "admin_and_matching_target_user_domain_id": "{{wrapper}}",
+ "admin_and_matching_user_domain_id": "{{wrapper}}",
+ "identity:get_user": "{{wrapper}}",
+ "identity:list_users": "{{wrapper}}",
+ "identity:create_user": "{{wrapper}}",
+ "identity:update_user": "{{wrapper}}",
+ "identity:delete_user": "{{wrapper}}",
+
+ "admin_and_matching_target_group_domain_id": "{{wrapper}}",
+ "admin_and_matching_group_domain_id": "{{wrapper}}",
+ "identity:get_group": "{{wrapper}}",
+ "identity:list_groups": "{{wrapper}}",
+ "identity:list_groups_for_user": "{{wrapper}}",
+ "identity:create_group": "{{wrapper}}",
+ "identity:update_group": "{{wrapper}}",
+ "identity:delete_group": "{{wrapper}}",
+ "identity:list_users_in_group": "{{wrapper}}",
+ "identity:remove_user_from_group": "{{wrapper}}",
+ "identity:check_user_in_group": "{{wrapper}}",
+ "identity:add_user_to_group": "{{wrapper}}",
+
+ "identity:get_credential": "{{wrapper}}",
+ "identity:list_credentials": "{{wrapper}}",
+ "identity:create_credential": "{{wrapper}}",
+ "identity:update_credential": "{{wrapper}}",
+ "identity:delete_credential": "{{wrapper}}",
+
+ "identity:ec2_get_credential": "{{wrapper}}",
+ "identity:ec2_list_credentials": "{{wrapper}}",
+ "identity:ec2_create_credential": "{{wrapper}}",
+ "identity:ec2_delete_credential": "{{wrapper}}",
+
+ "identity:get_role": "{{wrapper}}",
+ "identity:list_roles": "{{wrapper}}",
+ "identity:create_role": "{{wrapper}}",
+ "identity:update_role": "{{wrapper}}",
+ "identity:delete_role": "{{wrapper}}",
+
+ "identity:get_domain_role": "{{wrapper}}",
+ "identity:list_domain_roles": "{{wrapper}}",
+ "identity:create_domain_role": "{{wrapper}}",
+ "identity:update_domain_role": "{{wrapper}}",
+ "identity:delete_domain_role": "{{wrapper}}",
+ "domain_admin_matches_domain_role": "{{wrapper}}",
+ "get_domain_roles": "{{wrapper}}",
+ "domain_admin_matches_target_domain_role": "{{wrapper}}",
+ "project_admin_matches_target_domain_role": "{{wrapper}}",
+ "list_domain_roles": "{{wrapper}}",
+ "domain_admin_matches_filter_on_list_domain_roles": "{{wrapper}}",
+ "project_admin_matches_filter_on_list_domain_roles": "{{wrapper}}",
+ "admin_and_matching_prior_role_domain_id": "{{wrapper}}",
+ "implied_role_matches_prior_role_domain_or_global": "{{wrapper}}",
+
+ "identity:get_implied_role": "{{wrapper}}",
+ "identity:list_implied_roles": "{{wrapper}}",
+ "identity:create_implied_role": "{{wrapper}}",
+ "identity:delete_implied_role": "{{wrapper}}",
+ "identity:list_role_inference_rules": "{{wrapper}}",
+ "identity:check_implied_role": "{{wrapper}}",
+
+ "identity:list_system_grants_for_user": "{{wrapper}}",
+ "identity:check_system_grant_for_user": "{{wrapper}}",
+ "identity:create_system_grant_for_user": "{{wrapper}}",
+ "identity:revoke_system_grant_for_user": "{{wrapper}}",
+
+ "identity:list_system_grants_for_group": "{{wrapper}}",
+ "identity:check_system_grant_for_group": "{{wrapper}}",
+ "identity:create_system_grant_for_group": "{{wrapper}}",
+ "identity:revoke_system_grant_for_group": "{{wrapper}}",
+
+ "identity:check_grant": "{{wrapper}}",
+ "identity:list_grants": "{{wrapper}}",
+ "identity:create_grant": "{{wrapper}}",
+ "identity:revoke_grant": "{{wrapper}}",
+ "domain_admin_for_grants": "{{wrapper}}",
+ "domain_admin_for_global_role_grants": "{{wrapper}}",
+ "domain_admin_for_domain_role_grants": "{{wrapper}}",
+ "domain_admin_grant_match": "{{wrapper}}",
+ "project_admin_for_grants": "{{wrapper}}",
+ "project_admin_for_global_role_grants": "{{wrapper}}",
+ "project_admin_for_domain_role_grants": "{{wrapper}}",
+ "domain_admin_for_list_grants": "{{wrapper}}",
+ "project_admin_for_list_grants": "{{wrapper}}",
+
+ "admin_on_domain_filter": "{{wrapper}}",
+ "admin_on_project_filter": "{{wrapper}}",
+ "admin_on_domain_of_project_filter": "{{wrapper}}",
+ "identity:list_role_assignments": "{{wrapper}}",
+ "identity:list_role_assignments_for_tree": "{{wrapper}}",
+ "identity:get_policy": "{{wrapper}}",
+ "identity:list_policies": "{{wrapper}}",
+ "identity:create_policy": "{{wrapper}}",
+ "identity:update_policy": "{{wrapper}}",
+ "identity:delete_policy": "{{wrapper}}",
+
+ "identity:check_token": "{{wrapper}}",
+ "identity:validate_token": "{{wrapper}}",
+ "identity:validate_token_head": "{{wrapper}}",
+ "identity:revocation_list": "{{wrapper}}",
+ "identity:revoke_token": "{{wrapper}}",
+
+ "identity:create_trust": "{{wrapper}}",
+ "identity:list_trusts": "{{wrapper}}",
+ "identity:list_roles_for_trust": "{{wrapper}}",
+ "identity:get_role_for_trust": "{{wrapper}}",
+ "identity:delete_trust": "{{wrapper}}",
+ "identity:get_trust": "{{wrapper}}",
+
+ "identity:create_consumer": "{{wrapper}}",
+ "identity:get_consumer": "{{wrapper}}",
+ "identity:list_consumers": "{{wrapper}}",
+ "identity:delete_consumer": "{{wrapper}}",
+ "identity:update_consumer": "{{wrapper}}",
+
+ "identity:authorize_request_token": "{{wrapper}}",
+ "identity:list_access_token_roles": "{{wrapper}}",
+ "identity:get_access_token_role": "{{wrapper}}",
+ "identity:list_access_tokens": "{{wrapper}}",
+ "identity:get_access_token": "{{wrapper}}",
+ "identity:delete_access_token": "{{wrapper}}",
+
+ "identity:list_projects_for_endpoint": "{{wrapper}}",
+ "identity:add_endpoint_to_project": "{{wrapper}}",
+ "identity:check_endpoint_in_project": "{{wrapper}}",
+ "identity:list_endpoints_for_project": "{{wrapper}}",
+ "identity:remove_endpoint_from_project": "{{wrapper}}",
+
+ "identity:create_endpoint_group": "{{wrapper}}",
+ "identity:list_endpoint_groups": "{{wrapper}}",
+ "identity:get_endpoint_group": "{{wrapper}}",
+ "identity:update_endpoint_group": "{{wrapper}}",
+ "identity:delete_endpoint_group": "{{wrapper}}",
+ "identity:list_projects_associated_with_endpoint_group": "{{wrapper}}",
+ "identity:list_endpoints_associated_with_endpoint_group": "{{wrapper}}",
+ "identity:get_endpoint_group_in_project": "{{wrapper}}",
+ "identity:list_endpoint_groups_for_project": "{{wrapper}}",
+ "identity:add_endpoint_group_to_project": "{{wrapper}}",
+ "identity:remove_endpoint_group_from_project": "{{wrapper}}",
+
+ "identity:create_identity_provider": "{{wrapper}}",
+ "identity:list_identity_providers": "{{wrapper}}",
+ "identity:get_identity_provider": "{{wrapper}}",
+ "identity:update_identity_provider": "{{wrapper}}",
+ "identity:delete_identity_provider": "{{wrapper}}",
+
+ "identity:create_protocol": "{{wrapper}}",
+ "identity:update_protocol": "{{wrapper}}",
+ "identity:get_protocol": "{{wrapper}}",
+ "identity:list_protocols": "{{wrapper}}",
+ "identity:delete_protocol": "{{wrapper}}",
+
+ "identity:create_mapping": "{{wrapper}}",
+ "identity:get_mapping": "{{wrapper}}",
+ "identity:list_mappings": "{{wrapper}}",
+ "identity:delete_mapping": "{{wrapper}}",
+ "identity:update_mapping": "{{wrapper}}",
+
+ "identity:create_service_provider": "{{wrapper}}",
+ "identity:list_service_providers": "{{wrapper}}",
+ "identity:get_service_provider": "{{wrapper}}",
+ "identity:update_service_provider": "{{wrapper}}",
+ "identity:delete_service_provider": "{{wrapper}}",
+
+ "identity:get_auth_catalog": "{{wrapper}}",
+ "identity:get_auth_projects": "{{wrapper}}",
+ "identity:get_auth_domains": "{{wrapper}}",
+ "identity:get_auth_system": "{{wrapper}}",
+
+ "identity:list_projects_for_user": "{{wrapper}}",
+ "identity:list_domains_for_user": "{{wrapper}}",
+
+ "identity:list_revoke_events": "{{wrapper}}",
+
+ "identity:create_policy_association_for_endpoint": "{{wrapper}}",
+ "identity:check_policy_association_for_endpoint": "{{wrapper}}",
+ "identity:delete_policy_association_for_endpoint": "{{wrapper}}",
+ "identity:create_policy_association_for_service": "{{wrapper}}",
+ "identity:check_policy_association_for_service": "{{wrapper}}",
+ "identity:delete_policy_association_for_service": "{{wrapper}}",
+ "identity:create_policy_association_for_region_and_service": "{{wrapper}}",
+ "identity:check_policy_association_for_region_and_service": "{{wrapper}}",
+ "identity:delete_policy_association_for_region_and_service": "{{wrapper}}",
+ "identity:get_policy_for_endpoint": "{{wrapper}}",
+ "identity:list_endpoints_for_policy": "{{wrapper}}",
+
+ "identity:create_domain_config": "{{wrapper}}",
+ "identity:get_domain_config": "{{wrapper}}",
+ "identity:get_security_compliance_domain_config": "{{wrapper}}",
+ "identity:update_domain_config": "{{wrapper}}",
+ "identity:delete_domain_config": "{{wrapper}}",
+ "identity:get_domain_config_default": "{{wrapper}}",
+
+ "identity:get_application_credential": "{{wrapper}}",
+ "identity:list_application_credentials": "{{wrapper}}",
+ "identity:create_application_credential": "{{wrapper}}",
+ "identity:delete_application_credential": "{{wrapper}}",
+}
diff --git a/old/external_policy_checker/conf/templates/neutron.policy.json b/old/external_policy_checker/conf/templates/neutron.policy.json
new file mode 100644
index 00000000..d0ab0b63
--- /dev/null
+++ b/old/external_policy_checker/conf/templates/neutron.policy.json
@@ -0,0 +1,235 @@
+{
+ "context_is_admin": "role:admin or user_name:neutron",
+ "owner": "{{wrapper}}",
+ "admin_or_owner": "{{wrapper}}",
+ "context_is_advsvc": "role:advsvc",
+ "admin_or_network_owner": "{{wrapper}}",
+ "admin_owner_or_network_owner": "{{wrapper}}",
+ "admin_only": "{{wrapper}}",
+ "regular_user": "{{wrapper}}",
+ "admin_or_data_plane_int": "{{wrapper}}",
+ "shared": "{{wrapper}}",
+ "shared_subnetpools": "{{wrapper}}",
+ "shared_address_scopes": "{{wrapper}}",
+ "external": "{{wrapper}}",
+ "default": "{{wrapper}}",
+
+ "create_subnet": "{{wrapper}}",
+ "create_subnet:segment_id": "{{wrapper}}",
+ "create_subnet:service_types": "{{wrapper}}",
+ "get_subnet": "{{wrapper}}",
+ "get_subnet:segment_id": "{{wrapper}}",
+ "update_subnet": "{{wrapper}}",
+ "update_subnet:service_types": "{{wrapper}}",
+ "delete_subnet": "{{wrapper}}",
+
+ "create_subnetpool": "{{wrapper}}",
+ "create_subnetpool:shared": "{{wrapper}}",
+ "create_subnetpool:is_default": "{{wrapper}}",
+ "get_subnetpool": "{{wrapper}}",
+ "update_subnetpool": "{{wrapper}}",
+ "update_subnetpool:is_default": "{{wrapper}}",
+ "delete_subnetpool": "{{wrapper}}",
+
+ "create_address_scope": "{{wrapper}}",
+ "create_address_scope:shared": "{{wrapper}}",
+ "get_address_scope": "{{wrapper}}",
+ "update_address_scope": "{{wrapper}}",
+ "update_address_scope:shared": "{{wrapper}}",
+ "delete_address_scope": "{{wrapper}}",
+
+ "create_network": "{{wrapper}}",
+ "get_network": "{{wrapper}}",
+ "get_network:router:external": "{{wrapper}}",
+ "get_network:segments": "{{wrapper}}",
+ "get_network:provider:network_type": "{{wrapper}}",
+ "get_network:provider:physical_network": "{{wrapper}}",
+ "get_network:provider:segmentation_id": "{{wrapper}}",
+ "get_network:queue_id": "{{wrapper}}",
+ "get_network_ip_availabilities": "{{wrapper}}",
+ "get_network_ip_availability": "{{wrapper}}",
+ "create_network:shared": "{{wrapper}}",
+ "create_network:router:external": "{{wrapper}}",
+ "create_network:is_default": "{{wrapper}}",
+ "create_network:segments": "{{wrapper}}",
+ "create_network:provider:network_type": "{{wrapper}}",
+ "create_network:provider:physical_network": "{{wrapper}}",
+ "create_network:provider:segmentation_id": "{{wrapper}}",
+ "update_network": "{{wrapper}}",
+ "update_network:segments": "{{wrapper}}",
+ "update_network:shared": "{{wrapper}}",
+ "update_network:provider:network_type": "{{wrapper}}",
+ "update_network:provider:physical_network": "{{wrapper}}",
+ "update_network:provider:segmentation_id": "{{wrapper}}",
+ "update_network:router:external": "{{wrapper}}",
+ "delete_network": "{{wrapper}}",
+
+ "create_segment": "{{wrapper}}",
+ "get_segment": "{{wrapper}}",
+ "update_segment": "{{wrapper}}",
+ "delete_segment": "{{wrapper}}",
+
+ "network_device": "{{wrapper}}",
+ "create_port": "{{wrapper}}",
+ "create_port:device_owner": "{{wrapper}}",
+ "create_port:mac_address": "{{wrapper}}",
+ "create_port:fixed_ips:ip_address": "{{wrapper}}",
+ "create_port:fixed_ips:subnet_id": "{{wrapper}}",
+ "create_port:port_security_enabled": "{{wrapper}}",
+ "create_port:binding:host_id": "{{wrapper}}",
+ "create_port:binding:profile": "{{wrapper}}",
+ "create_port:mac_learning_enabled": "{{wrapper}}",
+ "create_port:allowed_address_pairs": "{{wrapper}}",
+ "get_port": "{{wrapper}}",
+ "get_port:queue_id": "{{wrapper}}",
+ "get_port:binding:vif_type": "{{wrapper}}",
+ "get_port:binding:vif_details": "{{wrapper}}",
+ "get_port:binding:host_id": "{{wrapper}}",
+ "get_port:binding:profile": "{{wrapper}}",
+ "update_port": "{{wrapper}}",
+ "update_port:device_owner": "{{wrapper}}",
+ "update_port:mac_address": "{{wrapper}}",
+ "update_port:fixed_ips:ip_address": "{{wrapper}}",
+ "update_port:fixed_ips:subnet_id": "{{wrapper}}",
+ "update_port:port_security_enabled": "{{wrapper}}",
+ "update_port:binding:host_id": "{{wrapper}}",
+ "update_port:binding:profile": "{{wrapper}}",
+ "update_port:mac_learning_enabled": "{{wrapper}}",
+ "update_port:allowed_address_pairs": "{{wrapper}}",
+ "update_port:data_plane_status": "{{wrapper}}",
+ "delete_port": "{{wrapper}}",
+
+ "get_router:ha": "{{wrapper}}",
+ "create_router": "{{wrapper}}",
+ "create_router:external_gateway_info:enable_snat": "{{wrapper}}",
+ "create_router:distributed": "{{wrapper}}",
+ "create_router:ha": "{{wrapper}}",
+ "get_router": "{{wrapper}}",
+ "get_router:distributed": "{{wrapper}}",
+ "update_router": "{{wrapper}}",
+ "update_router:external_gateway_info": "{{wrapper}}",
+ "update_router:external_gateway_info:network_id": "{{wrapper}}",
+ "update_router:external_gateway_info:enable_snat": "{{wrapper}}",
+ "update_router:distributed": "{{wrapper}}",
+ "update_router:ha": "{{wrapper}}",
+ "delete_router": "{{wrapper}}",
+
+ "add_router_interface": "{{wrapper}}",
+ "remove_router_interface": "{{wrapper}}",
+
+ "create_router:external_gateway_info:external_fixed_ips": "{{wrapper}}",
+ "update_router:external_gateway_info:external_fixed_ips": "{{wrapper}}",
+
+ "create_qos_queue": "{{wrapper}}",
+ "get_qos_queue": "{{wrapper}}",
+
+ "update_agent": "{{wrapper}}",
+ "delete_agent": "{{wrapper}}",
+ "get_agent": "{{wrapper}}",
+
+ "create_dhcp-network": "{{wrapper}}",
+ "delete_dhcp-network": "{{wrapper}}",
+ "get_dhcp-networks": "{{wrapper}}",
+ "create_l3-router": "{{wrapper}}",
+ "delete_l3-router": "{{wrapper}}",
+ "get_l3-routers": "{{wrapper}}",
+ "get_dhcp-agents": "{{wrapper}}",
+ "get_l3-agents": "{{wrapper}}",
+ "get_loadbalancer-agent": "{{wrapper}}",
+ "get_loadbalancer-pools": "{{wrapper}}",
+ "get_agent-loadbalancers": "{{wrapper}}",
+ "get_loadbalancer-hosting-agent": "{{wrapper}}",
+
+ "create_floatingip": "{{wrapper}}",
+ "create_floatingip:floating_ip_address": "{{wrapper}}",
+ "update_floatingip": "{{wrapper}}",
+ "delete_floatingip": "{{wrapper}}",
+ "get_floatingip": "{{wrapper}}",
+
+ "create_network_profile": "{{wrapper}}",
+ "update_network_profile": "{{wrapper}}",
+ "delete_network_profile": "{{wrapper}}",
+ "get_network_profiles": "{{wrapper}}",
+ "get_network_profile": "{{wrapper}}",
+ "update_policy_profiles": "{{wrapper}}",
+ "get_policy_profiles": "{{wrapper}}",
+ "get_policy_profile": "{{wrapper}}",
+
+ "create_metering_label": "{{wrapper}}",
+ "delete_metering_label": "{{wrapper}}",
+ "get_metering_label": "{{wrapper}}",
+
+ "create_metering_label_rule": "{{wrapper}}",
+ "delete_metering_label_rule": "{{wrapper}}",
+ "get_metering_label_rule": "{{wrapper}}",
+
+ "get_service_provider": "{{wrapper}}",
+ "get_lsn": "{{wrapper}}",
+ "create_lsn": "{{wrapper}}",
+
+ "create_flavor": "{{wrapper}}",
+ "update_flavor": "{{wrapper}}",
+ "delete_flavor": "{{wrapper}}",
+ "get_flavors": "{{wrapper}}",
+ "get_flavor": "{{wrapper}}",
+ "create_service_profile": "{{wrapper}}",
+ "update_service_profile": "{{wrapper}}",
+ "delete_service_profile": "{{wrapper}}",
+ "get_service_profiles": "{{wrapper}}",
+ "get_service_profile": "{{wrapper}}",
+
+ "get_policy": "{{wrapper}}",
+ "create_policy": "{{wrapper}}",
+ "update_policy": "{{wrapper}}",
+ "delete_policy": "{{wrapper}}",
+ "get_policy_bandwidth_limit_rule": "{{wrapper}}",
+ "create_policy_bandwidth_limit_rule": "{{wrapper}}",
+ "delete_policy_bandwidth_limit_rule": "{{wrapper}}",
+ "update_policy_bandwidth_limit_rule": "{{wrapper}}",
+ "get_policy_dscp_marking_rule": "{{wrapper}}",
+ "create_policy_dscp_marking_rule": "{{wrapper}}",
+ "delete_policy_dscp_marking_rule": "{{wrapper}}",
+ "update_policy_dscp_marking_rule": "{{wrapper}}",
+ "get_rule_type": "{{wrapper}}",
+ "get_policy_minimum_bandwidth_rule": "{{wrapper}}",
+ "create_policy_minimum_bandwidth_rule": "{{wrapper}}",
+ "delete_policy_minimum_bandwidth_rule": "{{wrapper}}",
+ "update_policy_minimum_bandwidth_rule": "{{wrapper}}",
+
+ "restrict_wildcard": "{{wrapper}}",
+ "create_rbac_policy": "{{wrapper}}",
+ "create_rbac_policy:target_tenant": "{{wrapper}}",
+ "update_rbac_policy": "{{wrapper}}",
+ "update_rbac_policy:target_tenant": "{{wrapper}}",
+ "get_rbac_policy": "{{wrapper}}",
+ "delete_rbac_policy": "{{wrapper}}",
+
+ "create_flavor_service_profile": "{{wrapper}}",
+ "delete_flavor_service_profile": "{{wrapper}}",
+ "get_flavor_service_profile": "{{wrapper}}",
+ "get_auto_allocated_topology": "{{wrapper}}",
+
+ "create_trunk": "{{wrapper}}",
+ "get_trunk": "{{wrapper}}",
+ "delete_trunk": "{{wrapper}}",
+ "get_subports": "{{wrapper}}",
+ "add_subports": "{{wrapper}}",
+ "remove_subports": "{{wrapper}}",
+
+ "get_security_groups": "{{wrapper}}",
+ "get_security_group": "{{wrapper}}",
+ "create_security_group": "{{wrapper}}",
+ "update_security_group": "{{wrapper}}",
+ "delete_security_group": "{{wrapper}}",
+ "get_security_group_rules": "{{wrapper}}",
+ "get_security_group_rule": "{{wrapper}}",
+ "create_security_group_rule": "{{wrapper}}",
+ "delete_security_group_rule": "{{wrapper}}",
+
+ "get_loggable_resources": "{{wrapper}}",
+ "create_log": "{{wrapper}}",
+ "update_log": "{{wrapper}}",
+ "delete_log": "{{wrapper}}",
+ "get_logs": "{{wrapper}}",
+ "get_log": "{{wrapper}}",
+}
diff --git a/old/external_policy_checker/conf/templates/nova.policy.json b/old/external_policy_checker/conf/templates/nova.policy.json
new file mode 100644
index 00000000..e5de675f
--- /dev/null
+++ b/old/external_policy_checker/conf/templates/nova.policy.json
@@ -0,0 +1,488 @@
+{
+ "context_is_admin": "role:admin",
+ "admin_or_owner": "is_admin:True or project_id:%(project_id)s",
+ "default": "{{wrapper}}",
+
+ "cells_scheduler_filter:TargetCellFilter": "{{wrapper}}",
+
+ "compute:create": "{{wrapper}}",
+ "compute:create:attach_network": "{{wrapper}}",
+ "compute:create:attach_volume": "{{wrapper}}",
+ "compute:create:forced_host": "{{wrapper}}",
+
+ "compute:get": "{{wrapper}}",
+ "compute:get_all": "{{wrapper}}",
+ "compute:get_all_tenants": "{{wrapper}}",
+
+ "compute:update": "{{wrapper}}",
+
+ "compute:get_instance_metadata": "{{wrapper}}",
+ "compute:get_all_instance_metadata": "{{wrapper}}",
+ "compute:get_all_instance_system_metadata": "{{wrapper}}",
+ "compute:update_instance_metadata": "{{wrapper}}",
+ "compute:delete_instance_metadata": "{{wrapper}}",
+
+ "compute:get_instance_faults": "{{wrapper}}",
+ "compute:get_diagnostics": "{{wrapper}}",
+ "compute:get_instance_diagnostics": "{{wrapper}}",
+
+ "compute:start": "{{wrapper}}",
+ "compute:stop": "{{wrapper}}",
+
+ "compute:get_lock": "{{wrapper}}",
+ "compute:lock": "{{wrapper}}",
+ "compute:unlock": "{{wrapper}}",
+ "compute:unlock_override": "{{wrapper}}",
+
+ "compute:get_vnc_console": "{{wrapper}}",
+ "compute:get_spice_console": "{{wrapper}}",
+ "compute:get_rdp_console": "{{wrapper}}",
+ "compute:get_serial_console": "{{wrapper}}",
+ "compute:get_mks_console": "{{wrapper}}",
+ "compute:get_console_output": "{{wrapper}}",
+
+ "compute:reset_network": "{{wrapper}}",
+ "compute:inject_network_info": "{{wrapper}}",
+ "compute:add_fixed_ip": "{{wrapper}}",
+ "compute:remove_fixed_ip": "{{wrapper}}",
+
+ "compute:attach_volume": "{{wrapper}}",
+ "compute:detach_volume": "{{wrapper}}",
+ "compute:swap_volume": "{{wrapper}}",
+
+ "compute:attach_interface": "{{wrapper}}",
+ "compute:detach_interface": "{{wrapper}}",
+
+ "compute:set_admin_password": "{{wrapper}}",
+
+ "compute:rescue": "{{wrapper}}",
+ "compute:unrescue": "{{wrapper}}",
+
+ "compute:suspend": "{{wrapper}}",
+ "compute:resume": "{{wrapper}}",
+
+ "compute:pause": "{{wrapper}}",
+ "compute:unpause": "{{wrapper}}",
+
+ "compute:shelve": "{{wrapper}}",
+ "compute:shelve_offload": "{{wrapper}}",
+ "compute:unshelve": "{{wrapper}}",
+
+ "compute:snapshot": "{{wrapper}}",
+ "compute:snapshot_volume_backed": "{{wrapper}}",
+ "compute:backup": "{{wrapper}}",
+
+ "compute:resize": "{{wrapper}}",
+ "compute:confirm_resize": "{{wrapper}}",
+ "compute:revert_resize": "{{wrapper}}",
+
+ "compute:rebuild": "{{wrapper}}",
+ "compute:reboot": "{{wrapper}}",
+ "compute:delete": "{{wrapper}}",
+ "compute:soft_delete": "{{wrapper}}",
+ "compute:force_delete": "{{wrapper}}",
+
+ "compute:security_groups:add_to_instance": "{{wrapper}}",
+ "compute:security_groups:remove_from_instance": "{{wrapper}}",
+
+ "compute:delete": "{{wrapper}}",
+ "compute:soft_delete": "{{wrapper}}",
+ "compute:force_delete": "{{wrapper}}",
+ "compute:restore": "{{wrapper}}",
+
+ "compute:volume_snapshot_create": "{{wrapper}}",
+ "compute:volume_snapshot_delete": "{{wrapper}}",
+
+ "admin_api": "{{wrapper}}",
+ "compute_extension:accounts": "{{wrapper}}",
+ "compute_extension:admin_actions": "{{wrapper}}",
+ "compute_extension:admin_actions:pause": "{{wrapper}}",
+ "compute_extension:admin_actions:unpause": "{{wrapper}}",
+ "compute_extension:admin_actions:suspend": "{{wrapper}}",
+ "compute_extension:admin_actions:resume": "{{wrapper}}",
+ "compute_extension:admin_actions:lock": "{{wrapper}}",
+ "compute_extension:admin_actions:unlock": "{{wrapper}}",
+ "compute_extension:admin_actions:resetNetwork": "{{wrapper}}",
+ "compute_extension:admin_actions:injectNetworkInfo": "{{wrapper}}",
+ "compute_extension:admin_actions:createBackup": "{{wrapper}}",
+ "compute_extension:admin_actions:migrateLive": "{{wrapper}}",
+ "compute_extension:admin_actions:resetState": "{{wrapper}}",
+ "compute_extension:admin_actions:migrate": "{{wrapper}}",
+ "compute_extension:aggregates": "{{wrapper}}",
+ "compute_extension:agents": "{{wrapper}}",
+ "compute_extension:attach_interfaces": "{{wrapper}}",
+ "compute_extension:baremetal_nodes": "{{wrapper}}",
+ "compute_extension:cells": "{{wrapper}}",
+ "compute_extension:cells:create": "{{wrapper}}",
+ "compute_extension:cells:delete": "{{wrapper}}",
+ "compute_extension:cells:update": "{{wrapper}}",
+ "compute_extension:cells:sync_instances": "{{wrapper}}",
+ "compute_extension:certificates": "{{wrapper}}",
+ "compute_extension:cloudpipe": "{{wrapper}}",
+ "compute_extension:cloudpipe_update": "{{wrapper}}",
+ "compute_extension:config_drive": "{{wrapper}}",
+ "compute_extension:console_output": "{{wrapper}}",
+ "compute_extension:consoles": "{{wrapper}}",
+ "compute_extension:createserverext": "{{wrapper}}",
+ "compute_extension:deferred_delete": "{{wrapper}}",
+ "compute_extension:disk_config": "{{wrapper}}",
+ "compute_extension:evacuate": "{{wrapper}}",
+ "compute_extension:extended_server_attributes": "{{wrapper}}",
+ "compute_extension:extended_status": "{{wrapper}}",
+ "compute_extension:extended_availability_zone": "{{wrapper}}",
+ "compute_extension:extended_ips": "{{wrapper}}",
+ "compute_extension:extended_ips_mac": "{{wrapper}}",
+ "compute_extension:extended_vif_net": "{{wrapper}}",
+ "compute_extension:extended_volumes": "{{wrapper}}",
+ "compute_extension:fixed_ips": "{{wrapper}}",
+ "compute_extension:flavor_access": "{{wrapper}}",
+ "compute_extension:flavor_access:addTenantAccess": "{{wrapper}}",
+ "compute_extension:flavor_access:removeTenantAccess": "{{wrapper}}",
+ "compute_extension:flavor_disabled": "{{wrapper}}",
+ "compute_extension:flavor_rxtx": "{{wrapper}}",
+ "compute_extension:flavor_swap": "{{wrapper}}",
+ "compute_extension:flavorextradata": "{{wrapper}}",
+ "compute_extension:flavorextraspecs:index": "{{wrapper}}",
+ "compute_extension:flavorextraspecs:show": "{{wrapper}}",
+ "compute_extension:flavorextraspecs:create": "{{wrapper}}",
+ "compute_extension:flavorextraspecs:update": "{{wrapper}}",
+ "compute_extension:flavorextraspecs:delete": "{{wrapper}}",
+ "compute_extension:flavormanage": "{{wrapper}}",
+ "compute_extension:floating_ip_dns": "{{wrapper}}",
+ "compute_extension:floating_ip_pools": "{{wrapper}}",
+ "compute_extension:floating_ips": "{{wrapper}}",
+ "compute_extension:floating_ips_bulk": "{{wrapper}}",
+ "compute_extension:fping": "{{wrapper}}",
+ "compute_extension:fping:all_tenants": "{{wrapper}}",
+ "compute_extension:hide_server_addresses": "{{wrapper}}",
+ "compute_extension:hosts": "{{wrapper}}",
+ "compute_extension:hypervisors": "{{wrapper}}",
+ "compute_extension:image_size": "{{wrapper}}",
+ "compute_extension:instance_actions": "{{wrapper}}",
+ "compute_extension:instance_actions:events": "{{wrapper}}",
+ "compute_extension:instance_usage_audit_log": "{{wrapper}}",
+ "compute_extension:keypairs": "{{wrapper}}",
+ "compute_extension:keypairs:index": "{{wrapper}}",
+ "compute_extension:keypairs:show": "{{wrapper}}",
+ "compute_extension:keypairs:create": "{{wrapper}}",
+ "compute_extension:keypairs:delete": "{{wrapper}}",
+ "compute_extension:multinic": "{{wrapper}}",
+ "compute_extension:networks": "{{wrapper}}",
+ "compute_extension:networks:view": "{{wrapper}}",
+ "compute_extension:networks_associate": "{{wrapper}}",
+ "compute_extension:os-tenant-networks": "{{wrapper}}",
+ "compute_extension:quotas:show": "{{wrapper}}",
+ "compute_extension:quotas:update": "{{wrapper}}",
+ "compute_extension:quotas:delete": "{{wrapper}}",
+ "compute_extension:quota_classes": "{{wrapper}}",
+ "compute_extension:rescue": "{{wrapper}}",
+ "compute_extension:security_group_default_rules": "{{wrapper}}",
+ "compute_extension:security_groups": "{{wrapper}}",
+ "compute_extension:server_diagnostics": "{{wrapper}}",
+ "compute_extension:server_groups": "{{wrapper}}",
+ "compute_extension:server_password": "{{wrapper}}",
+ "compute_extension:server_usage": "{{wrapper}}",
+ "compute_extension:services": "{{wrapper}}",
+ "compute_extension:shelve": "{{wrapper}}",
+ "compute_extension:shelveOffload": "{{wrapper}}",
+ "compute_extension:simple_tenant_usage:show": "{{wrapper}}",
+ "compute_extension:simple_tenant_usage:list": "{{wrapper}}",
+ "compute_extension:unshelve": "{{wrapper}}",
+ "compute_extension:users": "{{wrapper}}",
+ "compute_extension:virtual_interfaces": "{{wrapper}}",
+ "compute_extension:virtual_storage_arrays": "{{wrapper}}",
+ "compute_extension:volumes": "{{wrapper}}",
+ "compute_extension:volume_attachments:index": "{{wrapper}}",
+ "compute_extension:volume_attachments:show": "{{wrapper}}",
+ "compute_extension:volume_attachments:create": "{{wrapper}}",
+ "compute_extension:volume_attachments:update": "{{wrapper}}",
+ "compute_extension:volume_attachments:delete": "{{wrapper}}",
+ "compute_extension:volumetypes": "{{wrapper}}",
+ "compute_extension:availability_zone:list": "{{wrapper}}",
+ "compute_extension:availability_zone:detail": "{{wrapper}}",
+ "compute_extension:used_limits_for_admin": "{{wrapper}}",
+ "compute_extension:migrations:index": "{{wrapper}}",
+ "compute_extension:os-assisted-volume-snapshots:create": "{{wrapper}}",
+ "compute_extension:os-assisted-volume-snapshots:delete": "{{wrapper}}",
+ "compute_extension:console_auth_tokens": "{{wrapper}}",
+ "compute_extension:os-server-external-events:create": "{{wrapper}}",
+
+ "network:get_all": "{{wrapper}}",
+ "network:get": "{{wrapper}}",
+ "network:create": "{{wrapper}}",
+ "network:delete": "{{wrapper}}",
+ "network:associate": "{{wrapper}}",
+ "network:disassociate": "{{wrapper}}",
+ "network:get_vifs_by_instance": "{{wrapper}}",
+ "network:allocate_for_instance": "{{wrapper}}",
+ "network:deallocate_for_instance": "{{wrapper}}",
+ "network:validate_networks": "{{wrapper}}",
+ "network:get_instance_uuids_by_ip_filter": "{{wrapper}}",
+ "network:get_instance_id_by_floating_address": "{{wrapper}}",
+ "network:setup_networks_on_host": "{{wrapper}}",
+ "network:get_backdoor_port": "{{wrapper}}",
+
+ "network:get_floating_ip": "{{wrapper}}",
+ "network:get_floating_ip_pools": "{{wrapper}}",
+ "network:get_floating_ip_by_address": "{{wrapper}}",
+ "network:get_floating_ips_by_project": "{{wrapper}}",
+ "network:get_floating_ips_by_fixed_address": "{{wrapper}}",
+ "network:allocate_floating_ip": "{{wrapper}}",
+ "network:associate_floating_ip": "{{wrapper}}",
+ "network:disassociate_floating_ip": "{{wrapper}}",
+ "network:release_floating_ip": "{{wrapper}}",
+ "network:migrate_instance_start": "{{wrapper}}",
+ "network:migrate_instance_finish": "{{wrapper}}",
+
+ "network:get_fixed_ip": "{{wrapper}}",
+ "network:get_fixed_ip_by_address": "{{wrapper}}",
+ "network:add_fixed_ip_to_instance": "{{wrapper}}",
+ "network:remove_fixed_ip_from_instance": "{{wrapper}}",
+ "network:add_network_to_project": "{{wrapper}}",
+ "network:get_instance_nw_info": "{{wrapper}}",
+
+ "network:get_dns_domains": "{{wrapper}}",
+ "network:add_dns_entry": "{{wrapper}}",
+ "network:modify_dns_entry": "{{wrapper}}",
+ "network:delete_dns_entry": "{{wrapper}}",
+ "network:get_dns_entries_by_address": "{{wrapper}}",
+ "network:get_dns_entries_by_name": "{{wrapper}}",
+ "network:create_private_dns_domain": "{{wrapper}}",
+ "network:create_public_dns_domain": "{{wrapper}}",
+ "network:delete_dns_domain": "{{wrapper}}",
+ "network:attach_external_network": "{{wrapper}}",
+ "network:get_vif_by_mac_address": "{{wrapper}}",
+
+ "os_compute_api:servers:detail:get_all_tenants": "{{wrapper}}",
+ "os_compute_api:servers:index:get_all_tenants": "{{wrapper}}",
+ "os_compute_api:servers:confirm_resize": "{{wrapper}}",
+ "os_compute_api:servers:create": "{{wrapper}}",
+ "os_compute_api:servers:create:attach_network": "{{wrapper}}",
+ "os_compute_api:servers:create:attach_volume": "{{wrapper}}",
+ "os_compute_api:servers:create:forced_host": "{{wrapper}}",
+ "os_compute_api:servers:delete": "{{wrapper}}",
+ "os_compute_api:servers:update": "{{wrapper}}",
+ "os_compute_api:servers:detail": "{{wrapper}}",
+ "os_compute_api:servers:index": "{{wrapper}}",
+ "os_compute_api:servers:reboot": "{{wrapper}}",
+ "os_compute_api:servers:rebuild": "{{wrapper}}",
+ "os_compute_api:servers:resize": "{{wrapper}}",
+ "os_compute_api:servers:revert_resize": "{{wrapper}}",
+ "os_compute_api:servers:show": "{{wrapper}}",
+ "os_compute_api:servers:create_image": "{{wrapper}}",
+ "os_compute_api:servers:create_image:allow_volume_backed": "{{wrapper}}",
+ "os_compute_api:servers:start": "{{wrapper}}",
+ "os_compute_api:servers:stop": "{{wrapper}}",
+ "os_compute_api:os-access-ips:discoverable": "{{wrapper}}",
+ "os_compute_api:os-access-ips": "{{wrapper}}",
+ "os_compute_api:os-admin-actions": "{{wrapper}}",
+ "os_compute_api:os-admin-actions:discoverable": "{{wrapper}}",
+ "os_compute_api:os-admin-actions:reset_network": "{{wrapper}}",
+ "os_compute_api:os-admin-actions:inject_network_info": "{{wrapper}}",
+ "os_compute_api:os-admin-actions:reset_state": "{{wrapper}}",
+ "os_compute_api:os-admin-password": "{{wrapper}}",
+ "os_compute_api:os-admin-password:discoverable": "{{wrapper}}",
+ "os_compute_api:os-aggregates:discoverable": "{{wrapper}}",
+ "os_compute_api:os-aggregates:index": "{{wrapper}}",
+ "os_compute_api:os-aggregates:create": "{{wrapper}}",
+ "os_compute_api:os-aggregates:show": "{{wrapper}}",
+ "os_compute_api:os-aggregates:update": "{{wrapper}}",
+ "os_compute_api:os-aggregates:delete": "{{wrapper}}",
+ "os_compute_api:os-aggregates:add_host": "{{wrapper}}",
+ "os_compute_api:os-aggregates:remove_host": "{{wrapper}}",
+ "os_compute_api:os-aggregates:set_metadata": "{{wrapper}}",
+ "os_compute_api:os-agents": "{{wrapper}}",
+ "os_compute_api:os-agents:discoverable": "{{wrapper}}",
+ "os_compute_api:os-attach-interfaces": "{{wrapper}}",
+ "os_compute_api:os-attach-interfaces:discoverable": "{{wrapper}}",
+ "os_compute_api:os-baremetal-nodes": "{{wrapper}}",
+ "os_compute_api:os-baremetal-nodes:discoverable": "{{wrapper}}",
+ "os_compute_api:os-block-device-mapping-v1:discoverable": "{{wrapper}}",
+ "os_compute_api:os-cells": "{{wrapper}}",
+ "os_compute_api:os-cells:create": "{{wrapper}}",
+ "os_compute_api:os-cells:delete": "{{wrapper}}",
+ "os_compute_api:os-cells:update": "{{wrapper}}",
+ "os_compute_api:os-cells:sync_instances": "{{wrapper}}",
+ "os_compute_api:os-cells:discoverable": "{{wrapper}}",
+ "os_compute_api:os-certificates:create": "{{wrapper}}",
+ "os_compute_api:os-certificates:show": "{{wrapper}}",
+ "os_compute_api:os-certificates:discoverable": "{{wrapper}}",
+ "os_compute_api:os-cloudpipe": "{{wrapper}}",
+ "os_compute_api:os-cloudpipe:discoverable": "{{wrapper}}",
+ "os_compute_api:os-config-drive": "{{wrapper}}",
+ "os_compute_api:os-consoles:discoverable": "{{wrapper}}",
+ "os_compute_api:os-consoles:create": "{{wrapper}}",
+ "os_compute_api:os-consoles:delete": "{{wrapper}}",
+ "os_compute_api:os-consoles:index": "{{wrapper}}",
+ "os_compute_api:os-consoles:show": "{{wrapper}}",
+ "os_compute_api:os-console-output:discoverable": "{{wrapper}}",
+ "os_compute_api:os-console-output": "{{wrapper}}",
+ "os_compute_api:os-remote-consoles": "{{wrapper}}",
+ "os_compute_api:os-remote-consoles:discoverable": "{{wrapper}}",
+ "os_compute_api:os-create-backup:discoverable": "{{wrapper}}",
+ "os_compute_api:os-create-backup": "{{wrapper}}",
+ "os_compute_api:os-deferred-delete": "{{wrapper}}",
+ "os_compute_api:os-deferred-delete:discoverable": "{{wrapper}}",
+ "os_compute_api:os-disk-config": "{{wrapper}}",
+ "os_compute_api:os-disk-config:discoverable": "{{wrapper}}",
+ "os_compute_api:os-evacuate": "{{wrapper}}",
+ "os_compute_api:os-evacuate:discoverable": "{{wrapper}}",
+ "os_compute_api:os-extended-server-attributes": "{{wrapper}}",
+ "os_compute_api:os-extended-server-attributes:discoverable": "{{wrapper}}",
+ "os_compute_api:os-extended-status": "{{wrapper}}",
+ "os_compute_api:os-extended-status:discoverable": "{{wrapper}}",
+ "os_compute_api:os-extended-availability-zone": "{{wrapper}}",
+ "os_compute_api:os-extended-availability-zone:discoverable": "{{wrapper}}",
+ "os_compute_api:extensions": "{{wrapper}}",
+ "os_compute_api:extension_info:discoverable": "{{wrapper}}",
+ "os_compute_api:os-extended-volumes": "{{wrapper}}",
+ "os_compute_api:os-extended-volumes:discoverable": "{{wrapper}}",
+ "os_compute_api:os-fixed-ips": "{{wrapper}}",
+ "os_compute_api:os-fixed-ips:discoverable": "{{wrapper}}",
+ "os_compute_api:os-flavor-access": "{{wrapper}}",
+ "os_compute_api:os-flavor-access:discoverable": "{{wrapper}}",
+ "os_compute_api:os-flavor-access:remove_tenant_access": "{{wrapper}}",
+ "os_compute_api:os-flavor-access:add_tenant_access": "{{wrapper}}",
+ "os_compute_api:os-flavor-rxtx": "{{wrapper}}",
+ "os_compute_api:os-flavor-rxtx:discoverable": "{{wrapper}}",
+ "os_compute_api:flavors:discoverable": "{{wrapper}}",
+ "os_compute_api:os-flavor-extra-specs:discoverable": "{{wrapper}}",
+ "os_compute_api:os-flavor-extra-specs:index": "{{wrapper}}",
+ "os_compute_api:os-flavor-extra-specs:show": "{{wrapper}}",
+ "os_compute_api:os-flavor-extra-specs:create": "{{wrapper}}",
+ "os_compute_api:os-flavor-extra-specs:update": "{{wrapper}}",
+ "os_compute_api:os-flavor-extra-specs:delete": "{{wrapper}}",
+ "os_compute_api:os-flavor-manage:discoverable": "{{wrapper}}",
+ "os_compute_api:os-flavor-manage": "{{wrapper}}",
+ "os_compute_api:os-floating-ip-dns": "{{wrapper}}",
+ "os_compute_api:os-floating-ip-dns:discoverable": "{{wrapper}}",
+ "os_compute_api:os-floating-ip-dns:domain:update": "{{wrapper}}",
+ "os_compute_api:os-floating-ip-dns:domain:delete": "{{wrapper}}",
+ "os_compute_api:os-floating-ip-pools": "{{wrapper}}",
+ "os_compute_api:os-floating-ip-pools:discoverable": "{{wrapper}}",
+ "os_compute_api:os-floating-ips": "{{wrapper}}",
+ "os_compute_api:os-floating-ips:discoverable": "{{wrapper}}",
+ "os_compute_api:os-floating-ips-bulk": "{{wrapper}}",
+ "os_compute_api:os-floating-ips-bulk:discoverable": "{{wrapper}}",
+ "os_compute_api:os-fping": "{{wrapper}}",
+ "os_compute_api:os-fping:discoverable": "{{wrapper}}",
+ "os_compute_api:os-fping:all_tenants": "{{wrapper}}",
+ "os_compute_api:os-hide-server-addresses": "{{wrapper}}",
+ "os_compute_api:os-hide-server-addresses:discoverable": "{{wrapper}}",
+ "os_compute_api:os-hosts": "{{wrapper}}",
+ "os_compute_api:os-hosts:discoverable": "{{wrapper}}",
+ "os_compute_api:os-hypervisors": "{{wrapper}}",
+ "os_compute_api:os-hypervisors:discoverable": "{{wrapper}}",
+ "os_compute_api:images:discoverable": "{{wrapper}}",
+ "os_compute_api:image-size": "{{wrapper}}",
+ "os_compute_api:image-size:discoverable": "{{wrapper}}",
+ "os_compute_api:os-instance-actions": "{{wrapper}}",
+ "os_compute_api:os-instance-actions:discoverable": "{{wrapper}}",
+ "os_compute_api:os-instance-actions:events": "{{wrapper}}",
+ "os_compute_api:os-instance-usage-audit-log": "{{wrapper}}",
+ "os_compute_api:os-instance-usage-audit-log:discoverable": "{{wrapper}}",
+ "os_compute_api:ips:discoverable": "{{wrapper}}",
+ "os_compute_api:ips:index": "{{wrapper}}",
+ "os_compute_api:ips:show": "{{wrapper}}",
+ "os_compute_api:os-keypairs:discoverable": "{{wrapper}}",
+ "os_compute_api:os-keypairs": "{{wrapper}}",
+ "os_compute_api:os-keypairs:index": "{{wrapper}}",
+ "os_compute_api:os-keypairs:show": "{{wrapper}}",
+ "os_compute_api:os-keypairs:create": "{{wrapper}}",
+ "os_compute_api:os-keypairs:delete": "{{wrapper}}",
+ "os_compute_api:limits:discoverable": "{{wrapper}}",
+ "os_compute_api:limits": "{{wrapper}}",
+ "os_compute_api:os-lock-server:discoverable": "{{wrapper}}",
+ "os_compute_api:os-lock-server:lock": "{{wrapper}}",
+ "os_compute_api:os-lock-server:unlock": "{{wrapper}}",
+ "os_compute_api:os-lock-server:unlock:unlock_override": "{{wrapper}}",
+ "os_compute_api:os-migrate-server:discoverable": "{{wrapper}}",
+ "os_compute_api:os-migrate-server:migrate": "{{wrapper}}",
+ "os_compute_api:os-migrate-server:migrate_live": "{{wrapper}}",
+ "os_compute_api:os-multinic": "{{wrapper}}",
+ "os_compute_api:os-multinic:discoverable": "{{wrapper}}",
+ "os_compute_api:os-networks": "{{wrapper}}",
+ "os_compute_api:os-networks:view": "{{wrapper}}",
+ "os_compute_api:os-networks:discoverable": "{{wrapper}}",
+ "os_compute_api:os-networks-associate": "{{wrapper}}",
+ "os_compute_api:os-networks-associate:discoverable": "{{wrapper}}",
+ "os_compute_api:os-pause-server:discoverable": "{{wrapper}}",
+ "os_compute_api:os-pause-server:pause": "{{wrapper}}",
+ "os_compute_api:os-pause-server:unpause": "{{wrapper}}",
+ "os_compute_api:os-pci:pci_servers": "{{wrapper}}",
+ "os_compute_api:os-pci:discoverable": "{{wrapper}}",
+ "os_compute_api:os-pci:index": "{{wrapper}}",
+ "os_compute_api:os-pci:detail": "{{wrapper}}",
+ "os_compute_api:os-pci:show": "{{wrapper}}",
+ "os_compute_api:os-personality:discoverable": "{{wrapper}}",
+ "os_compute_api:os-preserve-ephemeral-rebuild:discoverable": "{{wrapper}}",
+ "os_compute_api:os-quota-sets:discoverable": "{{wrapper}}",
+ "os_compute_api:os-quota-sets:show": "{{wrapper}}",
+ "os_compute_api:os-quota-sets:defaults": "{{wrapper}}",
+ "os_compute_api:os-quota-sets:update": "{{wrapper}}",
+ "os_compute_api:os-quota-sets:delete": "{{wrapper}}",
+ "os_compute_api:os-quota-sets:detail": "{{wrapper}}",
+ "os_compute_api:os-quota-class-sets:update": "{{wrapper}}",
+ "os_compute_api:os-quota-class-sets:show": "{{wrapper}}",
+ "os_compute_api:os-quota-class-sets:discoverable": "{{wrapper}}",
+ "os_compute_api:os-rescue": "{{wrapper}}",
+ "os_compute_api:os-rescue:discoverable": "{{wrapper}}",
+ "os_compute_api:os-scheduler-hints:discoverable": "{{wrapper}}",
+ "os_compute_api:os-security-group-default-rules:discoverable": "{{wrapper}}",
+ "os_compute_api:os-security-group-default-rules": "{{wrapper}}",
+ "os_compute_api:os-security-groups": "{{wrapper}}",
+ "os_compute_api:os-security-groups:discoverable": "{{wrapper}}",
+ "os_compute_api:os-server-diagnostics": "{{wrapper}}",
+ "os_compute_api:os-server-diagnostics:discoverable": "{{wrapper}}",
+ "os_compute_api:os-server-password": "{{wrapper}}",
+ "os_compute_api:os-server-password:discoverable": "{{wrapper}}",
+ "os_compute_api:os-server-usage": "{{wrapper}}",
+ "os_compute_api:os-server-usage:discoverable": "{{wrapper}}",
+ "os_compute_api:os-server-groups": "{{wrapper}}",
+ "os_compute_api:os-server-groups:discoverable": "{{wrapper}}",
+ "os_compute_api:os-services": "{{wrapper}}",
+ "os_compute_api:os-services:discoverable": "{{wrapper}}",
+ "os_compute_api:server-metadata:discoverable": "{{wrapper}}",
+ "os_compute_api:server-metadata:index": "{{wrapper}}",
+ "os_compute_api:server-metadata:show": "{{wrapper}}",
+ "os_compute_api:server-metadata:delete": "{{wrapper}}",
+ "os_compute_api:server-metadata:create": "{{wrapper}}",
+ "os_compute_api:server-metadata:update": "{{wrapper}}",
+ "os_compute_api:server-metadata:update_all": "{{wrapper}}",
+ "os_compute_api:servers:discoverable": "{{wrapper}}",
+ "os_compute_api:os-shelve:shelve": "{{wrapper}}",
+ "os_compute_api:os-shelve:shelve:discoverable": "{{wrapper}}",
+ "os_compute_api:os-shelve:shelve_offload": "{{wrapper}}",
+ "os_compute_api:os-simple-tenant-usage:discoverable": "{{wrapper}}",
+ "os_compute_api:os-simple-tenant-usage:show": "{{wrapper}}",
+ "os_compute_api:os-simple-tenant-usage:list": "{{wrapper}}",
+ "os_compute_api:os-suspend-server:discoverable": "{{wrapper}}",
+ "os_compute_api:os-suspend-server:suspend": "{{wrapper}}",
+ "os_compute_api:os-suspend-server:resume": "{{wrapper}}",
+ "os_compute_api:os-tenant-networks": "{{wrapper}}",
+ "os_compute_api:os-tenant-networks:discoverable": "{{wrapper}}",
+ "os_compute_api:os-shelve:unshelve": "{{wrapper}}",
+ "os_compute_api:os-user-data:discoverable": "{{wrapper}}",
+ "os_compute_api:os-virtual-interfaces": "{{wrapper}}",
+ "os_compute_api:os-virtual-interfaces:discoverable": "{{wrapper}}",
+ "os_compute_api:os-volumes": "{{wrapper}}",
+ "os_compute_api:os-volumes:discoverable": "{{wrapper}}",
+ "os_compute_api:os-volumes-attachments:index": "{{wrapper}}",
+ "os_compute_api:os-volumes-attachments:show": "{{wrapper}}",
+ "os_compute_api:os-volumes-attachments:create": "{{wrapper}}",
+ "os_compute_api:os-volumes-attachments:update": "{{wrapper}}",
+ "os_compute_api:os-volumes-attachments:delete": "{{wrapper}}",
+ "os_compute_api:os-volumes-attachments:discoverable": "{{wrapper}}",
+ "os_compute_api:os-availability-zone:list": "{{wrapper}}",
+ "os_compute_api:os-availability-zone:discoverable": "{{wrapper}}",
+ "os_compute_api:os-availability-zone:detail": "{{wrapper}}",
+ "os_compute_api:os-used-limits": "{{wrapper}}",
+ "os_compute_api:os-used-limits:discoverable": "{{wrapper}}",
+ "os_compute_api:os-migrations:index": "{{wrapper}}",
+ "os_compute_api:os-migrations:discoverable": "{{wrapper}}",
+ "os_compute_api:os-assisted-volume-snapshots:create": "{{wrapper}}",
+ "os_compute_api:os-assisted-volume-snapshots:delete": "{{wrapper}}",
+ "os_compute_api:os-assisted-volume-snapshots:discoverable": "{{wrapper}}",
+ "os_compute_api:os-console-auth-tokens": "{{wrapper}}",
+ "os_compute_api:os-server-external-events:create": "{{wrapper}}",
+}
diff --git a/old/external_policy_checker/external_policy_checker/__init__.py b/old/external_policy_checker/external_policy_checker/__init__.py
new file mode 100644
index 00000000..a4e2017f
--- /dev/null
+++ b/old/external_policy_checker/external_policy_checker/__init__.py
@@ -0,0 +1 @@
+__version__ = "0.1"
diff --git a/old/external_policy_checker/external_policy_checker/__main__.py b/old/external_policy_checker/external_policy_checker/__main__.py
new file mode 100644
index 00000000..4499a96b
--- /dev/null
+++ b/old/external_policy_checker/external_policy_checker/__main__.py
@@ -0,0 +1,9 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+import moon_bouchon.server
+
+moon_bouchon.server.main()
diff --git a/old/external_policy_checker/external_policy_checker/conf_installer.py b/old/external_policy_checker/external_policy_checker/conf_installer.py
new file mode 100644
index 00000000..ec45003b
--- /dev/null
+++ b/old/external_policy_checker/external_policy_checker/conf_installer.py
@@ -0,0 +1,83 @@
+import shutil
+import logging
+import argparse
+import os
+from uuid import uuid4
+import glob
+
+logger = logging.getLogger(__name__)
+
+COMPONENTS = (
+ "cinder",
+ "nova",
+ "neutron",
+ "glance",
+ "keystone"
+)
+
+
+def init():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--verbose", '-v', action='store_true', help='verbose mode')
+ parser.add_argument("--debug", '-d', action='store_true', help='debug mode')
+ parser.add_argument("--templates", '-t', help='set template directory', default="templates/")
+ parser.add_argument("--out-dir", '-o', help='if set, copy the files in this directory', default=None)
+ parser.add_argument("wrapper_url", help='Wrapper URL to use', nargs="*",
+ default=["http://127.0.0.1:8080/policy_checker"])
+ args = parser.parse_args()
+ logging_format = "%(levelname)s: %(message)s"
+ if args.verbose:
+ logging.basicConfig(level=logging.INFO, format=logging_format)
+ if args.debug:
+ logging.basicConfig(level=logging.DEBUG, format=logging_format)
+ return args
+
+
+def update_templates(templates_dir, wrapper_url):
+ tmp_dir = os.path.join("/tmp", str(uuid4()))
+ wrapper_url = wrapper_url[0].strip('"').strip("'")
+ os.mkdir(tmp_dir)
+ for comp in COMPONENTS:
+ input_file = os.path.join(templates_dir, comp + ".policy.json")
+ output_file = os.path.join(tmp_dir, comp + ".policy.json")
+ output_fd = open(output_file, "w")
+ for line in open(input_file):
+ output_fd.write(line.replace("{{wrapper}}", wrapper_url))
+ return tmp_dir
+
+
+def remove_tmp_files(tmp_dir):
+ for _filename in glob.glob(os.path.join(tmp_dir, "*")):
+ logger.debug("{} {}".format(_filename, os.path.isfile(_filename)))
+ if os.path.isfile(_filename):
+ logger.debug("Trying to delete {}".format(_filename))
+ os.remove(_filename)
+ logger.debug("Delete done")
+ os.removedirs(tmp_dir)
+
+
+def main(templates_dir, wrapper_url, out_dir=None):
+ logger.info("Moving configuration files")
+ tmp_dir = update_templates(templates_dir, wrapper_url)
+ if out_dir:
+ logger.info("Moving to {}".format(out_dir))
+ try:
+ os.mkdir(out_dir)
+ except FileExistsError:
+ logger.warning("Output directory exists, writing on it!")
+ for comp in COMPONENTS:
+ logger.info("Moving {}".format(comp))
+ shutil.copy(os.path.join(tmp_dir, comp + ".policy.json"),
+ os.path.join(out_dir, comp + ".policy.json"))
+ else:
+ logger.info("Moving to /etc")
+ for comp in COMPONENTS:
+ logger.info("Moving {}".format(comp))
+ shutil.copy(os.path.join(tmp_dir, comp + ".policy.json"),
+ os.path.join("etc", comp, "policy.json"))
+ remove_tmp_files(tmp_dir)
+
+
+if __name__ == "__main__":
+ args = init()
+ main(args.templates, args.wrapper_url, args.out_dir)
diff --git a/old/external_policy_checker/external_policy_checker/server.py b/old/external_policy_checker/external_policy_checker/server.py
new file mode 100644
index 00000000..cbb4a933
--- /dev/null
+++ b/old/external_policy_checker/external_policy_checker/server.py
@@ -0,0 +1,135 @@
+# Copyright 2018 Orange
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import sys
+import flask
+from flask import Flask
+from flask import request
+import json
+import logging
+import random
+
+logger = logging.getLogger(__name__)
+logging.basicConfig(level=logging.INFO)
+app = Flask(__name__)
+
+
+def test_target(data, result):
+ if "resource_id" in data:
+ result["resource_id"] = data['object_id']
+ if "object_id" in data:
+ result["resource_id"] = data['object_id']
+ if 'project_id' in data:
+ result["project_id"] = data['project_id']
+ if 'user_id' in data:
+ result["user_id"] = data['user_id']
+
+
+def test_credentials(data, result):
+ if 'project_id' in data:
+ result["project_id"] = data['project_id']
+ if 'user_id' in data:
+ result["user_id"] = data['user_id']
+ if 'project_domain_id' in data:
+ result["domain_id"] = data['project_domain_id']
+
+
+def test_rule(data, result):
+ result['action_name'] = data
+
+
+def test_data():
+ data = request.form
+ result = {
+ "user_id": "",
+ "project_id": "",
+ "action_name": "",
+ "resource_id": "",
+ "domain_id": "",
+ }
+ if not dict(request.form):
+ data = json.loads(request.data.decode("utf-8"))
+ try:
+ target = json.loads(data.get('target', {}))
+ except Exception:
+ raise Exception("Error reading target")
+ try:
+ credentials = json.loads(data.get('credentials', {}))
+ except Exception:
+ raise Exception("Error reading credentials")
+ try:
+ rule = data.get('rule', "")
+ except Exception:
+ raise Exception("Error reading rule")
+ test_target(target, result)
+ test_credentials(credentials, result)
+ test_rule(rule, result)
+ return_value = True
+ logger.info("Analysing request with {}".format(rule))
+ for key in result:
+ if not result[key] and key != "domain_id":
+ return_value = False
+ logger.error("Attribute {} is absent".format(key))
+ if not result[key] and key == "domain_id":
+ logger.warning("Attribute {} is missing.".format(key))
+ return return_value
+
+
+@app.route("/policy_checker", methods=["POST"])
+def checker():
+ information_is_complete = False
+ try:
+ information_is_complete = test_data()
+ except Exception as e:
+ logger.exception(e)
+ if information_is_complete:
+ response = flask.make_response("True")
+ response.headers['content-type'] = 'application/octet-stream'
+ return response
+ else:
+ response = flask.make_response("False")
+ response.headers['content-type'] = 'application/octet-stream'
+ return response, 403
+
+
+def get_target():
+ data = request.form
+ if not dict(request.form):
+ data = json.loads(request.data.decode("utf-8"))
+ try:
+ return json.loads(data.get('target', {}))
+ except Exception:
+ raise Exception("Error reading target")
+
+
+@app.route("/authz/grant", methods=["POST"])
+def wrapper_grant():
+ logger.info("Requesting wrapper authz with {}".format(get_target()))
+ response = flask.make_response("True")
+ response.headers['content-type'] = 'application/octet-stream'
+ return response
+
+
+@app.route("/authz/deny", methods=["POST"])
+def wrapper_deny():
+ logger.info("Requesting wrapper authz with {}".format(get_target()))
+ response = flask.make_response("False")
+ response.headers['content-type'] = 'application/octet-stream'
+ return response, 403
+
+
+def main():
+ port = 8080
+ if len(sys.argv) > 1:
+ try:
+ port = int(sys.argv[1])
+ except ValueError:
+ logger.error("Argument for Port in command line is not an integer")
+ sys.exit(1)
+ app.run(host="0.0.0.0", port=port)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/old/external_policy_checker/requirements.txt b/old/external_policy_checker/requirements.txt
new file mode 100644
index 00000000..8ab6294c
--- /dev/null
+++ b/old/external_policy_checker/requirements.txt
@@ -0,0 +1 @@
+flask \ No newline at end of file
diff --git a/old/external_policy_checker/setup.cfg b/old/external_policy_checker/setup.cfg
new file mode 100644
index 00000000..7c2b2874
--- /dev/null
+++ b/old/external_policy_checker/setup.cfg
@@ -0,0 +1,2 @@
+[bdist_wheel]
+universal = 1 \ No newline at end of file
diff --git a/old/external_policy_checker/setup.py b/old/external_policy_checker/setup.py
new file mode 100644
index 00000000..acd994a6
--- /dev/null
+++ b/old/external_policy_checker/setup.py
@@ -0,0 +1,47 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from setuptools import setup, find_packages
+import external_policy_checker
+
+
+setup(
+
+ name='external_policy_checker',
+
+ version=external_policy_checker.__version__,
+
+ packages=find_packages(),
+
+ author="Thomas Duval",
+
+ author_email="thomas.duval@orange.com",
+
+ description="",
+
+ long_description=open('README.md').read(),
+
+ install_requires=["flask"],
+
+ include_package_data=True,
+
+ url='https://git.opnfv.org/cgit/moon',
+
+ classifiers=[
+ "Programming Language :: Python",
+ "Development Status :: 1 - Planning",
+ "License :: OSI Approved",
+ "Natural Language :: French",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python :: 3",
+ ],
+
+ entry_points={
+ 'console_scripts': [
+ 'external_policy_checker = external_policy_checker.server:main',
+ ],
+ }
+
+)
diff --git a/old/moon_authz/Changelog b/old/moon_authz/Changelog
new file mode 100644
index 00000000..ae1ec4d1
--- /dev/null
+++ b/old/moon_authz/Changelog
@@ -0,0 +1,39 @@
+# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+CHANGES
+=======
+
+1.0.0
+-----
+- First version of the manager
+
+2.0.0
+-----
+- Version built inside the Keystone component
+
+3.0.0
+-----
+- Version built outside the Keystone component
+
+4.0.0
+-----
+- First micro-architecture version
+
+4.3.3
+-----
+- use the threading capability of Flask app
+- set the number of manager to 1
+- update to the latest version of the python-moondb library
+
+4.3.4
+-----
+- apply PyLint rules
+- fix a bug in instructions management
+
+4.4.0
+-----
+- add the update API
diff --git a/old/moon_authz/Dockerfile b/old/moon_authz/Dockerfile
new file mode 100644
index 00000000..7081e31c
--- /dev/null
+++ b/old/moon_authz/Dockerfile
@@ -0,0 +1,15 @@
+FROM python:3
+
+LABEL Name=Authz_plugin
+LABEL Description="Authz plugin for the Moon platform"
+LABEL Maintainer="Thomas Duval"
+LABEL Url="https://wiki.opnfv.org/display/moon/Moon+Project+Proposal"
+
+USER root
+
+ADD . /root
+WORKDIR /root/
+RUN pip3 install --no-cache-dir -r requirements.txt
+RUN pip3 install --no-cache-dir .
+
+CMD ["python3", "-m", "moon_authz"] \ No newline at end of file
diff --git a/old/moon_authz/LICENSE b/old/moon_authz/LICENSE
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/old/moon_authz/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/old/moon_authz/MANIFEST.in b/old/moon_authz/MANIFEST.in
new file mode 100644
index 00000000..1f674d50
--- /dev/null
+++ b/old/moon_authz/MANIFEST.in
@@ -0,0 +1,9 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+include README.rst
+include LICENSE
+include setup.py
+include requirements.txt
diff --git a/old/moon_authz/README.md b/old/moon_authz/README.md
new file mode 100644
index 00000000..696c29a1
--- /dev/null
+++ b/old/moon_authz/README.md
@@ -0,0 +1,8 @@
+# moon_authz
+
+This package contains the core module for the Moon project
+It is designed to provide authorization features to all OpenStack components.
+
+For any other information, refer to the parent project:
+
+ https://git.opnfv.org/moon
diff --git a/old/moon_authz/moon_authz/__init__.py b/old/moon_authz/moon_authz/__init__.py
new file mode 100644
index 00000000..85c245e0
--- /dev/null
+++ b/old/moon_authz/moon_authz/__init__.py
@@ -0,0 +1,6 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+__version__ = "4.4.0"
diff --git a/old/moon_authz/moon_authz/__main__.py b/old/moon_authz/moon_authz/__main__.py
new file mode 100644
index 00000000..6f1f9807
--- /dev/null
+++ b/old/moon_authz/moon_authz/__main__.py
@@ -0,0 +1,4 @@
+from moon_authz.server import create_server
+
+SERVER = create_server()
+SERVER.run()
diff --git a/old/moon_authz/moon_authz/api/__init__.py b/old/moon_authz/moon_authz/api/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/moon_authz/moon_authz/api/__init__.py
diff --git a/old/moon_authz/moon_authz/api/authorization.py b/old/moon_authz/moon_authz/api/authorization.py
new file mode 100644
index 00000000..59af295d
--- /dev/null
+++ b/old/moon_authz/moon_authz/api/authorization.py
@@ -0,0 +1,397 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import itertools
+import pickle
+import logging
+import flask
+from flask import request
+from flask_restful import Resource
+from python_moonutilities import exceptions
+
+LOGGER = logging.getLogger("moon.authz.api." + __name__)
+
+
+class Authz(Resource):
+ """
+ Endpoint for authz requests
+ """
+ __version__ = "4.3.1"
+
+ __urls__ = (
+ "/authz",
+ "/authz/",
+ )
+
+ pdp_id = None
+ meta_rule_id = None
+ keystone_project_id = None
+ payload = None
+
+ def __init__(self, **kwargs):
+ component_data = kwargs.get("component_data", {})
+ self.component_id = component_data['component_id']
+ self.pdp_id = component_data['pdp_id']
+ self.meta_rule_id = component_data['meta_rule_id']
+ self.keystone_project_id = component_data['keystone_project_id']
+ self.cache = kwargs.get("cache")
+ self.context = None
+
+ def post(self):
+ """Get a response on an authorization request
+
+ :request:
+
+ :return: {
+ "args": {},
+ "ctx": {
+ "action_name": "4567",
+ "id": "123456",
+ "method": "authz",
+ "object_name": "234567",
+ "subject_name": "123456",
+ "user_id": "admin"
+ },
+ "error": {
+ "code": 500,
+ "description": "",
+ "title": "Moon Error"
+ },
+ "intra_extension_id": "123456",
+ "result": false
+ }
+ :internal_api: authz
+ """
+ self.context = pickle.loads(request.data)
+ self.context.set_cache(self.cache)
+ self.context.increment_index()
+ self.context.update_target()
+ # FIXME (asteroide): force the update but we should not do that
+ # a better way is to build the bilateral link between Master and Slaves
+ self.cache.update()
+ if not self.run():
+ raise exceptions.MoonError("Error in the request status={}".format(
+ self.context.current_state))
+ self.context.delete_cache()
+ response = flask.make_response(pickle.dumps(self.context))
+ response.headers['content-type'] = 'application/octet-stream'
+ return response
+
+ def run(self):
+ result, message = self.__check_rules()
+ if result:
+ return self.__exec_instructions(result)
+ self.context.current_state = "deny"
+ # self.__exec_next_state(result)
+ return
+
+ def __check_rules(self):
+ scopes_list = list()
+ current_header_id = self.context.headers[self.context.index]
+ # Context.update_target(context)
+ if not self.context.pdp_set:
+ raise exceptions.PdpUnknown
+ if current_header_id not in self.context.pdp_set:
+ raise Exception('Invalid index')
+ current_pdp = self.context.pdp_set[current_header_id]
+ category_list = list()
+ if 'meta_rules' not in current_pdp:
+ raise exceptions.PdpContentError
+ try:
+ category_list.extend(current_pdp["meta_rules"]["subject_categories"])
+ category_list.extend(current_pdp["meta_rules"]["object_categories"])
+ category_list.extend(current_pdp["meta_rules"]["action_categories"])
+ except Exception:
+ raise exceptions.MetaRuleContentError
+ if 'target' not in current_pdp:
+ raise exceptions.PdpContentError
+ for category in category_list:
+ scope = list(current_pdp['target'][category])
+ if not scope:
+ LOGGER.warning("Scope in category {} is empty".format(category))
+ raise exceptions.AuthzException
+ scopes_list.append(scope)
+ # policy_id = self.cache.get_policy_from_meta_rules("admin", current_header_id)
+ if self.context.current_policy_id not in self.cache.rules:
+ raise exceptions.PolicyUnknown
+ if 'rules' not in self.cache.rules[self.context.current_policy_id]:
+ raise exceptions.RuleUnknown
+ for item in itertools.product(*scopes_list):
+ req = list(item)
+ for rule in self.cache.rules[self.context.current_policy_id]["rules"]:
+ if req == rule['rule']:
+ return rule['instructions'], ""
+ LOGGER.warning("No rule match the request...")
+ return False, "No rule match the request..."
+
+ def __update_subject_category_in_policy(self, operation, target):
+ result = False
+ # try:
+ # policy_name, category_name, data_name = target.split(":")
+ # except ValueError:
+ # LOGGER.error("Cannot understand value in instruction ({})".format(target))
+ # return False
+ # # pdp_set = self.payload["authz_context"]['pdp_set']
+ # for meta_rule_id in self.context.pdp_set:
+ # if meta_rule_id == "effect":
+ # continue
+ # if self.context.pdp_set[meta_rule_id]["meta_rules"]["name"] == policy_name:
+ # for category_id, category_value in self.cache.subject_categories.items():
+ # if category_value["name"] == "role":
+ # subject_category_id = category_id
+ # break
+ # else:
+ # LOGGER.error("Cannot understand category in instruction ({})".format(target))
+ # return False
+ # subject_data_id = None
+ # for data in PolicyManager.get_subject_data("admin", policy_id,
+ # category_id=subject_category_id):
+ # for data_id, data_value in data['data'].items():
+ # if data_value["name"] == data_name:
+ # subject_data_id = data_id
+ # break
+ # if subject_data_id:
+ # break
+ # else:
+ # LOGGER.error("Cannot understand data in instruction ({})".format(target))
+ # return False
+ # if operation == "add":
+ # self.payload["authz_context"]['pdp_set'][meta_rule_id]['target'][
+ # subject_category_id].append(subject_data_id)
+ # elif operation == "delete":
+ # try:
+ # self.payload["authz_context"]['pdp_set'][meta_rule_id]['target'][
+ # subject_category_id].remove(subject_data_id)
+ # except ValueError:
+ # LOGGER.warning("Cannot remove role {} from target".format(data_name))
+ # result = True
+ # break
+ return result
+
+ def __update_container_chaining(self):
+ for index in range(len(self.payload["authz_context"]['headers'])):
+ self.payload["container_chaining"][index]["meta_rule_id"] = \
+ self.payload["authz_context"]['headers'][index]
+
+ def __get_container_from_meta_rule(self, meta_rule_id):
+ for index in range(len(self.payload["authz_context"]['headers'])):
+ if self.payload["container_chaining"][index]["meta_rule_id"] == meta_rule_id:
+ return self.payload["container_chaining"][index]
+
+ def __update_headers(self, name):
+ # context = self.payload["authz_context"]
+ for meta_rule_id, meta_rule_value in self.context.pdp_set.items():
+ if meta_rule_id == "effect":
+ continue
+ if meta_rule_value["meta_rules"]["name"] == name:
+ self.context.headers.append(meta_rule_id)
+ return True
+ return False
+
+ # def __exec_next_state(self, rule_found):
+ # index = self.context.index
+ # current_meta_rule = self.context.headers[index]
+ # current_container = self.__get_container_from_meta_rule(current_meta_rule)
+ # current_container_genre = current_container["genre"]
+ # try:
+ # next_meta_rule = self.context.headers[index + 1]
+ # except IndexError:
+ # next_meta_rule = None
+ # if current_container_genre == "authz":
+ # if rule_found:
+ # return True
+ # pass
+ # if next_meta_rule:
+ # # next will be session if current is deny and session is unset
+ # if self.payload["authz_context"]['pdp_set'][next_meta_rule]['effect'] == "unset":
+ # return notify(
+ # request_id=self.payload["authz_context"]["request_id"],
+ # container_id=self.__get_container_from_meta_rule(next_meta_rule)[
+ # 'container_id'],payload=self.payload)
+ # # next will be delegation if current is deny and session is passed or deny and
+ # delegation is unset
+ # else:
+ # LOG.error("Delegation is not developed!")
+ #
+ # else:
+ # # else next will be None and the request is sent to router
+ # return self.__return_to_router()
+ # elif current_container_genre == "session":
+ # pass
+ # # next will be next container in headers if current is passed
+ # if self.payload["authz_context"]['pdp_set'][current_meta_rule]['effect'] == "passed":
+ # return notify(
+ # request_id=self.payload["authz_context"]["request_id"],
+ # container_id=self.__get_container_from_meta_rule(next_meta_rule)[
+ # 'container_id'],payload=self.payload)
+ # # next will be None if current is grant and the request is sent to router
+ # else:
+ # return self.__return_to_router()
+ # elif current_container_genre == "delegation":
+ # LOG.error("Delegation is not developed!")
+ # # next will be authz if current is deny
+ # # next will be None if current is grant and the request is sent to router
+
+ # def __return_to_router(self):
+ # call(endpoint="security_router",
+ # ctx={"id": self.component_id,
+ # "call_master": False,
+ # "method": "return_authz",
+ # "request_id": self.payload["authz_context"]["request_id"]},
+ # method="route",
+ # args=self.payload["authz_context"])
+
+ def __exec_instructions(self, instructions):
+ if type(instructions) is dict:
+ instructions = [instructions, ]
+ if type(instructions) not in (list, tuple):
+ raise exceptions.RuleContentError("Bad instructions format")
+ for instruction in instructions:
+ for key in instruction:
+ if key == "decision":
+ if instruction["decision"] == "grant":
+ self.context.current_state = "grant"
+ LOGGER.info("__exec_instructions True %s" % self.context.current_state)
+ return True
+
+ self.context.current_state = instruction["decision"].lower()
+ elif key == "chain":
+ result = self.__update_headers(**instruction["chain"])
+ if not result:
+ self.context.current_state = "deny"
+ else:
+ self.context.current_state = "passed"
+ elif key == "update":
+ result = self.__update_subject_category_in_policy(**instruction["update"])
+ if not result:
+ self.context.current_state = "deny"
+ else:
+ self.context.current_state = "passed"
+ LOGGER.info("__exec_instructions False %s" % self.context.current_state)
+
+ # def __update_current_request(self):
+ # index = self.payload["authz_context"]["index"]
+ # current_header_id = self.payload["authz_context"]['headers'][index]
+ # previous_header_id = self.payload["authz_context"]['headers'][index - 1]
+ # current_policy_id = PolicyManager.get_policy_from_meta_rules("admin", current_header_id)
+ # previous_policy_id = PolicyManager.get_policy_from_meta_rules("admin", previous_header_id)
+ # # FIXME (asteroide): must change those lines to be ubiquitous against any type of policy
+ # if self.payload["authz_context"]['pdp_set'][current_header_id]['meta_rules'][
+ # 'name'] == "session":
+ # subject = self.payload["authz_context"]['current_request'].get("subject")
+ # subject_category_id = None
+ # role_names = []
+ # for category_id, category_value in ModelManager.get_subject_categories("admin").items():
+ # if category_value["name"] == "role":
+ # subject_category_id = category_id
+ # break
+ # for assignment_id, assignment_value in PolicyManager.get_subject_assignments(
+ # "admin", previous_policy_id, subject, subject_category_id).items():
+ # for data_id in assignment_value["assignments"]:
+ # data = PolicyManager.get_subject_data(
+ # "admin", previous_policy_id, data_id, subject_category_id)
+ # for _data in data:
+ # for key, value in _data["data"].items():
+ # role_names.append(value["name"])
+ # new_role_ids = []
+ # for perimeter_id, perimeter_value in PolicyManager.get_objects(
+ # "admin", current_policy_id).items():
+ # if perimeter_value["name"] in role_names:
+ # new_role_ids.append(perimeter_id)
+ # break
+ # perimeter_id = None
+ # for perimeter_id, perimeter_value in PolicyManager.get_actions(
+ # "admin", current_policy_id).items():
+ # if perimeter_value["name"] == "*":
+ # break
+ #
+ # self.payload["authz_context"]['current_request']['object'] = new_role_ids[0]
+ # self.payload["authz_context"]['current_request']['action'] = perimeter_id
+ # elif self.payload["authz_context"]['pdp_set'][current_header_id]['meta_rules']['name'] == "rbac":
+ # self.payload["authz_context"]['current_request']['subject'] = \
+ # self.payload["authz_context"]['initial_request']['subject']
+ # self.payload["authz_context"]['current_request']['object'] = \
+ # self.payload["authz_context"]['initial_request']['object']
+ # self.payload["authz_context"]['current_request']['action'] = \
+ # self.payload["authz_context"]['initial_request']['action']
+
+ def get_authz(self):
+ # self.keystone_project_id = payload["id"]
+ # LOG.info("get_authz {}".format(payload))
+ # self.payload = payload
+ try:
+ # if "authz_context" not in payload:
+ # try:
+ # self.payload["authz_context"] = Context(self.keystone_project_id,
+ # self.payload["subject_name"],
+ # self.payload["object_name"],
+ # self.payload["action_name"],
+ # self.payload["request_id"]).to_dict()
+ # except exceptions.SubjectUnknown:
+ # ctx = {
+ # "subject_name": self.payload["subject_name"],
+ # "object_name": self.payload["object_name"],
+ # "action_name": self.payload["action_name"],
+ # }
+ # call("moon_manager", method="update_from_master", ctx=ctx, args={})
+ # self.payload["authz_context"] = Context(self.keystone_project_id,
+ # self.payload["subject_name"],
+ # self.payload["object_name"],
+ # self.payload["action_name"],
+ # self.payload["request_id"]).to_dict()
+ # except exceptions.ObjectUnknown:
+ # ctx = {
+ # "subject_name": self.payload["subject_name"],
+ # "object_name": self.payload["object_name"],
+ # "action_name": self.payload["action_name"],
+ # }
+ # call("moon_manager", method="update_from_master", ctx=ctx, args={})
+ # self.payload["authz_context"] = Context(self.keystone_project_id,
+ # self.payload["subject_name"],
+ # self.payload["object_name"],
+ # self.payload["action_name"],
+ # self.payload["request_id"]).to_dict()
+ # except exceptions.ActionUnknown:
+ # ctx = {
+ # "subject_name": self.payload["subject_name"],
+ # "object_name": self.payload["object_name"],
+ # "action_name": self.payload["action_name"],
+ # }
+ # call("moon_manager", method="update_from_master", ctx=ctx, args={})
+ # self.payload["authz_context"] = Context(self.keystone_project_id,
+ # self.payload["subject_name"],
+ # self.payload["object_name"],
+ # self.payload["action_name"],
+ # self.payload["request_id"]).to_dict()
+ # self.__update_container_chaining()
+ # else:
+ # self.payload["authz_context"]["index"] += 1
+ # self.__update_current_request()
+ result, message = self.__check_rules()
+ current_header_id = self.payload["authz_context"]['headers'][
+ self.payload["authz_context"]['index']]
+ if result:
+ self.__exec_instructions(result)
+ else:
+ self.payload["authz_context"]['pdp_set'][current_header_id]["effect"] = "deny"
+ self.__exec_next_state(result)
+ return {"authz": result,
+ "error": message,
+ "pdp_id": self.pdp_id,
+ "args": self.payload}
+ except Exception as e:
+ try:
+ LOGGER.error(self.payload["authz_context"])
+ except KeyError:
+ LOGGER.error("Cannot find \"authz_context\" in context")
+ LOGGER.error(e, exc_info=True)
+ return {"authz": False,
+ "error": str(e),
+ "pdp_id": self.pdp_id,
+ "args": self.payload}
+
+ def head(self, uuid=None, subject_name=None, object_name=None, action_name=None):
+ LOGGER.info("HEAD request")
+ return "", 200
diff --git a/old/moon_authz/moon_authz/api/update.py b/old/moon_authz/moon_authz/api/update.py
new file mode 100644
index 00000000..68b7f0ce
--- /dev/null
+++ b/old/moon_authz/moon_authz/api/update.py
@@ -0,0 +1,42 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Authz is the endpoint to get authorization response
+"""
+
+from flask import request
+from flask_restful import Resource
+import logging
+
+__version__ = "4.4.0"
+
+LOGGER = logging.getLogger("moon.authz.api." + __name__)
+
+
+class Update(Resource):
+ """
+ Endpoint for update requests
+ """
+
+ __urls__ = (
+ "/update",
+ )
+
+ def __init__(self, **kwargs):
+ self.CACHE = kwargs.get("cache")
+ self.INTERFACE_NAME = kwargs.get("interface_name", "interface")
+ self.MANAGER_URL = kwargs.get("manager_url", "http://manager:8080")
+ self.TIMEOUT = 5
+
+ def put(self):
+ try:
+ self.CACHE.update_assignments(
+ request.form.get("policy_id", None),
+ request.form.get("perimeter_id", None),
+ )
+ except Exception as e:
+ LOGGER.exception(e)
+ return {"result": False, "reason": str(e)}
+ return {"result": True}
diff --git a/old/moon_authz/moon_authz/http_server.py b/old/moon_authz/moon_authz/http_server.py
new file mode 100644
index 00000000..86d8a914
--- /dev/null
+++ b/old/moon_authz/moon_authz/http_server.py
@@ -0,0 +1,142 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import logging
+from flask import Flask
+from flask_restful import Resource, Api
+from moon_authz import __version__
+from moon_authz.api.authorization import Authz
+from moon_authz.api.update import Update
+from python_moonutilities.cache import Cache
+from python_moonutilities import exceptions
+
+LOGGER = logging.getLogger("moon.authz.http_server")
+
+CACHE = Cache()
+CACHE.update()
+
+
+class Server:
+ """Base class for HTTP server"""
+
+ def __init__(self, host="localhost", port=80, api=None, **kwargs):
+ """Run a server
+
+ :param host: hostname of the server
+ :param port: port for the running server
+ :param kwargs: optional parameters
+ :return: a running server
+ """
+ self._host = host
+ self._port = port
+ self._api = api
+ self._extra = kwargs
+
+ @property
+ def host(self):
+ return self._host
+
+ @host.setter
+ def host(self, name):
+ self._host = name
+
+ @host.deleter
+ def host(self):
+ self._host = ""
+
+ @property
+ def port(self):
+ return self._port
+
+ @port.setter
+ def port(self, number):
+ self._port = number
+
+ @port.deleter
+ def port(self):
+ self._port = 80
+
+ def run(self):
+ raise NotImplementedError()
+
+
+__API__ = (
+ Authz, Update
+)
+
+
+class Root(Resource):
+ """
+ The root of the web service
+ """
+ __urls__ = ("/",)
+ __methods = ("get", "post", "put", "delete", "options")
+
+ def get(self):
+ tree = {"/": {"methods": ("get",),
+ "description": "List all methods for that service."}}
+ for item in __API__:
+ tree[item.__name__] = {"urls": item.__urls__}
+ _methods = []
+ for _method in self.__methods:
+ if _method in dir(item):
+ _methods.append(_method)
+ tree[item.__name__]["methods"] = _methods
+ tree[item.__name__]["description"] = item.__doc__.strip()
+ return {
+ "version": __version__,
+ "tree": tree
+ }
+
+ def head(self):
+ return "", 201
+
+
+class HTTPServer(Server):
+ def __init__(self, host="localhost", port=38001, **kwargs):
+ super(HTTPServer, self).__init__(host=host, port=port, **kwargs)
+ self.component_data = kwargs.get("component_data", {})
+ LOGGER.info("HTTPServer port={} {}".format(port, kwargs))
+ self.app = Flask(__name__)
+ self._port = port
+ self._host = host
+ self.component_id = kwargs.get("component_id")
+ self.keystone_project_id = kwargs.get("keystone_project_id")
+ self.container_chaining = kwargs.get("container_chaining")
+ self.api = Api(self.app)
+ self.__set_route()
+
+ # self.__hook_errors()
+
+ @self.app.errorhandler(exceptions.AuthException)
+ def _auth_exception(error):
+ return {"error": "Unauthorized"}, 401
+
+ def __hook_errors(self):
+ # FIXME (dthom): it doesn't work
+ def get_404_json(e):
+ return {"error": "Error", "code": 404, "description": e}
+
+ self.app.register_error_handler(404, get_404_json)
+
+ def get_400_json(e):
+ return {"error": "Error", "code": 400, "description": e}
+
+ self.app.register_error_handler(400, lambda e: get_400_json)
+ self.app.register_error_handler(403, exceptions.AuthException)
+
+ def __set_route(self):
+ self.api.add_resource(Root, '/')
+
+ for api in __API__:
+ self.api.add_resource(api, *api.__urls__,
+ resource_class_kwargs={
+ "component_data": self.component_data,
+ "cache": CACHE
+ }
+ )
+
+ def run(self):
+ self.app.run(host=self._host, port=self._port, threaded=True) # nosec
diff --git a/old/moon_authz/moon_authz/server.py b/old/moon_authz/moon_authz/server.py
new file mode 100644
index 00000000..d1b5a59b
--- /dev/null
+++ b/old/moon_authz/moon_authz/server.py
@@ -0,0 +1,56 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import os
+import logging
+from moon_authz.http_server import HTTPServer as Server
+from python_moonutilities import configuration, exceptions
+
+LOGGER = logging.getLogger("moon.authz.server")
+
+
+def create_server():
+ configuration.init_logging()
+
+ component_id = os.getenv("UUID")
+ component_type = os.getenv("TYPE")
+ tcp_port = os.getenv("PORT")
+ pdp_id = os.getenv("PDP_ID")
+ meta_rule_id = os.getenv("META_RULE_ID")
+ keystone_project_id = os.getenv("KEYSTONE_PROJECT_ID")
+ LOGGER.info("component_type={}".format(component_type))
+ conf = configuration.get_plugins()
+ # conf = configuration.get_configuration("plugins/{}".format(component_type))
+ # conf["plugins/{}".format(component_type)]['id'] = component_id
+ if component_type not in conf:
+ raise exceptions.ConsulComponentNotFound("{} not found".format(
+ component_type))
+ hostname = conf[component_type].get('hostname', component_id)
+ port = conf[component_type].get('port', tcp_port)
+ bind = conf[component_type].get('bind', "0.0.0.0")
+
+ LOGGER.info("Starting server with IP {} on port {} bind to {}".format(
+ hostname, port, bind))
+ server = Server(
+ host=bind,
+ port=int(port),
+ component_data={
+ 'component_id': component_id,
+ 'component_type': component_type,
+ 'pdp_id': pdp_id,
+ 'meta_rule_id': meta_rule_id,
+ 'keystone_project_id': keystone_project_id,
+ }
+ )
+ return server
+
+
+def run():
+ server = create_server()
+ server.run()
+
+
+if __name__ == '__main__':
+ run()
diff --git a/old/moon_authz/requirements.txt b/old/moon_authz/requirements.txt
new file mode 100644
index 00000000..8cad7a7a
--- /dev/null
+++ b/old/moon_authz/requirements.txt
@@ -0,0 +1,5 @@
+flask
+flask_restful
+flask_cors
+python_moondb
+python_moonutilities
diff --git a/old/moon_authz/setup.py b/old/moon_authz/setup.py
new file mode 100644
index 00000000..ad99b9f8
--- /dev/null
+++ b/old/moon_authz/setup.py
@@ -0,0 +1,47 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from setuptools import setup, find_packages
+import moon_authz
+
+
+setup(
+
+ name='moon_authz',
+
+ version=moon_authz.__version__,
+
+ packages=find_packages(),
+
+ author="Thomas Duval",
+
+ author_email="thomas.duval@orange.com",
+
+ description="",
+
+ long_description=open('README.md').read(),
+
+ # install_requires= ,
+
+ include_package_data=True,
+
+ url='https://git.opnfv.org/moon',
+
+ classifiers=[
+ "Programming Language :: Python",
+ "Development Status :: 1 - Planning",
+ "License :: OSI Approved",
+ "Natural Language :: French",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python :: 3",
+ ],
+
+ entry_points={
+ 'console_scripts': [
+ 'moon_authz = moon_authz.server:run',
+ ],
+ }
+
+)
diff --git a/old/moon_authz/tests/unit_python/conftest.py b/old/moon_authz/tests/unit_python/conftest.py
new file mode 100644
index 00000000..a6e62078
--- /dev/null
+++ b/old/moon_authz/tests/unit_python/conftest.py
@@ -0,0 +1,29 @@
+import pytest
+import requests_mock
+import mock_pods
+import os
+from utilities import CONTEXT
+
+
+@pytest.fixture
+def context():
+ return CONTEXT
+
+
+def set_env_variables():
+ os.environ['UUID'] = "1111111111"
+ os.environ['TYPE'] = "authz"
+ os.environ['PORT'] = "8081"
+ os.environ['PDP_ID'] = "b3d3e18abf3340e8b635fd49e6634ccd"
+ os.environ['META_RULE_ID'] = "f8f49a779ceb47b3ac810f01ef71b4e0"
+ os.environ['KEYSTONE_PROJECT_ID'] = CONTEXT['project_id']
+
+
+@pytest.fixture(autouse=True)
+def no_requests(monkeypatch):
+ """ Modify the response from Requests module
+ """
+ set_env_variables()
+ with requests_mock.Mocker(real_http=True) as m:
+ mock_pods.register_pods(m)
+ yield m
diff --git a/old/moon_authz/tests/unit_python/mock_pods.py b/old/moon_authz/tests/unit_python/mock_pods.py
new file mode 100644
index 00000000..39223a57
--- /dev/null
+++ b/old/moon_authz/tests/unit_python/mock_pods.py
@@ -0,0 +1,545 @@
+from utilities import CONF, get_b64_conf, COMPONENTS
+
+pdp_mock = {
+ "b3d3e18abf3340e8b635fd49e6634ccd": {
+ "description": "test",
+ "security_pipeline": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0"
+ ],
+ "name": "pdp_rbac",
+ "keystone_project_id": "a64beb1cc224474fb4badd43173e7101"
+ },
+ "pdp_id1": {
+ "name": "pdp_id1",
+ "security_pipeline": ["policy_id_1", "policy_id_2"],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ },
+ "pdp_id12": {
+ "name": "pdp_id2",
+ "security_pipeline": ["policy_id_1", "policy_id_2"],
+ "keystone_project_id": "keystone_project_id2",
+ "description": "...",
+ }
+}
+
+meta_rules_mock = {
+ "f8f49a779ceb47b3ac810f01ef71b4e0": {
+ "subject_categories": [
+ "14e6ae0ba34d458b876c791b73aa17bd"
+ ],
+ "action_categories": [
+ "241a2a791554421a91c9f1bc564aa94d"
+ ],
+ "description": "",
+ "name": "rbac",
+ "object_categories": [
+ "6d48500f639d4c2cab2b1f33ef93a1e8"
+ ]
+ },
+ "meta_rule_id1": {
+ "name": "meta_rule1",
+ "algorithm": "name of the meta rule algorithm",
+ "subject_categories": ["subject_category_id1",
+ "subject_category_id2"],
+ "object_categories": ["object_category_id1"],
+ "action_categories": ["action_category_id1"]
+ },
+ "meta_rule_id2": {
+ "name": "name of the meta rules2",
+ "algorithm": "name of the meta rule algorithm",
+ "subject_categories": ["subject_category_id1",
+ "subject_category_id2"],
+ "object_categories": ["object_category_id1"],
+ "action_categories": ["action_category_id1"]
+ }
+}
+
+policies_mock = {
+ "f8f49a779ceb47b3ac810f01ef71b4e0": {
+ "name": "RBAC policy example",
+ "model_id": "cd923d8633ff4978ab0e99938f5153d6",
+ "description": "test",
+ "genre": "authz"
+ },
+ "policy_id_1": {
+ "name": "test_policy1",
+ "model_id": "model_id_1",
+ "genre": "authz",
+ "description": "test",
+ },
+ "policy_id_2": {
+ "name": "test_policy2",
+ "model_id": "model_id_2",
+ "genre": "authz",
+ "description": "test",
+ }
+}
+
+subject_mock = {
+ "f8f49a779ceb47b3ac810f01ef71b4e0": {
+ "89ba91c18dd54abfbfde7a66936c51a6": {
+ "description": "test",
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ],
+ "name": "testuser",
+ "email": "mail",
+ "id": "89ba91c18dd54abfbfde7a66936c51a6",
+ "extra": {}
+ }
+ },
+ "policy_id_1": {
+ "subject_id": {
+ "name": "subject_name",
+ "keystone_id": "keystone_project_id1",
+ "description": "a description"
+ }
+ },
+ "policy_id_2": {
+ "subject_id": {
+ "name": "subject_name",
+ "keystone_id": "keystone_project_id2",
+ "description": "a description"
+ }
+ }
+}
+
+subject_assignment_mock = {
+ "826c1156d0284fc9b4b2ddb279f63c52": {
+ "category_id": "14e6ae0ba34d458b876c791b73aa17bd",
+ "assignments": [
+ "24ea95256c5f4c888c1bb30a187788df",
+ "6b227b77184c48b6a5e2f3ed1de0c02a",
+ "31928b17ec90438ba5a2e50ae7650e63",
+ "4e60f554dd3147af87595fb6b37dcb13",
+ "7a5541b63a024fa88170a6b59f99ccd7",
+ "dd2af27812f742029d289df9687d6126"
+ ],
+ "id": "826c1156d0284fc9b4b2ddb279f63c52",
+ "subject_id": "89ba91c18dd54abfbfde7a66936c51a6",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ },
+ "7407ffc1232944279b0cbcb0847c86f7": {
+ "category_id": "315072d40d774c43a89ff33937ed24eb",
+ "assignments": [
+ "6b227b77184c48b6a5e2f3ed1de0c02a",
+ "31928b17ec90438ba5a2e50ae7650e63",
+ "7a5541b63a024fa88170a6b59f99ccd7",
+ "dd2af27812f742029d289df9687d6126"
+ ],
+ "id": "7407ffc1232944279b0cbcb0847c86f7",
+ "subject_id": "89ba91c18dd54abfbfde7a66936c51a6",
+ "policy_id": "3e65256389b448cb9897917ea235f0bb"
+ }
+}
+
+object_mock = {
+ "f8f49a779ceb47b3ac810f01ef71b4e0": {
+ "9089b3d2ce5b4e929ffc7e35b55eba1a": {
+ "name": "vm1",
+ "description": "test",
+ "id": "9089b3d2ce5b4e929ffc7e35b55eba1a",
+ "extra": {},
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ]
+ },
+ },
+ "policy_id_1": {
+ "object_id": {
+ "name": "object_name",
+ "description": "a description"
+ }
+ },
+ "policy_id_2": {
+ "object_id": {
+ "name": "object_name",
+ "description": "a description"
+ }
+ }
+}
+
+object_assignment_mock = {
+ "201ad05fd3f940948b769ab9214fe295": {
+ "object_id": "9089b3d2ce5b4e929ffc7e35b55eba1a",
+ "assignments": [
+ "030fbb34002e4236a7b74eeb5fd71e35",
+ "06bcb8655b9d46a9b90e67ef7c825b50",
+ "34eb45d7f46d4fb6bc4965349b8e4b83",
+ "4b7793dbae434c31a77da9d92de9fa8c"
+ ],
+ "id": "201ad05fd3f940948b769ab9214fe295",
+ "category_id": "6d48500f639d4c2cab2b1f33ef93a1e8",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ },
+ "90c5e86f8be34c0298fbd1973e4fb043": {
+ "object_id": "67b8008a3f8d4f8e847eb628f0f7ca0e",
+ "assignments": [
+ "a098918e915b4b12bccb89f9a3f3b4e4",
+ "06bcb8655b9d46a9b90e67ef7c825b50",
+ "7dc76c6142af47c88b60cc2b0df650ba",
+ "4b7793dbae434c31a77da9d92de9fa8c"
+ ],
+ "id": "90c5e86f8be34c0298fbd1973e4fb043",
+ "category_id": "33aece52d45b4474a20dc48a76800daf",
+ "policy_id": "3e65256389b448cb9897917ea235f0bb"
+ }
+}
+
+action_mock = {
+ "f8f49a779ceb47b3ac810f01ef71b4e0": {
+ "cdb3df220dc05a6ea3334b994827b068": {
+ "name": "boot",
+ "description": "test",
+ "id": "cdb3df220dc04a6ea3334b994827b068",
+ "extra": {},
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ]
+ },
+ "cdb3df220dc04a6ea3334b994827b068": {
+ "name": "stop",
+ "description": "test",
+ "id": "cdb3df220dc04a6ea3334b994827b068",
+ "extra": {},
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ]
+ },
+ "9f5112afe9b34a6c894eb87246ccb7aa": {
+ "name": "start",
+ "description": "test",
+ "id": "9f5112afe9b34a6c894eb87246ccb7aa",
+ "extra": {},
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ]
+ }
+ },
+ "policy_id_1": {
+ "action_id": {
+ "name": "action_name",
+ "description": "a description"
+ }
+ },
+ "policy_id_2": {
+ "action_id": {
+ "name": "action_name",
+ "description": "a description"
+ }
+ }
+}
+
+action_assignment_mock = {
+ "2128e3ffbd1c4ef5be515d625745c2d4": {
+ "category_id": "241a2a791554421a91c9f1bc564aa94d",
+ "action_id": "cdb3df220dc05a6ea3334b994827b068",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "id": "2128e3ffbd1c4ef5be515d625745c2d4",
+ "assignments": [
+ "570c036781e540dc9395b83098c40ba7",
+ "7fe17d7a2e3542719f8349c3f2273182",
+ "015ca6f40338422ba3f692260377d638",
+ "23d44c17bf88480f83e8d57d2aa1ea79"
+ ]
+ },
+ "cffb98852f3a4110af7a0ddfc4e19201": {
+ "category_id": "4a2c5abaeaf644fcaf3ca8df64000d53",
+ "action_id": "cdb3df220dc04a6ea3334b994827b068",
+ "policy_id": "3e65256389b448cb9897917ea235f0bb",
+ "id": "cffb98852f3a4110af7a0ddfc4e19201",
+ "assignments": [
+ "570c036781e540dc9395b83098c40ba7",
+ "7fe17d7a2e3542719f8349c3f2273182",
+ "015ca6f40338422ba3f692260377d638",
+ "23d44c17bf88480f83e8d57d2aa1ea79"
+ ]
+ }
+}
+
+models_mock = {
+ "cd923d8633ff4978ab0e99938f5153d6": {
+ "name": "RBAC",
+ "meta_rules": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0"
+ ],
+ "description": "test"
+ },
+ "model_id_1": {
+ "name": "test_model",
+ "description": "test",
+ "meta_rules": ["meta_rule_id1"]
+ },
+ "model_id_2": {
+ "name": "test_model",
+ "description": "test",
+ "meta_rules": ["meta_rule_id2"]
+ },
+}
+
+rules_mock = {
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "rules": [
+ {
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "rule": [
+ "24ea95256c5f4c888c1bb30a187788df",
+ "030fbb34002e4236a7b74eeb5fd71e35",
+ "570c036781e540dc9395b83098c40ba7"
+ ],
+ "enabled": True,
+ "id": "0201a2bcf56943c1904dbac016289b71",
+ "instructions": [
+ {
+ "decision": "grant"
+ }
+ ],
+ "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ },
+ {
+ "policy_id": "ecc2451c494e47b5bca7250cd324a360",
+ "rule": [
+ "54f574cd2043468da5d65e4f6ed6e3c9",
+ "6559686961a3490a978f246ac9f85fbf",
+ "ac0d1f600bf447e8bd2f37b7cc47f2dc"
+ ],
+ "enabled": True,
+ "id": "a83fed666af8436192dfd8b3c83a6fde",
+ "instructions": [
+ {
+ "decision": "grant"
+ }
+ ],
+ "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ }
+ ]
+}
+
+
+def register_pods(m):
+ """ Modify the response from Requests module
+ """
+ register_consul(m)
+ register_pdp(m)
+ register_meta_rules(m)
+ register_policies(m)
+ register_models(m)
+ register_orchestrator(m)
+ register_policy_subject(m, "f8f49a779ceb47b3ac810f01ef71b4e0")
+ # register_policy_subject(m, "policy_id_2")
+ register_policy_object(m, "f8f49a779ceb47b3ac810f01ef71b4e0")
+ # register_policy_object(m, "policy_id_2")
+ register_policy_action(m, "f8f49a779ceb47b3ac810f01ef71b4e0")
+ # register_policy_action(m, "policy_id_2")
+ register_policy_subject_assignment(m, "f8f49a779ceb47b3ac810f01ef71b4e0", "89ba91c18dd54abfbfde7a66936c51a6")
+ register_policy_subject_assignment_list(m, "f8f49a779ceb47b3ac810f01ef71b4e0")
+ register_policy_subject_assignment(m, "policy_id_2", "subject_id")
+ # register_policy_subject_assignment_list(m1, "policy_id_2")
+ register_policy_object_assignment(m, "f8f49a779ceb47b3ac810f01ef71b4e0", "9089b3d2ce5b4e929ffc7e35b55eba1a")
+ register_policy_object_assignment_list(m, "f8f49a779ceb47b3ac810f01ef71b4e0")
+ register_policy_object_assignment(m, "policy_id_2", "object_id")
+ # register_policy_object_assignment_list(m1, "policy_id_2")
+ register_policy_action_assignment(m, "f8f49a779ceb47b3ac810f01ef71b4e0", "cdb3df220dc05a6ea3334b994827b068")
+ register_policy_action_assignment_list(m, "f8f49a779ceb47b3ac810f01ef71b4e0")
+ register_policy_action_assignment(m, "policy_id_2", "action_id")
+ # register_policy_action_assignment_list(m1, "policy_id_2")
+ register_rules(m, "f8f49a779ceb47b3ac810f01ef71b4e0")
+ register_rules(m, "policy_id_1")
+ register_rules(m, "policy_id_2")
+
+
+def register_consul(m):
+ for component in COMPONENTS:
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/{}'.format(component),
+ json=[{'Key': component, 'Value': get_b64_conf(component)}]
+ )
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/components_port_start',
+ json=[
+ {
+ "LockIndex": 0,
+ "Key": "components_port_start",
+ "Flags": 0,
+ "Value": "MzEwMDE=",
+ "CreateIndex": 9,
+ "ModifyIndex": 9
+ }
+ ],
+ )
+ m.register_uri(
+ 'PUT', 'http://consul:8500/v1/kv/components_port_start',
+ json=[],
+ )
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/plugins?recurse=true',
+ json=[
+ {
+ "LockIndex": 0,
+ "Key": "plugins/authz",
+ "Flags": 0,
+ "Value": "eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0=",
+ "CreateIndex": 14,
+ "ModifyIndex": 656
+ }
+ ],
+ )
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/components?recurse=true',
+ json=[
+ {"Key": key, "Value": get_b64_conf(key)} for key in COMPONENTS
+ ],
+ )
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/plugins/authz',
+ json=[
+ {
+ "LockIndex": 0,
+ "Key": "plugins/authz",
+ "Flags": 0,
+ "Value": "eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0=",
+ "CreateIndex": 14,
+ "ModifyIndex": 656
+ }
+ ],
+ )
+
+
+def register_orchestrator(m):
+ m.register_uri(
+ 'GET', 'http://orchestrator:8083/pods',
+ json={
+ "pods": {
+ "1234567890": [
+ {"name": "wrapper-quiet", "port": 8080,
+ "container": "wukongsun/moon_wrapper:v4.3.1",
+ "namespace": "moon"}]}}
+ )
+
+
+def register_pdp(m):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'pdp'),
+ json={'pdps': pdp_mock}
+ )
+
+
+def register_meta_rules(m):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'meta_rules'),
+ json={'meta_rules': meta_rules_mock}
+ )
+
+
+def register_policies(m):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies'),
+ json={'policies': policies_mock}
+ )
+
+
+def register_models(m):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'models'),
+ json={'models': models_mock}
+ )
+
+
+def register_policy_subject(m, policy_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/subjects'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies', policy_id),
+ json={'subjects': subject_mock[policy_id]}
+ )
+
+
+def register_policy_object(m, policy_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/objects'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies', policy_id),
+ json={'objects': object_mock[policy_id]}
+ )
+
+
+def register_policy_action(m, policy_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/actions'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies', policy_id),
+ json={'actions': action_mock[policy_id]}
+ )
+
+
+def register_policy_subject_assignment(m, policy_id, subj_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/subject_assignments/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies',
+ policy_id,
+ subj_id),
+ json={'subject_assignments': subject_assignment_mock}
+ )
+
+
+def register_policy_subject_assignment_list(m, policy_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/subject_assignments'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies',
+ policy_id),
+ json={'subject_assignments': subject_assignment_mock}
+ )
+
+
+def register_policy_object_assignment(m, policy_id, obj_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/object_assignments/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies',
+ policy_id,
+ obj_id),
+ json={'object_assignments': object_assignment_mock}
+ )
+
+
+def register_policy_object_assignment_list(m, policy_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/object_assignments'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies',
+ policy_id),
+ json={'object_assignments': object_assignment_mock}
+ )
+
+
+def register_policy_action_assignment(m, policy_id, action_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/action_assignments/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies',
+ policy_id,
+ action_id),
+ json={'action_assignments': action_assignment_mock}
+ )
+
+
+def register_policy_action_assignment_list(m, policy_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/action_assignments'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies',
+ policy_id),
+ json={'action_assignments': action_assignment_mock}
+ )
+
+
+def register_rules(m, policy_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies',
+ policy_id, 'rules'),
+ json={'rules': rules_mock}
+ ) \ No newline at end of file
diff --git a/old/moon_authz/tests/unit_python/requirements.txt b/old/moon_authz/tests/unit_python/requirements.txt
new file mode 100644
index 00000000..21975ce3
--- /dev/null
+++ b/old/moon_authz/tests/unit_python/requirements.txt
@@ -0,0 +1,5 @@
+flask
+flask_cors
+flask_restful
+python_moondb
+python_moonutilities \ No newline at end of file
diff --git a/old/moon_authz/tests/unit_python/test_authz.py b/old/moon_authz/tests/unit_python/test_authz.py
new file mode 100644
index 00000000..2352fe06
--- /dev/null
+++ b/old/moon_authz/tests/unit_python/test_authz.py
@@ -0,0 +1,116 @@
+import json
+import pickle
+import pytest
+
+
+def get_data(data):
+ return pickle.loads(data)
+
+
+def get_json(data):
+ return json.loads(data.decode("utf-8"))
+
+
+def run(component_data, cache, context):
+ from moon_authz.api.authorization import Authz
+ authz = Authz(component_data=component_data, cache=cache)
+ authz.context = context
+ authz.run()
+
+
+def test_authz_true(context):
+ import moon_authz.server
+ from python_moonutilities.context import Context
+ from python_moonutilities.cache import Cache
+ server = moon_authz.server.create_server()
+ client = server.app.test_client()
+ CACHE = Cache()
+ CACHE.update()
+ print(CACHE.pdp)
+ _context = Context(context, CACHE)
+ req = client.post("/authz", data=pickle.dumps(_context))
+ assert req.status_code == 200
+ data = get_data(req.data)
+ assert data
+ assert isinstance(data, Context)
+ policy_id = data.headers[0]
+ assert policy_id
+ assert "effect" in data.pdp_set[policy_id]
+ assert data.pdp_set[policy_id]['effect'] == "grant"
+
+
+def test_user_not_allowed(context):
+ import moon_authz.server
+ from python_moonutilities.context import Context
+ from python_moonutilities.cache import Cache
+ server = moon_authz.server.create_server()
+ client = server.app.test_client()
+ CACHE = Cache()
+ CACHE.update()
+ context['subject_name'] = "user_not_allowed"
+ _context = Context(context, CACHE)
+ req = client.post("/authz", data=pickle.dumps(_context))
+ assert req.status_code == 400
+ data = get_json(req.data)
+ assert data
+ assert isinstance(data, dict)
+ assert "message" in data
+ assert data["message"] == "Cannot find subject user_not_allowed"
+
+
+def test_object_not_allowed(context):
+ import moon_authz.server
+ from python_moonutilities.context import Context
+ from python_moonutilities.cache import Cache
+ server = moon_authz.server.create_server()
+ client = server.app.test_client()
+ CACHE = Cache()
+ CACHE.update()
+ context['subject_name'] = "testuser"
+ context['object_name'] = "invalid"
+ _context = Context(context, CACHE)
+ req = client.post("/authz", data=pickle.dumps(_context))
+ assert req.status_code == 400
+ data = get_json(req.data)
+ assert data
+ assert isinstance(data, dict)
+ assert "message" in data
+ assert data["message"] == "Cannot find object invalid"
+
+
+def test_action_not_allowed(context):
+ import moon_authz.server
+ from python_moonutilities.context import Context
+ from python_moonutilities.cache import Cache
+ server = moon_authz.server.create_server()
+ client = server.app.test_client()
+ CACHE = Cache()
+ CACHE.update()
+ context['subject_name'] = "testuser"
+ context['object_name'] = "vm1"
+ context['action_name'] = "invalid"
+ _context = Context(context, CACHE)
+ req = client.post("/authz", data=pickle.dumps(_context))
+ assert req.status_code == 400
+ data = get_json(req.data)
+ assert data
+ assert isinstance(data, dict)
+ assert "message" in data
+ assert data["message"] == "Cannot find action invalid"
+
+
+def test_authz_with_empty_pdp_set(context):
+ from python_moonutilities.context import Context
+ from python_moonutilities.cache import Cache
+ CACHE = Cache()
+ CACHE.update()
+ _context = Context(context, CACHE)
+ component_data = {
+ 'component_id': 'component_id1',
+ 'pdp_id': 'pdp_id1',
+ 'meta_rule_id': 'meta_rule_id1',
+ 'keystone_project_id': 'keystone_project_id1',
+ }
+ with pytest.raises(Exception) as exception_info:
+ run(component_data, CACHE, _context)
+ assert str(exception_info.value) == '400: Pdp Unknown'
diff --git a/old/moon_authz/tests/unit_python/utilities.py b/old/moon_authz/tests/unit_python/utilities.py
new file mode 100644
index 00000000..e3a111bd
--- /dev/null
+++ b/old/moon_authz/tests/unit_python/utilities.py
@@ -0,0 +1,182 @@
+import base64
+import json
+import pytest
+from uuid import uuid4
+
+
+CONF = {
+ "openstack": {
+ "keystone": {
+ "url": "http://keystone:5000/v3",
+ "user": "admin",
+ "check_token": False,
+ "password": "p4ssw0rd",
+ "domain": "default",
+ "certificate": False,
+ "project": "admin"
+ }
+ },
+ "components": {
+ "wrapper": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_wrapper:v4.3",
+ "timeout": 5,
+ "hostname": "wrapper"
+ },
+ "manager": {
+ "bind": "0.0.0.0",
+ "port": 8082,
+ "container": "wukongsun/moon_manager:v4.3",
+ "hostname": "manager"
+ },
+ "port_start": 31001,
+ "orchestrator": {
+ "bind": "0.0.0.0",
+ "port": 8083,
+ "container": "wukongsun/moon_orchestrator:v4.3",
+ "hostname": "orchestrator"
+ },
+ "pipeline": {
+ "interface": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_interface:v4.3",
+ "hostname": "interface"
+ },
+ "authz": {
+ "bind": "0.0.0.0",
+ "port": 8081,
+ "container": "wukongsun/moon_authz:v4.3",
+ "hostname": "authz"
+ }
+ }
+ },
+ "plugins": {
+ "session": {
+ "port": 8082,
+ "container": "asteroide/session:latest"
+ },
+ "authz": {
+ "port": 8081,
+ "container": "wukongsun/moon_authz:v4.3"
+ }
+ },
+ "logging": {
+ "handlers": {
+ "file": {
+ "filename": "/tmp/moon.log",
+ "class": "logging.handlers.RotatingFileHandler",
+ "level": "DEBUG",
+ "formatter": "custom",
+ "backupCount": 3,
+ "maxBytes": 1048576
+ },
+ "console": {
+ "class": "logging.StreamHandler",
+ "formatter": "brief",
+ "level": "INFO",
+ "stream": "ext://sys.stdout"
+ }
+ },
+ "formatters": {
+ "brief": {
+ "format": "%(levelname)s %(name)s %(message)-30s"
+ },
+ "custom": {
+ "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s"
+ }
+ },
+ "root": {
+ "handlers": [
+ "console"
+ ],
+ "level": "ERROR"
+ },
+ "version": 1,
+ "loggers": {
+ "moon": {
+ "handlers": [
+ "console",
+ "file"
+ ],
+ "propagate": False,
+ "level": "DEBUG"
+ }
+ }
+ },
+ "slave": {
+ "name": None,
+ "master": {
+ "url": None,
+ "login": None,
+ "password": None
+ }
+ },
+ "docker": {
+ "url": "tcp://172.88.88.1:2376",
+ "network": "moon"
+ },
+ "database": {
+ "url": "sqlite:///database.db",
+ # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon",
+ "driver": "sql"
+ },
+ "messenger": {
+ "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon"
+ }
+}
+
+
+CONTEXT = {
+ "project_id": "a64beb1cc224474fb4badd43173e7101",
+ "subject_name": "testuser",
+ "object_name": "vm1",
+ "action_name": "boot",
+ "request_id": uuid4().hex,
+ "interface_name": "interface",
+ "manager_url": "http://{}:{}".format(
+ CONF["components"]["manager"]["hostname"],
+ CONF["components"]["manager"]["port"]
+ ),
+ "cookie": uuid4().hex,
+ "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd",
+ "security_pipeline": ["f8f49a779ceb47b3ac810f01ef71b4e0"]
+ }
+
+
+COMPONENTS = (
+ "logging",
+ "openstack/keystone",
+ "database",
+ "slave",
+ "components/manager",
+ "components/orchestrator",
+ "components/pipeline",
+
+ "components/wrapper",
+)
+
+
+def get_b64_conf(component=None):
+ if component == "components":
+ return base64.b64encode(
+ json.dumps(CONF["components"]).encode('utf-8')+b"\n").decode('utf-8')
+ elif component in CONF:
+ return base64.b64encode(
+ json.dumps(
+ CONF[component]).encode('utf-8')+b"\n").decode('utf-8')
+ elif not component:
+ return base64.b64encode(
+ json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8')
+ elif "/" in component:
+ key1, _, key2 = component.partition("/")
+ return base64.b64encode(
+ json.dumps(
+ CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8')
+
+
+def get_json(data):
+ return json.loads(data.decode("utf-8"))
+
+
diff --git a/old/moon_bouchon/Dockerfile b/old/moon_bouchon/Dockerfile
new file mode 100644
index 00000000..ed013935
--- /dev/null
+++ b/old/moon_bouchon/Dockerfile
@@ -0,0 +1,8 @@
+FROM python:3
+
+ADD . /root
+RUN pip install -r /root/requirements.txt --upgrade
+WORKDIR /root
+RUN pip install .
+
+CMD ["python", "-m", "moon_bouchon"] \ No newline at end of file
diff --git a/old/moon_bouchon/README.md b/old/moon_bouchon/README.md
new file mode 100644
index 00000000..11733cef
--- /dev/null
+++ b/old/moon_bouchon/README.md
@@ -0,0 +1,42 @@
+#Moon Bouchon
+
+Moon_bouchon is a fake interface to the Moon platform.
+Moon platform can be requested through 2 interfaces:
+
+- ''wrapper'', interface for the OpenStack platform
+- ''interface'', interface for other components
+
+## Usage:
+
+### server
+
+To start the server:
+
+ docker run -ti -p 31002:31002 wukongsun/moon_bouchon:v1.0
+ # or docker run -dti -p 31002:31002 wukongsun/moon_bouchon:v1.0
+
+### wrapper
+
+Here are the URL, you can request:
+
+ POST /wrapper/authz/grant to request the wrapper component with always a "True" response
+ POST /wrapper/authz/deny to request the wrapper component with always a "False" response
+ POST /wrapper/authz to request the wrapper component with always a "True" or "False" response
+
+In each request you must pass the following data (or similar):
+
+ {'rule': 'start', 'target': '{"target": {"name": "vm0"}, "user_id": "user0"}', 'credentials': 'null'}
+
+You have examples in the moon_bouchon/tests directory.
+
+### interface
+
+Here are the URL, you can request:
+
+ GET /interface/authz/grant/<string:project_id>/<string:subject_name>/<string:object_name>/<string:action_name> to request the interface component with always a "True" response
+ GET /interface/authz/deny/<string:project_id>/<string:subject_name>/<string:object_name>/<string:action_name> to request the interface component with always a "False" response
+ GET /interface/authz/<string:project_id>/<string:subject_name>/<string:object_name>/<string:action_name> to request the interface component with always a "True" or "False" response
+
+You have examples in the moon_bouchon/tests directory.
+
+
diff --git a/old/moon_bouchon/moon_bouchon/__init__.py b/old/moon_bouchon/moon_bouchon/__init__.py
new file mode 100644
index 00000000..8811d91d
--- /dev/null
+++ b/old/moon_bouchon/moon_bouchon/__init__.py
@@ -0,0 +1,7 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+__version__ = "1.1"
diff --git a/old/moon_bouchon/moon_bouchon/__main__.py b/old/moon_bouchon/moon_bouchon/__main__.py
new file mode 100644
index 00000000..4499a96b
--- /dev/null
+++ b/old/moon_bouchon/moon_bouchon/__main__.py
@@ -0,0 +1,9 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+import moon_bouchon.server
+
+moon_bouchon.server.main()
diff --git a/old/moon_bouchon/moon_bouchon/server.py b/old/moon_bouchon/moon_bouchon/server.py
new file mode 100644
index 00000000..29e9101e
--- /dev/null
+++ b/old/moon_bouchon/moon_bouchon/server.py
@@ -0,0 +1,138 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import sys
+import flask
+from flask import Flask
+from flask import request
+import json
+import logging
+import random
+
+logger = logging.getLogger(__name__)
+app = Flask(__name__)
+
+
+@app.route("/interface/authz/grant/<string:project_id>/<string:subject_name>/"
+ "<string:object_name>/<string:action_name>",
+ methods=["GET"])
+def interface_grant(project_id, subject_name, object_name, action_name):
+ logger.info("Requesting interface authz on {} {} {} {}".format(
+ project_id, subject_name, object_name, action_name))
+ return json.dumps({
+ "result": True,
+ "context": {
+ "project_id": project_id,
+ "subject_name": subject_name,
+ "object_name": object_name,
+ "action_name": action_name
+ }
+ })
+
+
+@app.route("/interface/authz/deny/<string:project_id>/<string:subject_name>/"
+ "<string:object_name>/<string:action_name>",
+ methods=["GET"])
+def interface_deny(project_id, subject_name, object_name, action_name):
+ logger.info("Requesting interface authz on {} {} {} {}".format(
+ project_id, subject_name, object_name, action_name))
+ return json.dumps({
+ "result": False,
+ "context": {
+ "project_id": project_id,
+ "subject_name": subject_name,
+ "object_name": object_name,
+ "action_name": action_name
+ }
+ })
+
+
+@app.route("/interface/authz/<string:project_id>/<string:subject_name>/"
+ "<string:object_name>/<string:action_name>",
+ methods=["GET"])
+def interface_authz(project_id, subject_name, object_name, action_name):
+ logger.info("Requesting interface authz on {} {} {} {}".format(
+ project_id, subject_name, object_name, action_name))
+ return json.dumps({
+ "result": random.choice((True, False)),
+ "context": {
+ "project_id": project_id,
+ "subject_name": subject_name,
+ "object_name": object_name,
+ "action_name": action_name
+ }
+ })
+
+
+def test_data():
+ data = request.form
+ if not dict(request.form):
+ data = json.loads(request.data.decode("utf-8"))
+ try:
+ target = json.loads(data.get('target', {}))
+ except Exception:
+ raise Exception("Error reading target")
+ try:
+ credentials = json.loads(data.get('credentials', {}))
+ except Exception:
+ raise Exception("Error reading credentials")
+ try:
+ rule = data.get('rule', "")
+ except Exception:
+ raise Exception("Error reading rule")
+
+
+@app.route("/wrapper/authz/grant", methods=["POST"])
+def wrapper_grant():
+ logger.info("Requesting wrapper authz")
+ try:
+ test_data()
+ except Exception as e:
+ logger.exception(e)
+ return str(e), 400
+ response = flask.make_response("True")
+ response.headers['content-type'] = 'application/octet-stream'
+ return response
+
+
+@app.route("/wrapper/authz/deny", methods=["POST"])
+def wrapper_deny():
+ logger.info("Requesting wrapper authz")
+ try:
+ test_data()
+ except Exception as e:
+ logger.exception(e)
+ return str(e), 400
+ response = flask.make_response("False")
+ response.headers['content-type'] = 'application/octet-stream'
+ return response
+
+
+@app.route("/wrapper/authz", methods=["POST"])
+def wrapper_authz():
+ logger.info("Requesting wrapper authz")
+ try:
+ test_data()
+ except Exception as e:
+ logger.exception(e)
+ return str(e), 400
+ response = flask.make_response(random.choice(("True", "False")))
+ response.headers['content-type'] = 'application/octet-stream'
+ return response
+
+
+def main():
+ port = 31002
+ if len(sys.argv) > 1:
+ try:
+ port = int(sys.argv[1])
+ except ValueError:
+ logger.error("Argument for Port in command line is not an integer")
+ sys.exit(1)
+ app.run(host="0.0.0.0", port=port)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/old/moon_bouchon/requirements.txt b/old/moon_bouchon/requirements.txt
new file mode 100644
index 00000000..8ab6294c
--- /dev/null
+++ b/old/moon_bouchon/requirements.txt
@@ -0,0 +1 @@
+flask \ No newline at end of file
diff --git a/old/moon_bouchon/setup.cfg b/old/moon_bouchon/setup.cfg
new file mode 100644
index 00000000..7c2b2874
--- /dev/null
+++ b/old/moon_bouchon/setup.cfg
@@ -0,0 +1,2 @@
+[bdist_wheel]
+universal = 1 \ No newline at end of file
diff --git a/old/moon_bouchon/setup.py b/old/moon_bouchon/setup.py
new file mode 100644
index 00000000..a875be40
--- /dev/null
+++ b/old/moon_bouchon/setup.py
@@ -0,0 +1,47 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from setuptools import setup, find_packages
+import moon_bouchon
+
+
+setup(
+
+ name='moon_bouchon',
+
+ version=moon_bouchon.__version__,
+
+ packages=find_packages(),
+
+ author="Thomas Duval",
+
+ author_email="thomas.duval@orange.com",
+
+ description="",
+
+ long_description=open('README.md').read(),
+
+ install_requires=["flask"],
+
+ include_package_data=True,
+
+ url='https://git.opnfv.org/cgit/moon',
+
+ classifiers=[
+ "Programming Language :: Python",
+ "Development Status :: 1 - Planning",
+ "License :: OSI Approved",
+ "Natural Language :: French",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python :: 3",
+ ],
+
+ entry_points={
+ 'console_scripts': [
+ 'moon_bouchon = moon_bouchon.server:main',
+ ],
+ }
+
+)
diff --git a/old/moon_bouchon/tests/test_interface.py b/old/moon_bouchon/tests/test_interface.py
new file mode 100644
index 00000000..425ba2e5
--- /dev/null
+++ b/old/moon_bouchon/tests/test_interface.py
@@ -0,0 +1,61 @@
+import requests
+from uuid import uuid4
+import pytest
+
+
+@pytest.fixture
+def args():
+ return {
+ "project_id": uuid4().hex,
+ "subject_id": uuid4().hex,
+ "object_id": uuid4().hex,
+ "action_id": uuid4().hex
+ }
+
+
+def test_false(args):
+ url = "http://127.0.0.1:31002/interface/authz/deny/{project_id}" \
+ "/{subject_id}/{object_id}/{action_id}".format(**args)
+ data = {'rule': 'start',
+ 'target': '{"target": {"name": "vm0"}, "user_id": "user0"}',
+ 'credentials': 'null'}
+ req = requests.get(
+ url, json=data,
+ headers={'content-type': "application/x-www-form-urlencode"}
+ )
+ assert req.status_code == 200
+ assert "result" in req.json()
+ assert req.json()["result"] == False
+
+
+def test_true(args):
+ url = "http://127.0.0.1:31002/interface/authz/grant/{project_id}" \
+ "/{subject_id}/{object_id}/{action_id}".format(**args)
+
+ data = {'rule': 'start',
+ 'target': '{"target": {"name": "vm0"}, "user_id": "user0"}',
+ 'credentials': 'null'}
+ req = requests.get(
+ url, json=data,
+ headers={'content-type': "application/x-www-form-urlencode"}
+ )
+ assert req.status_code == 200
+ assert "result" in req.json()
+ assert req.json()["result"] == True
+
+
+def test_random(args):
+ url = "http://127.0.0.1:31002/interface/authz/{project_id}" \
+ "/{subject_id}/{object_id}/{action_id}".format(**args)
+
+ data = {'rule': 'start',
+ 'target': '{"target": {"name": "vm0"}, "user_id": "user0"}',
+ 'credentials': 'null'}
+ req = requests.get(
+ url, json=data,
+ headers={'content-type': "application/x-www-form-urlencode"}
+ )
+ assert req.status_code == 200
+ assert "result" in req.json()
+ assert req.json()["result"] in (False, True)
+
diff --git a/old/moon_bouchon/tests/test_wrapper.py b/old/moon_bouchon/tests/test_wrapper.py
new file mode 100644
index 00000000..3d5e150c
--- /dev/null
+++ b/old/moon_bouchon/tests/test_wrapper.py
@@ -0,0 +1,38 @@
+import requests
+
+
+def test_false():
+ url = "http://127.0.0.1:31002/wrapper/authz/deny"
+
+ data = {'rule': 'start', 'target': '{"target": {"name": "vm0"}, "user_id": "user0"}', 'credentials': 'null'}
+ req = requests.post(
+ url, json=data,
+ headers={'content-type': "application/x-www-form-urlencode"}
+ )
+ assert req.status_code == 200
+ assert req.text == "False"
+
+
+def test_true():
+ url = "http://127.0.0.1:31002/wrapper/authz/grant"
+
+ data = {'rule': 'start', 'target': '{"target": {"name": "vm0"}, "user_id": "user0"}', 'credentials': 'null'}
+ req = requests.post(
+ url, json=data,
+ headers={'content-type': "application/x-www-form-urlencode"}
+ )
+ assert req.status_code == 200
+ assert req.text == "True"
+
+
+def test_random():
+ url = "http://127.0.0.1:31002/wrapper/authz"
+
+ data = {'rule': 'start', 'target': '{"target": {"name": "vm0"}, "user_id": "user0"}', 'credentials': 'null'}
+ req = requests.post(
+ url, json=data,
+ headers={'content-type': "application/x-www-form-urlencode"}
+ )
+ assert req.status_code == 200
+ assert req.text in ("False", "True")
+
diff --git a/old/moon_dashboard/.gitignore b/old/moon_dashboard/.gitignore
new file mode 100644
index 00000000..61f2dc9f
--- /dev/null
+++ b/old/moon_dashboard/.gitignore
@@ -0,0 +1 @@
+**/__pycache__/
diff --git a/old/moon_dashboard/.gitlab-ci.yml b/old/moon_dashboard/.gitlab-ci.yml
new file mode 100644
index 00000000..50fd8a4e
--- /dev/null
+++ b/old/moon_dashboard/.gitlab-ci.yml
@@ -0,0 +1,64 @@
+stages:
+ - lint
+ - build
+ - test
+ - publish
+
+variables:
+ http_proxy: "http://devwatt-proxy.si.fr.intraorange:8080"
+ https_proxy: "http://devwatt-proxy.si.fr.intraorange:8080"
+ no_proxy: dind, gitlab.forge.orange-labs.fr
+ DOCKER_DRIVER: overlay
+ DOCKER_HOST: tcp://dind:2375
+ CONTAINER_RELEASE_IMAGE: moonplatform/$CI_PROJECT_NAME
+ CONTAINER_TAG: dev
+ DOCKER_VERSION: "17.12"
+
+services:
+ - name: dockerproxy-iva.si.francetelecom.fr/docker:$DOCKER_VERSION-dind
+ alias: dind
+image: dockerproxy-iva.si.francetelecom.fr/docker:$DOCKER_VERSION
+
+lint-job:
+ image: dockerfactory-iva.si.francetelecom.fr/docker/orange-dockerfile-lint:0.2.7-alpine3.6-2
+ tags:
+ - rsc
+ - docker
+ - shared
+ stage: lint
+ script:
+ - dockerfile_lint -f Dockerfile
+
+build-job:
+ stage: build
+ tags:
+ - rsc
+ - docker-privileged
+ script:
+ - docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
+ - docker build -t $CONTAINER_RELEASE_IMAGE:$CONTAINER_TAG --build-arg http_proxy=$http_proxy --build-arg https_proxy=$http_proxy .
+ - docker push $CONTAINER_RELEASE_IMAGE:$CONTAINER_TAG
+
+test-job:
+ stage: test
+ tags:
+ - rsc
+ - docker-privileged
+ script:
+ - docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
+ - docker run -e http_proxy=$http_proxy -e https_proxy=$http_proxy $CONTAINER_RELEASE_IMAGE:$CONTAINER_TAG curl http://localhost:8000
+
+publish-job:
+ stage: publish
+ tags:
+ - rsc
+ - docker-privileged
+ script:
+ - docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
+ - FINAL_TAG=$(grep version setup.cfg | cut -d "=" -f 2)
+ - echo FINAL_TAG=$FINAL_TAG
+ - docker pull $CONTAINER_RELEASE_IMAGE:$CONTAINER_TAG
+ - docker tag $CONTAINER_RELEASE_IMAGE:$CONTAINER_TAG $CONTAINER_RELEASE_IMAGE:$FINAL_TAG
+ - docker push $CONTAINER_RELEASE_IMAGE:$FINAL_TAG
+ only:
+ - master
diff --git a/old/moon_dashboard/Dockerfile b/old/moon_dashboard/Dockerfile
new file mode 100644
index 00000000..790a2b21
--- /dev/null
+++ b/old/moon_dashboard/Dockerfile
@@ -0,0 +1,38 @@
+FROM python:3.5
+
+LABEL Name=Dashboard
+LABEL Description="User interface for the Moon platform"
+LABEL Maintainer="Thomas Duval"
+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=5000
+ENV OPENSTACK_HOST="127.0.0.1"
+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 [ -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
+RUN pip install --no-cache-dir tox
+
+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/old/moon_dashboard/LICENSE b/old/moon_dashboard/LICENSE
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/moon_dashboard/LICENSE
diff --git a/old/moon_dashboard/MANIFEST.in b/old/moon_dashboard/MANIFEST.in
new file mode 100644
index 00000000..1f077b06
--- /dev/null
+++ b/old/moon_dashboard/MANIFEST.in
@@ -0,0 +1,3 @@
+include setup.py
+
+recursive-include myplugin *.js *.html *.scss \ No newline at end of file
diff --git a/old/moon_dashboard/README.md b/old/moon_dashboard/README.md
new file mode 100644
index 00000000..fca52b2d
--- /dev/null
+++ b/old/moon_dashboard/README.md
@@ -0,0 +1,40 @@
+# Moon plugin for Horizon (OpenStack Dashboard)
+
+## Install Horizon
+
+https://docs.openstack.org/horizon/latest/install/index.html
+
+or for developper quick start:
+
+https://docs.openstack.org/horizon/latest/contributor/quickstart.html
+
+
+## Moon plugin
+
+Clone the plugin:
+
+```bash
+git clone https://gitlab.forge.orange-labs.fr/moon/dashboard.git
+```
+
+* ``$plugin`` is the location of moon plugin
+* ``$horizon`` is the location of horizon
+
+Make symbolic link to enabled file:
+
+```bash
+ln -s $plugin/moon/enabled/_32000_moon.py $horizon/openstack_dashboard/local/enabled/_32000_moon.py
+```
+
+Make symbolic link to dashboard folder:
+
+```bash
+ln -s $plugin/moon/ $horizon/openstack_dashboard/dashboards/moon
+```
+
+Finish by restarting the Horizon server.
+
+## Set Moon API endpoint
+
+Set the endpoint in $plugin/moon/moon/static/moon/js/moon.module.js file
+
diff --git a/old/moon_dashboard/README.rst b/old/moon_dashboard/README.rst
new file mode 100644
index 00000000..de9c4058
--- /dev/null
+++ b/old/moon_dashboard/README.rst
@@ -0,0 +1,39 @@
+=============================================
+Moon plugin for Horizon (OpenStack Dashboard)
+=============================================
+
+Install Horizon
+===============
+
+https://docs.openstack.org/horizon/latest/install/index.html
+
+or for developper quick start:
+
+https://docs.openstack.org/horizon/latest/contributor/quickstart.html
+
+
+Moon plugin
+===========
+
+Clone the plugin:
+
+"git clone https://gitlab.forge.orange-labs.fr/moon/dashboard.git"
+
+* ``plugin`` is the location of moon plugin
+* ``horizon`` is the location of horizon
+
+Make symbolic link to enabled file:
+
+"ln -s ``plugin`̀`/moon/enabled/_32000_moon.py ``horizon``/openstack_dashboard/local/enabled/_32000_moon.py"
+
+Make symbolic link to dashboard folder:
+
+"ln -s ``plugin`̀`/moon/ ``horizon``/openstack_dashboard/dashboards/moon"
+
+Finish by restarting the Horizon server.
+
+
+Set Moon API endpoint
+===========
+
+Set the endpoint in ``plugin``/moon/moon/static/moon/js/moon.module.js file \ No newline at end of file
diff --git a/old/moon_dashboard/babel-django.cfg b/old/moon_dashboard/babel-django.cfg
new file mode 100644
index 00000000..fa906ad8
--- /dev/null
+++ b/old/moon_dashboard/babel-django.cfg
@@ -0,0 +1,5 @@
+[extractors]
+django = django_babel.extract:extract_django
+
+[python: **.py]
+[django: **/templates/**.html] \ No newline at end of file
diff --git a/old/moon_dashboard/babel-djangojs.cfg b/old/moon_dashboard/babel-djangojs.cfg
new file mode 100644
index 00000000..1c07ba6a
--- /dev/null
+++ b/old/moon_dashboard/babel-djangojs.cfg
@@ -0,0 +1,14 @@
+[extractors]
+# We use a custom extractor to find translatable strings in AngularJS
+# templates. The extractor is included in horizon.utils for now.
+# See http://babel.pocoo.org/docs/messages/#referencing-extraction-methods for
+# details on how this works.
+angular = horizon.utils.babel_extract_angular:extract_angular
+
+[javascript: **.js]
+
+# We need to look into all static folders for HTML files.
+# The **/static ensures that we also search within
+# /openstack_dashboard/dashboards/XYZ/static which will ensure
+# that plugins are also translated.
+[angular: **/static/**.html] \ No newline at end of file
diff --git a/old/moon_dashboard/moon/__init__.py b/old/moon_dashboard/moon/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/moon_dashboard/moon/__init__.py
diff --git a/old/moon_dashboard/moon/api/__init__.py b/old/moon_dashboard/moon/api/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/moon_dashboard/moon/api/__init__.py
diff --git a/old/moon_dashboard/moon/api/moon_api.py b/old/moon_dashboard/moon/api/moon_api.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/moon_dashboard/moon/api/moon_api.py
diff --git a/old/moon_dashboard/moon/dashboard.py b/old/moon_dashboard/moon/dashboard.py
new file mode 100644
index 00000000..0e3e491e
--- /dev/null
+++ b/old/moon_dashboard/moon/dashboard.py
@@ -0,0 +1,13 @@
+from django.utils.translation import ugettext_lazy as _
+
+import horizon
+
+
+class Moon(horizon.Dashboard):
+ name = _("Moon")
+ slug = "moon"
+ panels = ('model','policy','pdp',) # Add your panels here.
+ default_panel = 'model' # Specify the slug of the default panel.
+
+
+horizon.register(Moon)
diff --git a/old/moon_dashboard/moon/enabled/_32000_moon.py b/old/moon_dashboard/moon/enabled/_32000_moon.py
new file mode 100644
index 00000000..73198de6
--- /dev/null
+++ b/old/moon_dashboard/moon/enabled/_32000_moon.py
@@ -0,0 +1,19 @@
+# The name of the dashboard to be added to HORIZON['dashboards']. Required.
+DASHBOARD = 'moon'
+
+# If set to True, this dashboard will not be added to the settings.
+DISABLED = False
+
+# A list of AngularJS modules to be loaded when Angular bootstraps.
+ADD_ANGULAR_MODULES = ['moon']
+
+# Automatically discover static resources in installed apps
+AUTO_DISCOVER_STATIC_FILES = True
+
+# A list of applications to be added to INSTALLED_APPS.
+ADD_INSTALLED_APPS = [
+ 'openstack_dashboard.dashboards.moon',
+]
+
+# A list of scss files to be included in the compressed set of files
+ADD_SCSS_FILES = ['moon/scss/moon.scss']
diff --git a/old/moon_dashboard/moon/model/__init__.py b/old/moon_dashboard/moon/model/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/moon_dashboard/moon/model/__init__.py
diff --git a/old/moon_dashboard/moon/model/panel.py b/old/moon_dashboard/moon/model/panel.py
new file mode 100644
index 00000000..9cb65ef0
--- /dev/null
+++ b/old/moon_dashboard/moon/model/panel.py
@@ -0,0 +1,23 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from django.utils.translation import ugettext_lazy as _
+
+import horizon
+from openstack_dashboard.dashboards.moon import dashboard
+
+class Model(horizon.Panel):
+ name = _("Models")
+ slug = "model"
+
+
+dashboard.Moon.register(Model)
diff --git a/old/moon_dashboard/moon/model/templates/model/index.html b/old/moon_dashboard/moon/model/templates/model/index.html
new file mode 100644
index 00000000..db372a02
--- /dev/null
+++ b/old/moon_dashboard/moon/model/templates/model/index.html
@@ -0,0 +1,16 @@
+{% extends 'base.html' %}
+{% load i18n %}
+{% block title %}{% trans "Models" %}{% endblock %}
+
+{% block page_header %}
+ {% include "horizon/common/_page_header.html" with title=_("Models") %}
+{% endblock page_header %}
+
+
+
+{% block main %}
+ <ng-include
+ src="'{{ STATIC_URL }}moon/model/model.html'">
+ </ng-include>
+{% endblock %}
+
diff --git a/old/moon_dashboard/moon/model/tests.py b/old/moon_dashboard/moon/model/tests.py
new file mode 100644
index 00000000..ec988636
--- /dev/null
+++ b/old/moon_dashboard/moon/model/tests.py
@@ -0,0 +1,19 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from horizon.test import helpers as test
+
+
+class MypanelTests(test.TestCase):
+ # Unit tests for mypanel.
+ def test_me(self):
+ self.assertTrue(1 + 1 == 2)
diff --git a/old/moon_dashboard/moon/model/urls.py b/old/moon_dashboard/moon/model/urls.py
new file mode 100644
index 00000000..ca9507fb
--- /dev/null
+++ b/old/moon_dashboard/moon/model/urls.py
@@ -0,0 +1,20 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from django.conf.urls import url
+
+from openstack_dashboard.dashboards.moon.model import views
+
+
+urlpatterns = [
+ url(r'^$', views.IndexView.as_view(), name='index'),
+]
diff --git a/old/moon_dashboard/moon/model/views.py b/old/moon_dashboard/moon/model/views.py
new file mode 100644
index 00000000..73509537
--- /dev/null
+++ b/old/moon_dashboard/moon/model/views.py
@@ -0,0 +1,22 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from horizon import views
+
+
+class IndexView(views.APIView):
+ # A very simple class-based view...
+ template_name = 'moon/model/index.html'
+
+ def get_data(self, request, context, *args, **kwargs):
+ # Add data to the context here...
+ return context
diff --git a/old/moon_dashboard/moon/pdp/__init__.py b/old/moon_dashboard/moon/pdp/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/moon_dashboard/moon/pdp/__init__.py
diff --git a/old/moon_dashboard/moon/pdp/panel.py b/old/moon_dashboard/moon/pdp/panel.py
new file mode 100644
index 00000000..9c4b3fa3
--- /dev/null
+++ b/old/moon_dashboard/moon/pdp/panel.py
@@ -0,0 +1,23 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from django.utils.translation import ugettext_lazy as _
+
+import horizon
+from openstack_dashboard.dashboards.moon import dashboard
+
+class Pdp(horizon.Panel):
+ name = _("PDP")
+ slug = "pdp"
+
+
+dashboard.Moon.register(Pdp)
diff --git a/old/moon_dashboard/moon/pdp/templates/pdp/index.html b/old/moon_dashboard/moon/pdp/templates/pdp/index.html
new file mode 100644
index 00000000..30ac5f93
--- /dev/null
+++ b/old/moon_dashboard/moon/pdp/templates/pdp/index.html
@@ -0,0 +1,16 @@
+{% extends 'base.html' %}
+{% load i18n %}
+{% block title %}{% trans "PDP" %}{% endblock %}
+
+{% block page_header %}
+ {% include "horizon/common/_page_header.html" with title=_("PDP") %}
+{% endblock page_header %}
+
+
+
+{% block main %}
+ <ng-include
+ src="'{{ STATIC_URL }}moon/pdp/pdp.html'">
+ </ng-include>
+{% endblock %}
+
diff --git a/old/moon_dashboard/moon/pdp/tests.py b/old/moon_dashboard/moon/pdp/tests.py
new file mode 100644
index 00000000..ec988636
--- /dev/null
+++ b/old/moon_dashboard/moon/pdp/tests.py
@@ -0,0 +1,19 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from horizon.test import helpers as test
+
+
+class MypanelTests(test.TestCase):
+ # Unit tests for mypanel.
+ def test_me(self):
+ self.assertTrue(1 + 1 == 2)
diff --git a/old/moon_dashboard/moon/pdp/urls.py b/old/moon_dashboard/moon/pdp/urls.py
new file mode 100644
index 00000000..a66c8e0c
--- /dev/null
+++ b/old/moon_dashboard/moon/pdp/urls.py
@@ -0,0 +1,20 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from django.conf.urls import url
+
+from openstack_dashboard.dashboards.moon.pdp import views
+
+
+urlpatterns = [
+ url(r'^$', views.IndexView.as_view(), name='index'),
+]
diff --git a/old/moon_dashboard/moon/pdp/views.py b/old/moon_dashboard/moon/pdp/views.py
new file mode 100644
index 00000000..8355a5d5
--- /dev/null
+++ b/old/moon_dashboard/moon/pdp/views.py
@@ -0,0 +1,22 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from horizon import views
+
+
+class IndexView(views.APIView):
+ # A very simple class-based view...
+ template_name = 'moon/pdp/index.html'
+
+ def get_data(self, request, context, *args, **kwargs):
+ # Add data to the context here...
+ return context
diff --git a/old/moon_dashboard/moon/policy/__init__.py b/old/moon_dashboard/moon/policy/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/moon_dashboard/moon/policy/__init__.py
diff --git a/old/moon_dashboard/moon/policy/panel.py b/old/moon_dashboard/moon/policy/panel.py
new file mode 100644
index 00000000..875a2d76
--- /dev/null
+++ b/old/moon_dashboard/moon/policy/panel.py
@@ -0,0 +1,23 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from django.utils.translation import ugettext_lazy as _
+
+import horizon
+from openstack_dashboard.dashboards.moon import dashboard
+
+class Policy(horizon.Panel):
+ name = _("Policies")
+ slug = "policy"
+
+
+dashboard.Moon.register(Policy)
diff --git a/old/moon_dashboard/moon/policy/templates/policy/index.html b/old/moon_dashboard/moon/policy/templates/policy/index.html
new file mode 100644
index 00000000..67cd9c3d
--- /dev/null
+++ b/old/moon_dashboard/moon/policy/templates/policy/index.html
@@ -0,0 +1,16 @@
+{% extends 'base.html' %}
+{% load i18n %}
+{% block title %}{% trans "Policies" %}{% endblock %}
+
+{% block page_header %}
+ {% include "horizon/common/_page_header.html" with title=_("Policies") %}
+{% endblock page_header %}
+
+
+
+{% block main %}
+ <ng-include
+ src="'{{ STATIC_URL }}moon/policy/policy.html'">
+ </ng-include>
+{% endblock %}
+
diff --git a/old/moon_dashboard/moon/policy/tests.py b/old/moon_dashboard/moon/policy/tests.py
new file mode 100644
index 00000000..ec988636
--- /dev/null
+++ b/old/moon_dashboard/moon/policy/tests.py
@@ -0,0 +1,19 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from horizon.test import helpers as test
+
+
+class MypanelTests(test.TestCase):
+ # Unit tests for mypanel.
+ def test_me(self):
+ self.assertTrue(1 + 1 == 2)
diff --git a/old/moon_dashboard/moon/policy/urls.py b/old/moon_dashboard/moon/policy/urls.py
new file mode 100644
index 00000000..81bde0ca
--- /dev/null
+++ b/old/moon_dashboard/moon/policy/urls.py
@@ -0,0 +1,20 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from django.conf.urls import url
+
+from openstack_dashboard.dashboards.moon.policy import views
+
+
+urlpatterns = [
+ url(r'^$', views.IndexView.as_view(), name='index'),
+]
diff --git a/old/moon_dashboard/moon/policy/views.py b/old/moon_dashboard/moon/policy/views.py
new file mode 100644
index 00000000..826c833b
--- /dev/null
+++ b/old/moon_dashboard/moon/policy/views.py
@@ -0,0 +1,22 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from horizon import views
+
+
+class IndexView(views.APIView):
+ # A very simple class-based view...
+ template_name = 'moon/policy/index.html'
+
+ def get_data(self, request, context, *args, **kwargs):
+ # Add data to the context here...
+ return context
diff --git a/old/moon_dashboard/moon/static/moon/js/angular-resource.js b/old/moon_dashboard/moon/static/moon/js/angular-resource.js
new file mode 100644
index 00000000..e8bb3014
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/js/angular-resource.js
@@ -0,0 +1,863 @@
+/**
+ * @license AngularJS v1.5.8
+ * (c) 2010-2016 Google, Inc. http://angularjs.org
+ * License: MIT
+ */
+(function(window, angular) {'use strict';
+
+var $resourceMinErr = angular.$$minErr('$resource');
+
+// Helper functions and regex to lookup a dotted path on an object
+// stopping at undefined/null. The path must be composed of ASCII
+// identifiers (just like $parse)
+var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$@][0-9a-zA-Z_$@]*)+$/;
+
+function isValidDottedPath(path) {
+ return (path != null && path !== '' && path !== 'hasOwnProperty' &&
+ MEMBER_NAME_REGEX.test('.' + path));
+}
+
+function lookupDottedPath(obj, path) {
+ if (!isValidDottedPath(path)) {
+ throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path);
+ }
+ var keys = path.split('.');
+ for (var i = 0, ii = keys.length; i < ii && angular.isDefined(obj); i++) {
+ var key = keys[i];
+ obj = (obj !== null) ? obj[key] : undefined;
+ }
+ return obj;
+}
+
+/**
+ * Create a shallow copy of an object and clear other fields from the destination
+ */
+function shallowClearAndCopy(src, dst) {
+ dst = dst || {};
+
+ angular.forEach(dst, function(value, key) {
+ delete dst[key];
+ });
+
+ for (var key in src) {
+ if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
+ dst[key] = src[key];
+ }
+ }
+
+ return dst;
+}
+
+/**
+ * @ngdoc module
+ * @name ngResource
+ * @description
+ *
+ * # ngResource
+ *
+ * The `ngResource` module provides interaction support with RESTful services
+ * via the $resource service.
+ *
+ *
+ * <div doc-module-components="ngResource"></div>
+ *
+ * See {@link ngResource.$resourceProvider} and {@link ngResource.$resource} for usage.
+ */
+
+/**
+ * @ngdoc provider
+ * @name $resourceProvider
+ *
+ * @description
+ *
+ * Use `$resourceProvider` to change the default behavior of the {@link ngResource.$resource}
+ * service.
+ *
+ * ## Dependencies
+ * Requires the {@link ngResource } module to be installed.
+ *
+ */
+
+/**
+ * @ngdoc service
+ * @name $resource
+ * @requires $http
+ * @requires ng.$log
+ * @requires $q
+ * @requires ng.$timeout
+ *
+ * @description
+ * A factory which creates a resource object that lets you interact with
+ * [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources.
+ *
+ * The returned resource object has action methods which provide high-level behaviors without
+ * the need to interact with the low level {@link ng.$http $http} service.
+ *
+ * Requires the {@link ngResource `ngResource`} module to be installed.
+ *
+ * By default, trailing slashes will be stripped from the calculated URLs,
+ * which can pose problems with server backends that do not expect that
+ * behavior. This can be disabled by configuring the `$resourceProvider` like
+ * this:
+ *
+ * ```js
+ app.config(['$resourceProvider', function($resourceProvider) {
+ // Don't strip trailing slashes from calculated URLs
+ $resourceProvider.defaults.stripTrailingSlashes = false;
+ }]);
+ * ```
+ *
+ * @param {string} url A parameterized URL template with parameters prefixed by `:` as in
+ * `/user/:username`. If you are using a URL with a port number (e.g.
+ * `http://example.com:8080/api`), it will be respected.
+ *
+ * If you are using a url with a suffix, just add the suffix, like this:
+ * `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')`
+ * or even `$resource('http://example.com/resource/:resource_id.:format')`
+ * If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be
+ * collapsed down to a single `.`. If you need this sequence to appear and not collapse then you
+ * can escape it with `/\.`.
+ *
+ * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
+ * `actions` methods. If a parameter value is a function, it will be called every time
+ * a param value needs to be obtained for a request (unless the param was overridden). The function
+ * will be passed the current data value as an argument.
+ *
+ * Each key value in the parameter object is first bound to url template if present and then any
+ * excess keys are appended to the url search query after the `?`.
+ *
+ * Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
+ * URL `/path/greet?salutation=Hello`.
+ *
+ * If the parameter value is prefixed with `@`, then the value for that parameter will be
+ * extracted from the corresponding property on the `data` object (provided when calling a
+ * "non-GET" action method).
+ * For example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of
+ * `someParam` will be `data.someProp`.
+ * Note that the parameter will be ignored, when calling a "GET" action method (i.e. an action
+ * method that does not accept a request body)
+ *
+ * @param {Object.<Object>=} actions Hash with declaration of custom actions that should extend
+ * the default set of resource actions. The declaration should be created in the format of {@link
+ * ng.$http#usage $http.config}:
+ *
+ * {action1: {method:?, params:?, isArray:?, headers:?, ...},
+ * action2: {method:?, params:?, isArray:?, headers:?, ...},
+ * ...}
+ *
+ * Where:
+ *
+ * - **`action`** – {string} – The name of action. This name becomes the name of the method on
+ * your resource object.
+ * - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`,
+ * `DELETE`, `JSONP`, etc).
+ * - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
+ * the parameter value is a function, it will be called every time when a param value needs to
+ * be obtained for a request (unless the param was overridden). The function will be passed the
+ * current data value as an argument.
+ * - **`url`** – {string} – action specific `url` override. The url templating is supported just
+ * like for the resource-level urls.
+ * - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
+ * see `returns` section.
+ * - **`transformRequest`** –
+ * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
+ * transform function or an array of such functions. The transform function takes the http
+ * request body and headers and returns its transformed (typically serialized) version.
+ * By default, transformRequest will contain one function that checks if the request data is
+ * an object and serializes to using `angular.toJson`. To prevent this behavior, set
+ * `transformRequest` to an empty array: `transformRequest: []`
+ * - **`transformResponse`** –
+ * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
+ * transform function or an array of such functions. The transform function takes the http
+ * response body and headers and returns its transformed (typically deserialized) version.
+ * By default, transformResponse will contain one function that checks if the response looks
+ * like a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior,
+ * set `transformResponse` to an empty array: `transformResponse: []`
+ * - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
+ * GET request, otherwise if a cache instance built with
+ * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
+ * caching.
+ * - **`timeout`** – `{number}` – timeout in milliseconds.<br />
+ * **Note:** In contrast to {@link ng.$http#usage $http.config}, {@link ng.$q promises} are
+ * **not** supported in $resource, because the same value would be used for multiple requests.
+ * If you are looking for a way to cancel requests, you should use the `cancellable` option.
+ * - **`cancellable`** – `{boolean}` – if set to true, the request made by a "non-instance" call
+ * will be cancelled (if not already completed) by calling `$cancelRequest()` on the call's
+ * return value. Calling `$cancelRequest()` for a non-cancellable or an already
+ * completed/cancelled request will have no effect.<br />
+ * - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
+ * XHR object. See
+ * [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5)
+ * for more information.
+ * - **`responseType`** - `{string}` - see
+ * [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
+ * - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
+ * `response` and `responseError`. Both `response` and `responseError` interceptors get called
+ * with `http response` object. See {@link ng.$http $http interceptors}.
+ *
+ * @param {Object} options Hash with custom settings that should extend the
+ * default `$resourceProvider` behavior. The supported options are:
+ *
+ * - **`stripTrailingSlashes`** – {boolean} – If true then the trailing
+ * slashes from any calculated URL will be stripped. (Defaults to true.)
+ * - **`cancellable`** – {boolean} – If true, the request made by a "non-instance" call will be
+ * cancelled (if not already completed) by calling `$cancelRequest()` on the call's return value.
+ * This can be overwritten per action. (Defaults to false.)
+ *
+ * @returns {Object} A resource "class" object with methods for the default set of resource actions
+ * optionally extended with custom `actions`. The default set contains these actions:
+ * ```js
+ * { 'get': {method:'GET'},
+ * 'save': {method:'POST'},
+ * 'query': {method:'GET', isArray:true},
+ * 'remove': {method:'DELETE'},
+ * 'delete': {method:'DELETE'} };
+ * ```
+ *
+ * Calling these methods invoke an {@link ng.$http} with the specified http method,
+ * destination and parameters. When the data is returned from the server then the object is an
+ * instance of the resource class. The actions `save`, `remove` and `delete` are available on it
+ * as methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
+ * read, update, delete) on server-side data like this:
+ * ```js
+ * var User = $resource('/user/:userId', {userId:'@id'});
+ * var user = User.get({userId:123}, function() {
+ * user.abc = true;
+ * user.$save();
+ * });
+ * ```
+ *
+ * It is important to realize that invoking a $resource object method immediately returns an
+ * empty reference (object or array depending on `isArray`). Once the data is returned from the
+ * server the existing reference is populated with the actual data. This is a useful trick since
+ * usually the resource is assigned to a model which is then rendered by the view. Having an empty
+ * object results in no rendering, once the data arrives from the server then the object is
+ * populated with the data and the view automatically re-renders itself showing the new data. This
+ * means that in most cases one never has to write a callback function for the action methods.
+ *
+ * The action methods on the class object or instance object can be invoked with the following
+ * parameters:
+ *
+ * - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
+ * - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
+ * - non-GET instance actions: `instance.$action([parameters], [success], [error])`
+ *
+ *
+ * Success callback is called with (value, responseHeaders) arguments, where the value is
+ * the populated resource instance or collection object. The error callback is called
+ * with (httpResponse) argument.
+ *
+ * Class actions return empty instance (with additional properties below).
+ * Instance actions return promise of the action.
+ *
+ * The Resource instances and collections have these additional properties:
+ *
+ * - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
+ * instance or collection.
+ *
+ * On success, the promise is resolved with the same resource instance or collection object,
+ * updated with data from server. This makes it easy to use in
+ * {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view
+ * rendering until the resource(s) are loaded.
+ *
+ * On failure, the promise is rejected with the {@link ng.$http http response} object, without
+ * the `resource` property.
+ *
+ * If an interceptor object was provided, the promise will instead be resolved with the value
+ * returned by the interceptor.
+ *
+ * - `$resolved`: `true` after first server interaction is completed (either with success or
+ * rejection), `false` before that. Knowing if the Resource has been resolved is useful in
+ * data-binding.
+ *
+ * The Resource instances and collections have these additional methods:
+ *
+ * - `$cancelRequest`: If there is a cancellable, pending request related to the instance or
+ * collection, calling this method will abort the request.
+ *
+ * The Resource instances have these additional methods:
+ *
+ * - `toJSON`: It returns a simple object without any of the extra properties added as part of
+ * the Resource API. This object can be serialized through {@link angular.toJson} safely
+ * without attaching Angular-specific fields. Notice that `JSON.stringify` (and
+ * `angular.toJson`) automatically use this method when serializing a Resource instance
+ * (see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON()_behavior)).
+ *
+ * @example
+ *
+ * # Credit card resource
+ *
+ * ```js
+ // Define CreditCard class
+ var CreditCard = $resource('/user/:userId/card/:cardId',
+ {userId:123, cardId:'@id'}, {
+ charge: {method:'POST', params:{charge:true}}
+ });
+
+ // We can retrieve a collection from the server
+ var cards = CreditCard.query(function() {
+ // GET: /user/123/card
+ // server returns: [ {id:456, number:'1234', name:'Smith'} ];
+
+ var card = cards[0];
+ // each item is an instance of CreditCard
+ expect(card instanceof CreditCard).toEqual(true);
+ card.name = "J. Smith";
+ // non GET methods are mapped onto the instances
+ card.$save();
+ // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
+ // server returns: {id:456, number:'1234', name: 'J. Smith'};
+
+ // our custom method is mapped as well.
+ card.$charge({amount:9.99});
+ // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
+ });
+
+ // we can create an instance as well
+ var newCard = new CreditCard({number:'0123'});
+ newCard.name = "Mike Smith";
+ newCard.$save();
+ // POST: /user/123/card {number:'0123', name:'Mike Smith'}
+ // server returns: {id:789, number:'0123', name: 'Mike Smith'};
+ expect(newCard.id).toEqual(789);
+ * ```
+ *
+ * The object returned from this function execution is a resource "class" which has "static" method
+ * for each action in the definition.
+ *
+ * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
+ * `headers`.
+ *
+ * @example
+ *
+ * # User resource
+ *
+ * When the data is returned from the server then the object is an instance of the resource type and
+ * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
+ * operations (create, read, update, delete) on server-side data.
+
+ ```js
+ var User = $resource('/user/:userId', {userId:'@id'});
+ User.get({userId:123}, function(user) {
+ user.abc = true;
+ user.$save();
+ });
+ ```
+ *
+ * It's worth noting that the success callback for `get`, `query` and other methods gets passed
+ * in the response that came from the server as well as $http header getter function, so one
+ * could rewrite the above example and get access to http headers as:
+ *
+ ```js
+ var User = $resource('/user/:userId', {userId:'@id'});
+ User.get({userId:123}, function(user, getResponseHeaders){
+ user.abc = true;
+ user.$save(function(user, putResponseHeaders) {
+ //user => saved user object
+ //putResponseHeaders => $http header getter
+ });
+ });
+ ```
+ *
+ * You can also access the raw `$http` promise via the `$promise` property on the object returned
+ *
+ ```
+ var User = $resource('/user/:userId', {userId:'@id'});
+ User.get({userId:123})
+ .$promise.then(function(user) {
+ $scope.user = user;
+ });
+ ```
+ *
+ * @example
+ *
+ * # Creating a custom 'PUT' request
+ *
+ * In this example we create a custom method on our resource to make a PUT request
+ * ```js
+ * var app = angular.module('app', ['ngResource', 'ngRoute']);
+ *
+ * // Some APIs expect a PUT request in the format URL/object/ID
+ * // Here we are creating an 'update' method
+ * app.factory('Notes', ['$resource', function($resource) {
+ * return $resource('/notes/:id', null,
+ * {
+ * 'update': { method:'PUT' }
+ * });
+ * }]);
+ *
+ * // In our controller we get the ID from the URL using ngRoute and $routeParams
+ * // We pass in $routeParams and our Notes factory along with $scope
+ * app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
+ function($scope, $routeParams, Notes) {
+ * // First get a note object from the factory
+ * var note = Notes.get({ id:$routeParams.id });
+ * $id = note.id;
+ *
+ * // Now call update passing in the ID first then the object you are updating
+ * Notes.update({ id:$id }, note);
+ *
+ * // This will PUT /notes/ID with the note object in the request payload
+ * }]);
+ * ```
+ *
+ * @example
+ *
+ * # Cancelling requests
+ *
+ * If an action's configuration specifies that it is cancellable, you can cancel the request related
+ * to an instance or collection (as long as it is a result of a "non-instance" call):
+ *
+ ```js
+ // ...defining the `Hotel` resource...
+ var Hotel = $resource('/api/hotel/:id', {id: '@id'}, {
+ // Let's make the `query()` method cancellable
+ query: {method: 'get', isArray: true, cancellable: true}
+ });
+
+ // ...somewhere in the PlanVacationController...
+ ...
+ this.onDestinationChanged = function onDestinationChanged(destination) {
+ // We don't care about any pending request for hotels
+ // in a different destination any more
+ this.availableHotels.$cancelRequest();
+
+ // Let's query for hotels in '<destination>'
+ // (calls: /api/hotel?location=<destination>)
+ this.availableHotels = Hotel.query({location: destination});
+ };
+ ```
+ *
+ */
+angular.module('ngResource', ['ng']).
+ provider('$resource', function() {
+ var PROTOCOL_AND_DOMAIN_REGEX = /^https?:\/\/[^\/]*/;
+ var provider = this;
+
+ /**
+ * @ngdoc property
+ * @name $resourceProvider#defaults
+ * @description
+ * Object containing default options used when creating `$resource` instances.
+ *
+ * The default values satisfy a wide range of usecases, but you may choose to overwrite any of
+ * them to further customize your instances. The available properties are:
+ *
+ * - **stripTrailingSlashes** – `{boolean}` – If true, then the trailing slashes from any
+ * calculated URL will be stripped.<br />
+ * (Defaults to true.)
+ * - **cancellable** – `{boolean}` – If true, the request made by a "non-instance" call will be
+ * cancelled (if not already completed) by calling `$cancelRequest()` on the call's return
+ * value. For more details, see {@link ngResource.$resource}. This can be overwritten per
+ * resource class or action.<br />
+ * (Defaults to false.)
+ * - **actions** - `{Object.<Object>}` - A hash with default actions declarations. Actions are
+ * high-level methods corresponding to RESTful actions/methods on resources. An action may
+ * specify what HTTP method to use, what URL to hit, if the return value will be a single
+ * object or a collection (array) of objects etc. For more details, see
+ * {@link ngResource.$resource}. The actions can also be enhanced or overwritten per resource
+ * class.<br />
+ * The default actions are:
+ * ```js
+ * {
+ * get: {method: 'GET'},
+ * save: {method: 'POST'},
+ * query: {method: 'GET', isArray: true},
+ * remove: {method: 'DELETE'},
+ * delete: {method: 'DELETE'}
+ * }
+ * ```
+ *
+ * #### Example
+ *
+ * For example, you can specify a new `update` action that uses the `PUT` HTTP verb:
+ *
+ * ```js
+ * angular.
+ * module('myApp').
+ * config(['resourceProvider', function ($resourceProvider) {
+ * $resourceProvider.defaults.actions.update = {
+ * method: 'PUT'
+ * };
+ * });
+ * ```
+ *
+ * Or you can even overwrite the whole `actions` list and specify your own:
+ *
+ * ```js
+ * angular.
+ * module('myApp').
+ * config(['resourceProvider', function ($resourceProvider) {
+ * $resourceProvider.defaults.actions = {
+ * create: {method: 'POST'}
+ * get: {method: 'GET'},
+ * getAll: {method: 'GET', isArray:true},
+ * update: {method: 'PUT'},
+ * delete: {method: 'DELETE'}
+ * };
+ * });
+ * ```
+ *
+ */
+ this.defaults = {
+ // Strip slashes by default
+ stripTrailingSlashes: true,
+
+ // Make non-instance requests cancellable (via `$cancelRequest()`)
+ cancellable: false,
+
+ // Default actions configuration
+ actions: {
+ 'get': {method: 'GET'},
+ 'save': {method: 'POST'},
+ 'query': {method: 'GET', isArray: true},
+ 'remove': {method: 'DELETE'},
+ 'delete': {method: 'DELETE'}
+ }
+ };
+
+ this.$get = ['$http', '$log', '$q', '$timeout', function($http, $log, $q, $timeout) {
+
+ var noop = angular.noop,
+ forEach = angular.forEach,
+ extend = angular.extend,
+ copy = angular.copy,
+ isFunction = angular.isFunction;
+
+ /**
+ * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
+ * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set
+ * (pchar) allowed in path segments:
+ * segment = *pchar
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ * pct-encoded = "%" HEXDIG HEXDIG
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ * / "*" / "+" / "," / ";" / "="
+ */
+ function encodeUriSegment(val) {
+ return encodeUriQuery(val, true).
+ replace(/%26/gi, '&').
+ replace(/%3D/gi, '=').
+ replace(/%2B/gi, '+');
+ }
+
+
+ /**
+ * This method is intended for encoding *key* or *value* parts of query component. We need a
+ * custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't
+ * have to be encoded per http://tools.ietf.org/html/rfc3986:
+ * query = *( pchar / "/" / "?" )
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ * pct-encoded = "%" HEXDIG HEXDIG
+ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ * / "*" / "+" / "," / ";" / "="
+ */
+ function encodeUriQuery(val, pctEncodeSpaces) {
+ return encodeURIComponent(val).
+ replace(/%40/gi, '@').
+ replace(/%3A/gi, ':').
+ replace(/%24/g, '$').
+ replace(/%2C/gi, ',').
+ replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
+ }
+
+ function Route(template, defaults) {
+ this.template = template;
+ this.defaults = extend({}, provider.defaults, defaults);
+ this.urlParams = {};
+ }
+
+ Route.prototype = {
+ setUrlParams: function(config, params, actionUrl) {
+ var self = this,
+ url = actionUrl || self.template,
+ val,
+ encodedVal,
+ protocolAndDomain = '';
+
+ var urlParams = self.urlParams = {};
+ forEach(url.split(/\W/), function(param) {
+ if (param === 'hasOwnProperty') {
+ throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name.");
+ }
+ if (!(new RegExp("^\\d+$").test(param)) && param &&
+ (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
+ urlParams[param] = {
+ isQueryParamValue: (new RegExp("\\?.*=:" + param + "(?:\\W|$)")).test(url)
+ };
+ }
+ });
+ url = url.replace(/\\:/g, ':');
+ url = url.replace(PROTOCOL_AND_DOMAIN_REGEX, function(match) {
+ protocolAndDomain = match;
+ return '';
+ });
+
+ params = params || {};
+ forEach(self.urlParams, function(paramInfo, urlParam) {
+ val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
+ if (angular.isDefined(val) && val !== null) {
+ if (paramInfo.isQueryParamValue) {
+ encodedVal = encodeUriQuery(val, true);
+ } else {
+ encodedVal = encodeUriSegment(val);
+ }
+ url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
+ return encodedVal + p1;
+ });
+ } else {
+ url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
+ leadingSlashes, tail) {
+ if (tail.charAt(0) == '/') {
+ return tail;
+ } else {
+ return leadingSlashes + tail;
+ }
+ });
+ }
+ });
+
+ // strip trailing slashes and set the url (unless this behavior is specifically disabled)
+ if (self.defaults.stripTrailingSlashes) {
+ url = url.replace(/\/+$/, '') || '/';
+ }
+
+ // then replace collapse `/.` if found in the last URL path segment before the query
+ // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
+ url = url.replace(/\/\.(?=\w+($|\?))/, '.');
+ // replace escaped `/\.` with `/.`
+ config.url = protocolAndDomain + url.replace(/\/\\\./, '/.');
+
+
+ // set params - delegate param encoding to $http
+ forEach(params, function(value, key) {
+ if (!self.urlParams[key]) {
+ config.params = config.params || {};
+ config.params[key] = value;
+ }
+ });
+ }
+ };
+
+
+ function resourceFactory(url, paramDefaults, actions, options) {
+ var route = new Route(url, options);
+
+ actions = extend({}, provider.defaults.actions, actions);
+
+ function extractParams(data, actionParams) {
+ var ids = {};
+ actionParams = extend({}, paramDefaults, actionParams);
+ forEach(actionParams, function(value, key) {
+ if (isFunction(value)) { value = value(data); }
+ ids[key] = value && value.charAt && value.charAt(0) == '@' ?
+ lookupDottedPath(data, value.substr(1)) : value;
+ });
+ return ids;
+ }
+
+ function defaultResponseInterceptor(response) {
+ return response.resource;
+ }
+
+ function Resource(value) {
+ shallowClearAndCopy(value || {}, this);
+ }
+
+ Resource.prototype.toJSON = function() {
+ var data = extend({}, this);
+ delete data.$promise;
+ delete data.$resolved;
+ return data;
+ };
+
+ forEach(actions, function(action, name) {
+ var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
+ var numericTimeout = action.timeout;
+ var cancellable = angular.isDefined(action.cancellable) ? action.cancellable :
+ (options && angular.isDefined(options.cancellable)) ? options.cancellable :
+ provider.defaults.cancellable;
+
+ if (numericTimeout && !angular.isNumber(numericTimeout)) {
+ $log.debug('ngResource:\n' +
+ ' Only numeric values are allowed as `timeout`.\n' +
+ ' Promises are not supported in $resource, because the same value would ' +
+ 'be used for multiple requests. If you are looking for a way to cancel ' +
+ 'requests, you should use the `cancellable` option.');
+ delete action.timeout;
+ numericTimeout = null;
+ }
+
+ Resource[name] = function(a1, a2, a3, a4) {
+ var params = {}, data, success, error;
+
+ /* jshint -W086 */ /* (purposefully fall through case statements) */
+ switch (arguments.length) {
+ case 4:
+ error = a4;
+ success = a3;
+ //fallthrough
+ case 3:
+ case 2:
+ if (isFunction(a2)) {
+ if (isFunction(a1)) {
+ success = a1;
+ error = a2;
+ break;
+ }
+
+ success = a2;
+ error = a3;
+ //fallthrough
+ } else {
+ params = a1;
+ data = a2;
+ success = a3;
+ break;
+ }
+ case 1:
+ if (isFunction(a1)) success = a1;
+ else if (hasBody) data = a1;
+ else params = a1;
+ break;
+ case 0: break;
+ default:
+ throw $resourceMinErr('badargs',
+ "Expected up to 4 arguments [params, data, success, error], got {0} arguments",
+ arguments.length);
+ }
+ /* jshint +W086 */ /* (purposefully fall through case statements) */
+
+ var isInstanceCall = this instanceof Resource;
+ var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
+ var httpConfig = {};
+ var responseInterceptor = action.interceptor && action.interceptor.response ||
+ defaultResponseInterceptor;
+ var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
+ undefined;
+ var timeoutDeferred;
+ var numericTimeoutPromise;
+
+ forEach(action, function(value, key) {
+ switch (key) {
+ default:
+ httpConfig[key] = copy(value);
+ break;
+ case 'params':
+ case 'isArray':
+ case 'interceptor':
+ case 'cancellable':
+ break;
+ }
+ });
+
+ if (!isInstanceCall && cancellable) {
+ timeoutDeferred = $q.defer();
+ httpConfig.timeout = timeoutDeferred.promise;
+
+ if (numericTimeout) {
+ numericTimeoutPromise = $timeout(timeoutDeferred.resolve, numericTimeout);
+ }
+ }
+
+ if (hasBody) httpConfig.data = data;
+ route.setUrlParams(httpConfig,
+ extend({}, extractParams(data, action.params || {}), params),
+ action.url);
+
+ var promise = $http(httpConfig).then(function(response) {
+ var data = response.data;
+
+ if (data) {
+ // Need to convert action.isArray to boolean in case it is undefined
+ // jshint -W018
+ if (angular.isArray(data) !== (!!action.isArray)) {
+ throw $resourceMinErr('badcfg',
+ 'Error in resource configuration for action `{0}`. Expected response to ' +
+ 'contain an {1} but got an {2} (Request: {3} {4})', name, action.isArray ? 'array' : 'object',
+ angular.isArray(data) ? 'array' : 'object', httpConfig.method, httpConfig.url);
+ }
+ // jshint +W018
+ if (action.isArray) {
+ value.length = 0;
+ forEach(data, function(item) {
+ if (typeof item === "object") {
+ value.push(new Resource(item));
+ } else {
+ // Valid JSON values may be string literals, and these should not be converted
+ // into objects. These items will not have access to the Resource prototype
+ // methods, but unfortunately there
+ value.push(item);
+ }
+ });
+ } else {
+ var promise = value.$promise; // Save the promise
+ shallowClearAndCopy(data, value);
+ value.$promise = promise; // Restore the promise
+ }
+ }
+ response.resource = value;
+
+ return response;
+ }, function(response) {
+ (error || noop)(response);
+ return $q.reject(response);
+ });
+
+ promise['finally'](function() {
+ value.$resolved = true;
+ if (!isInstanceCall && cancellable) {
+ value.$cancelRequest = angular.noop;
+ $timeout.cancel(numericTimeoutPromise);
+ timeoutDeferred = numericTimeoutPromise = httpConfig.timeout = null;
+ }
+ });
+
+ promise = promise.then(
+ function(response) {
+ var value = responseInterceptor(response);
+ (success || noop)(value, response.headers);
+ return value;
+ },
+ responseErrorInterceptor);
+
+ if (!isInstanceCall) {
+ // we are creating instance / collection
+ // - set the initial promise
+ // - return the instance / collection
+ value.$promise = promise;
+ value.$resolved = false;
+ if (cancellable) value.$cancelRequest = timeoutDeferred.resolve;
+
+ return value;
+ }
+
+ // instance call
+ return promise;
+ };
+
+
+ Resource.prototype['$' + name] = function(params, success, error) {
+ if (isFunction(params)) {
+ error = success; success = params; params = {};
+ }
+ var result = Resource[name].call(this, params, this, success, error);
+ return result.$promise || result;
+ };
+ });
+
+ Resource.bind = function(additionalParamDefaults) {
+ return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
+ };
+
+ return Resource;
+ }
+
+ return resourceFactory;
+ }];
+ });
+
+
+})(window, window.angular);
diff --git a/old/moon_dashboard/moon/static/moon/js/import.service.js b/old/moon_dashboard/moon/static/moon/js/import.service.js
new file mode 100755
index 00000000..d55c8a19
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/js/import.service.js
@@ -0,0 +1,27 @@
+(function () {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('moon.import.service', importService);
+
+ importService.$inject = ['moon.util.service', '$resource', 'moon.URI'];
+
+ function importService(util, $resource, URI) {
+ var host = URI.API;
+ var importResource = $resource(host + '/import/', {}, {
+ create: { method: 'POST' },
+ });
+
+ return {
+ importData: function importData(data) {
+ return importResource.create(null, data).$promise.then(success, util.displayErrorFunction('Unable to import data'));
+
+ function success(data) {
+ util.displaySuccess('Data imported');
+ }
+ }
+ }
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_dashboard/moon/static/moon/js/moon.module.js b/old/moon_dashboard/moon/static/moon/js/moon.module.js
new file mode 100755
index 00000000..c8b86439
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/js/moon.module.js
@@ -0,0 +1,29 @@
+/**
+# Copyright 2015 Orange
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+ */
+
+(function () {
+
+ 'use strict';
+
+ var moon = angular
+
+ .module('moon', [
+ 'ngResource',
+ ]).constant('moon.URI', {
+ API: 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}',
+ })
+
+})();
diff --git a/old/moon_dashboard/moon/static/moon/js/util.service.js b/old/moon_dashboard/moon/static/moon/js/util.service.js
new file mode 100755
index 00000000..29680a43
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/js/util.service.js
@@ -0,0 +1,140 @@
+(function () {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('moon.util.service', utilService);
+
+ utilService.$inject = ['horizon.framework.widgets.toast.service'];
+
+ function utilService(toast) {
+
+
+ return {
+ mapToArray: function mapToArray(map, action) {
+ var result = []
+ for (var key in map) {
+ if (map.hasOwnProperty(key)) {
+ var item = map[key];
+ item.id = key;
+ if (action != null) {
+ action(item);
+ }
+ result.push(item);
+ }
+ }
+ return result;
+ },
+
+ mapIdToItem: function mapIdToItem(array, map) {
+ if (array) {
+ for (var index = 0; index < array.length; index++) {
+ var id = array[index];
+ array[index] = map[id];
+ }
+ }
+ },
+
+ mapItemToId: function mapItemToId(array) {
+ if (array) {
+ for (var index = 0; index < array.length; index++) {
+ var item = array[index];
+ array[index] = item.id;
+ }
+ }
+ },
+
+ addToMap: function addToMap(array, map) {
+ if (array) {
+ for (var index = 0; index < array.length; index++) {
+ var item = array[index];
+ map[item.id] = item;
+ }
+ }
+ },
+
+ updateObject: function updateObject(object, newObject) {
+ for (var key in newObject) {
+ if (newObject.hasOwnProperty(key)) {
+ object[key] = newObject[key];
+ }
+ }
+ },
+
+ cleanObject: function cleanObject(object) {
+ for (var key in object) {
+ if (object.hasOwnProperty(key)) {
+ delete object[key];
+ }
+ }
+ },
+
+ pushAll: function pushAll(array, arrayToPush) {
+ Array.prototype.push.apply(array, arrayToPush);
+ },
+
+ indexOf: function indexOf(array, property, value) {
+ for (var i = 0; i < array.length; i += 1) {
+ if (array[i][property] === value) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ createInternal: function createInternal(data, array, map, action) {
+ var added = this.mapToArray(data, action)
+ this.addToMap(added, map);
+ this.pushAll(array, added);
+ return added;
+ },
+
+ updateInternal: function updateInternal(data, map, action) {
+ var updated = this.mapToArray(data, action)
+ var result = []
+ for (var index = 0; index < updated.length; index++) {
+ var item = updated[index];
+ this.updateObject(map[item.id], item)
+ result.push(map[item.id])
+ }
+ return result;
+ },
+
+ removeInternal: function removeInternal(id, array, map) {
+ var old = map[id];
+ delete map[old.id];
+ array.splice(array.indexOf(old), 1);
+ return old;
+ },
+
+ arrayToTitleMap: function arrayToTitleMap(array) {
+ return array.map(function (item) {
+ return { value: item.id, name: item.name }
+ }).sort(function (itemA, itemB) {
+ return itemA.name.localeCompare(itemB.name);
+ })
+ },
+
+ displayErrorFunction: function displayErrorFunction(message) {
+ return function(response) {
+ var text = gettext(message);
+ if (response && response.data && response.data.message) {
+ text += ' (' + response.data.message + ')'
+ }
+ toast.add('error', text);
+ }
+ },
+
+ displaySuccess: function displaySuccess(message) {
+ toast.add('success', gettext(message));
+ },
+
+ displayError: function displayError(message) {
+ toast.add('error', gettext(message));
+ },
+
+ }
+
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_dashboard/moon/static/moon/js/util.service.spec.js b/old/moon_dashboard/moon/static/moon/js/util.service.spec.js
new file mode 100755
index 00000000..d8e3ed31
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/js/util.service.spec.js
@@ -0,0 +1,86 @@
+(function () {
+ 'use strict';
+
+ describe('moon.util.service', function () {
+ var service;
+
+ beforeEach(module('horizon.app.core'));
+ beforeEach(module('horizon.framework'));
+ beforeEach(module('moon'));
+
+ beforeEach(inject(function ($injector) {
+ service = $injector.get('moon.util.service');
+ }));
+
+ it('should push all', function () {
+ var a1 = [0, 1, 2];
+ var a2 = [3, 4];
+ service.pushAll(a1, a2)
+
+ expect(a1.length).toBe(5);
+ expect(a1).toEqual([0, 1, 2, 3, 4]);
+ });
+
+ it('should index of', function () {
+ var a = [{ name: 'n0' }, { name: 'n1' }, { name: 'n2' }];
+ var result = service.indexOf(a, 'name', 'n1');
+
+ expect(result).toBe(1);
+ });
+
+ it('should map to array', function () {
+ var map = { "a": { name: "a" }, "b": { name: "b" } };
+ var result = service.mapToArray(map);
+
+ expect(result.length).toBe(2);
+ });
+
+ it('should map ID to item', function () {
+ var map = { "a": { name: "a" }, "b": { name: "b" } };
+ var array = ["a", "b"];
+ service.mapIdToItem(array, map);
+
+ expect(array.length).toBe(2);
+ expect(array[0].name).toBe("a");
+ expect(array[1].name).toBe("b");
+ });
+
+ it('should map item to ID', function () {
+ var array = [{ id: "a" }, { id: "b" }];
+ service.mapItemToId(array);
+
+ expect(array.length).toBe(2);
+ expect(array[0]).toBe("a");
+ expect(array[1]).toBe("b");
+ });
+
+ it('should add to map', function () {
+ var map = { "a": { name: "a" }, "b": { name: "b" } };
+ var array = [{ id: "c" }];
+ service.addToMap(array, map);
+
+ expect(map.c).toEqual({ id: "c" });
+ });
+
+ it('should update object', function () {
+ var object = { a: 1, b: "test" };
+ var update = { a: 2, c: "test2" };
+ service.updateObject(object, update);
+
+ expect(object.a).toBe(2);
+ expect(object.b).toBe("test");
+ expect(object.c).toBe("test2");
+ });
+
+ it('should clean object', function () {
+ var object = { a: 1, b: "test" };
+ service.cleanObject(object);
+
+ expect(object.a).not.toBeDefined();
+ expect(object.b).not.toBeDefined();
+ expect(object).toEqual({});
+ });
+ });
+
+
+})(); \ No newline at end of file
diff --git a/old/moon_dashboard/moon/static/moon/model/model.controller.js b/old/moon_dashboard/moon/static/moon/model/model.controller.js
new file mode 100644
index 00000000..99a7c7ed
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/model/model.controller.js
@@ -0,0 +1,316 @@
+(function () {
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('onReadFile', directive)
+ .controller('moon.model.controller', controller);
+
+ controller.$inject = ['moon.util.service', 'moon.model.service', 'moon.import.service', 'horizon.framework.widgets.form.ModalFormService'];
+
+ directive.$inject = ['$parse'];
+
+ function directive($parse) {
+ return {
+ restrict: 'A',
+ scope: false,
+ link: function (scope, element, attrs) {
+ element.bind('change', function (e) {
+
+ var onFileRead = $parse(attrs.onReadFile);
+ var reader = new FileReader();
+
+ reader.onload = function () {
+ var fileContents = reader.result;
+ scope.$apply(function () {
+ onFileRead(scope, {
+ 'contents': fileContents
+ });
+ });
+ };
+ reader.readAsText(element[0].files[0]);
+ });
+ }
+ };
+ }
+
+ var categoryMap = {
+ 'subject': {
+ addTitle: 'Add Subject Category',
+ removeTitleFromMetaRule: 'Are you sure to remove from meta rule this Subject Category?',
+ removeTitle: 'Are you sure to remove this Subject Category?',
+ listName: 'subject_categories',
+ serviceListName: 'subjectCategories'
+ },
+ 'object': {
+ addTitle: 'Add Object Category',
+ removeTitleFromMetaRule: 'Are you sure to remove from meta rule this Object Category?',
+ removeTitle: 'Are you sure to remove this Object Category?',
+ listName: 'object_categories',
+ serviceListName: 'objectCategories'
+ },
+ 'action': {
+ addTitle: 'Add Action Category',
+ removeTitleFromMetaRule: 'Are you sure to remove from meta rule this Action Category?',
+ removeTitle: 'Are you sure to remove this Action Category?',
+ listName: 'action_categories',
+ serviceListName: 'actionCategories'
+ },
+ }
+
+ function controller(util, modelService, importService, ModalFormService) {
+ var self = this;
+ self.model = modelService;
+ self.showOrphan = false;
+ 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');
+ })
+ }
+
+ self.createModel = function createModel() {
+ 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 model = { name: '', description: '' };
+ var config = {
+ title: gettext('Create Model'),
+ schema: schema,
+ form: ['name', { key: 'description', type: 'textarea' }],
+ model: model
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ modelService.createModel(form.model);
+ }
+ }
+
+ self.updateModel = function updateModel(model) {
+ 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 config = {
+ title: gettext('Update Model'),
+ schema: schema,
+ form: ['name', { key: 'description', type: 'textarea' }],
+ model: angular.copy(model)
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ modelService.updateModel(form.model);
+ }
+ }
+
+ self.removeModel = function removeModel(model) {
+ if (confirm(gettext('Are you sure to delete this Model?')))
+ 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: {
+ id: { type: "string", title: gettext("Select a Meta Rule:") }
+ },
+ required: ['id']
+ };
+ 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 },
+ {
+ 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) {
+ var metaRule = modelService.getMetaRule(form.model.id);
+ var modelCopy = angular.copy(model);
+ modelCopy.meta_rules.push(metaRule);
+ modelService.updateModel(modelCopy);
+ }
+ }
+
+ self.updateMetaRule = function updateMetaRule(metaRule) {
+ 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 metaRuleCopy = angular.copy(metaRule);
+ var config = {
+ title: gettext('Update Meta Rule'),
+ schema: schema,
+ form: ['name', { key: 'description', type: 'textarea' }],
+ model: metaRuleCopy
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ modelService.updateMetaRule(form.model);
+ }
+ }
+
+ self.removeMetaRuleFromModel = function removeMetaRuleFromModel(model, metaRule) {
+ if (confirm(gettext('Are you sure to remove this Meta Rule from model?'))) {
+ var modelCopy = angular.copy(model);
+ modelCopy.meta_rules.splice(model.meta_rules.indexOf(metaRule), 1);
+ modelService.updateModel(modelCopy);
+ }
+ }
+
+ self.removeMetaRule = function removeMetaRule(metaRule) {
+ if (confirm(gettext('Are you sure to remove this Meta Rule?'))) {
+ modelService.removeMetaRule(metaRule);
+ }
+ }
+
+ 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: {
+ id: { type: "string", title: gettext("Select a Category:") }
+ },
+ required: ['id']
+ };
+ 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 },
+ {
+ 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) {
+ var category = modelService.getCategory(type, form.model.id);
+ var metaRuleCopy = angular.copy(metaRule);
+ metaRuleCopy[typeValue.listName].push(category);
+ modelService.updateMetaRule(metaRuleCopy)
+ }
+ }
+
+ self.removeCategoryFromMetaRule = function removeCategoryFromMetaRule(type, metaRule, category) {
+ var typeValue = categoryMap[type];
+ if (confirm(gettext(typeValue.removeTitleFromMetaRule))) {
+ var metaRuleCopy = angular.copy(metaRule);
+ metaRuleCopy[typeValue.listName].splice(metaRule[typeValue.listName].indexOf(category), 1);
+ modelService.updateMetaRule(metaRuleCopy);
+ }
+ }
+
+ self.removeCategory = function removeCategory(type, category) {
+ var typeValue = categoryMap[type];
+ if (confirm(gettext(typeValue.removeTitle))) {
+ modelService.removeCategory(type, category);
+ }
+ }
+
+
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_dashboard/moon/static/moon/model/model.html b/old/moon_dashboard/moon/static/moon/model/model.html
new file mode 100644
index 00000000..97f08910
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/model/model.html
@@ -0,0 +1,139 @@
+<div ng-controller="moon.model.controller as ctrl">
+ <div ng-if="ctrl.model.orphanMetaRules.length
+ || ctrl.model.orphanSubjectCategories.length
+ || ctrl.model.orphanActionCategories.length
+ || ctrl.model.orphanObjectCategories.length" class="alert alert-dismissable alert-warning">
+ <button type="button" class="close" data-dismiss="alert" ng-click="ctrl.showOrphan=false">×</button>
+ <h4 translate>Warning!</h4>
+ <p translate>
+ Some metarules or categories are orphan, please check them and delete them if necessary.
+ <a href="" ng-click="ctrl.showOrphan=true" ng-show="!ctrl.showOrphan" translate>Show orphans</a>
+ <a href="" ng-click="ctrl.showOrphan=false" ng-show="ctrl.showOrphan" translate>Hide orphans</a>
+ </p>
+ </div>
+
+ <div class="row" ng-show="ctrl.showOrphan">
+ <div class="list-group col-lg-3" ng-if="ctrl.model.orphanMetaRules.length">
+ <h3 class="list-group-item active" translate>Orphan Meta rules</h3>
+ <div ng-repeat="metaRule in ctrl.model.orphanMetaRules | orderBy:'name'" class="list-group-item">
+ <h4 class="list-group-item-heading inline">{$ metaRule.name $}</h4>
+ <button type="button" class="fa fa-trash pull-right" ng-click="ctrl.removeMetaRule(metaRule)" title="{$ 'Remove Meta rule' | translate $}"></button>
+ <p class="list-group-item-text">{$ metaRule.description $}</p>
+ </div>
+ </div>
+
+ <div class="list-group col-lg-3" ng-if="ctrl.model.orphanSubjectCategories.length">
+ <h3 class="list-group-item active" translate>Orphan Subject categories</h3>
+ <div ng-repeat="subject in ctrl.model.orphanSubjectCategories | orderBy:'name'" class="list-group-item">
+ <h4 class="list-group-item-heading inline">{$ subject.name $}</h4>
+ <button type="button" class="fa fa-trash pull-right" ng-click="ctrl.removeCategory('subject', subject)" title="{$ 'Remove Subject category' | translate $}"></button>
+ <p class="list-group-item-text">{$ subject.description $}</p>
+ </div>
+ </div>
+
+ <div class="list-group col-lg-3" ng-if="ctrl.model.orphanObjectCategories.length">
+ <h3 class="list-group-item active" translate>Orphan Object categories</h3>
+ <div ng-repeat="object in ctrl.model.orphanObjectCategories | orderBy:'name'" class="list-group-item">
+ <h4 class="list-group-item-heading inline">{$ object.name $}</h4>
+ <button type="button" class="fa fa-trash pull-right" ng-click="ctrl.removeCategory('object', object)" title="{$ 'Remove Object category' | translate $}"></button>
+ <p class="list-group-item-text">{$ object.description $}</p>
+ </div>
+ </div>
+
+ <div class="list-group col-lg-3" ng-if="ctrl.model.orphanActionCategories.length">
+ <h3 class="list-group-item active" translate>Orphan Action categories</h3>
+ <div ng-repeat="action in ctrl.model.orphanActionCategories | orderBy:'name'" class="list-group-item">
+ <h4 class="list-group-item-heading inline">{$ action.name $}</h4>
+ <button type="button" class="fa fa-trash pull-right" ng-click="ctrl.removeCategory('action', action)" title="{$ 'Remove Action category' | translate $}"></button>
+ <p class="list-group-item-text">{$ action.description $}</p>
+ </div>
+ </div>
+ </div>
+
+ <div class="clearfix list-group">
+ <div class="pull-right">
+ <input type="search" class="form-control filter" placeholder="Filter" ng-model="filterText">
+ <button type="button" class="btn btn-default" ng-click="ctrl.createModel()">
+ <span class="fa fa-plus"></span>
+ <translate>Create Model</translate>
+ </button>
+ <label for="file" class="label-file btn btn-primary">
+ <span class="fa fa-upload"></span>
+ <translate>Import</translate>
+ </label>
+ <input id="file" class="input-file" type="file" on-read-file="ctrl.importData(contents)" accept="application/json,.json"/>
+ </div>
+ </div>
+
+
+ <div class="list-group">
+ <div ng-repeat="model in ctrl.model.models | orderBy:'name' | filter:filterText " class="list-group-item">
+ <h3 class="list-group-item-heading inline">{$ model.name $}</h3>
+ <div class="pull-right">
+ <button type="button" class="fa fa-trash" ng-click="ctrl.removeModel(model)" title="{$ 'Remove Model' | translate $}"></button>
+ <button type="button" class="fa fa-edit" ng-click="ctrl.updateModel(model)" title="{$ 'Edit Model' | translate $}"></button>
+ </div>
+ <p class="list-group-item-text">{$ model.description $}</p>
+ <details class="list-group-item-text">
+ <summary>
+ <h4 class="inline">{$ model.meta_rules.length $}
+ <translate>meta rule(s)</translate>
+ </h4>
+ <button type="button" class="fa fa-plus " ng-click="ctrl.addMetaRule(model)" title="{$ 'Add Meta Rule' | translate $}"></button>
+ </summary>
+ <div class="list-group">
+ <div ng-repeat="metaRule in model.meta_rules | orderBy:'name'" class="list-group-item">
+ <h3 class="list-group-item-heading inline">{$ metaRule.name $}</h3>
+ <div class="pull-right">
+ <button type="button" class="fa fa-trash" ng-click="ctrl.removeMetaRuleFromModel(model, metaRule)" title="{$ 'Remove Meta Rule' | translate $}"></button>
+ <button type="button" class="fa fa-edit" ng-click="ctrl.updateMetaRule(metaRule)" title="{$ 'Edit Meta Rule' | translate $}"></button>
+ </div>
+ <p class="list-group-item-text">{$ metaRule.description $}</p>
+ <p class="list-group-item-text">
+ <table class="table categories">
+ <thead>
+ <tr>
+ <th>
+ <span translate>Subjects</span>
+ <button type="button" class="fa fa-plus pull-right" ng-click="ctrl.addCategory('subject', metaRule)" title="{$ 'Add Subject' | translate $}"></button>
+ </th>
+ <th>
+ <span translate>Objects</span>
+ <button type="button" class="fa fa-plus pull-right" ng-click="ctrl.addCategory('object', metaRule)" title="{$ 'Add Object' | translate $}"></button>
+ </th>
+ <th>
+ <span translate>Actions</span>
+ <button type="button" class="fa fa-plus pull-right" ng-click="ctrl.addCategory('action', metaRule)" title="{$ 'Add Action' | translate $}"></button>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <p ng-repeat="category in metaRule.subject_categories">
+ <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 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 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>
+ </tr>
+ </tbody>
+ </table>
+ </p>
+ </div>
+ </div>
+ </details>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/old/moon_dashboard/moon/static/moon/model/model.service.js b/old/moon_dashboard/moon/static/moon/model/model.service.js
new file mode 100755
index 00000000..986eb6b1
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/model/model.service.js
@@ -0,0 +1,291 @@
+(function () {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('moon.model.service', modelService);
+
+ modelService.$inject = ['moon.util.service', '$resource', 'moon.URI', '$q'];
+
+ function modelService(util, $resource, URI, $q) {
+ var host = URI.API;
+ var modelResource = $resource(host + '/models/' + ':id', {}, {
+ get: { method: 'GET' },
+ query: { method: 'GET' },
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' },
+ update: { method: 'PATCH' }
+ });
+
+ var metaRuleResource = $resource(host + '/meta_rules/' + ':id', {}, {
+ query: { method: 'GET' },
+ get: { method: 'GET' },
+ update: { method: 'PATCH' },
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ });
+
+ var subjectCategoryResource = $resource(host + '/subject_categories/' + ':id', {}, {
+ query: { method: 'GET' },
+ get: { method: 'GET' },
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ });
+
+ var objectCategoryResource = $resource(host + '/object_categories/' + ':id', {}, {
+ query: { method: 'GET' },
+ get: { method: 'GET' },
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ });
+
+ var actionCategoryResource = $resource(host + '/action_categories/' + ':id', {}, {
+ query: { method: 'GET' },
+ get: { method: 'GET' },
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ });
+
+ var modelsMap = {};
+ var metaRulesMap = {};
+ var subjectCategoriesMap = {};
+ var objectCategoriesMap = {};
+ var actionCategoriesMap = {};
+ var models = [];
+ var metaRules = [];
+ var orphanMetaRules = [];
+ var subjectCategories = [];
+ var objectCategories = [];
+ var actionCategories = [];
+ var orphanSubjectCategories = [];
+ var orphanObjectCategories = [];
+ var orphanActionCategories = [];
+
+ var categoryMap = {
+ 'subject': {
+ resource: subjectCategoryResource,
+ map: subjectCategoriesMap,
+ list: subjectCategories,
+ listName: 'subject_categories'
+ },
+ 'object': {
+ resource: objectCategoryResource,
+ map: objectCategoriesMap,
+ list: objectCategories,
+ listName: 'object_categories'
+ },
+ 'action': {
+ resource: actionCategoryResource,
+ map: actionCategoriesMap,
+ list: actionCategories,
+ listName: 'action_categories'
+ }
+ }
+
+ function loadModels() {
+ var queries = {
+ subjectCategories: subjectCategoryResource.query().$promise,
+ objectCategories: objectCategoryResource.query().$promise,
+ actionCategories: actionCategoryResource.query().$promise,
+ metaRules: metaRuleResource.query().$promise,
+ models: modelResource.query().$promise,
+ }
+
+ var result = $q.all(queries).then(function (result) {
+ createModels(result.models, result.metaRules, result.subjectCategories, result.objectCategories, result.actionCategories)
+ console.log('moon', 'models initialized')
+ })
+
+ return result;
+ }
+
+ function createModels(modelsData, metarulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData) {
+ util.cleanObject(modelsMap);
+ util.cleanObject(metaRulesMap);
+ util.cleanObject(subjectCategoriesMap);
+ util.cleanObject(objectCategoriesMap);
+ util.cleanObject(actionCategoriesMap);
+ models.splice(0, models.length);
+ metaRules.splice(0, metaRules.length);
+ subjectCategories.splice(0, subjectCategories.length);
+ objectCategories.splice(0, objectCategories.length);
+ actionCategories.splice(0, actionCategories.length);
+ if (subjectCategoriesData.subject_categories) createCategoryInternal('subject', subjectCategoriesData.subject_categories);
+ if (objectCategoriesData.object_categories) createCategoryInternal('object', objectCategoriesData.object_categories);
+ if (actionCategoriesData.action_categories) createCategoryInternal('action', actionCategoriesData.action_categories);
+ if (metarulesData.meta_rules) createMetaRuleInternal(metarulesData.meta_rules);
+ if (modelsData.models) createModelInternal(modelsData.models);
+ updateOrphan();
+ }
+
+ function mapModel(model) {
+ util.mapIdToItem(model.meta_rules, metaRulesMap);
+ }
+
+ function createModelInternal(data) {
+ return util.createInternal(data, models, modelsMap, mapModel);
+ }
+
+ function updateModelInternal(data) {
+ return util.updateInternal(data, modelsMap, mapModel);
+ }
+
+ function removeModelInternal(id) {
+ return util.removeInternal(id, models, modelsMap);
+ }
+
+ function mapMetaRule(metaRule) {
+ util.mapIdToItem(metaRule.subject_categories, subjectCategoriesMap);
+ util.mapIdToItem(metaRule.object_categories, objectCategoriesMap);
+ util.mapIdToItem(metaRule.action_categories, actionCategoriesMap);
+ }
+
+ function createMetaRuleInternal(data) {
+ return util.createInternal(data, metaRules, metaRulesMap, mapMetaRule);
+ }
+
+ function updateMetaRuleInternal(data) {
+ return util.updateInternal(data, metaRulesMap, mapMetaRule);
+ }
+
+ function removeMetaRuleInternal(id) {
+ return util.removeInternal(id, metaRules, metaRulesMap);
+ }
+
+ function createCategoryInternal(type, data) {
+ var categoryValue = categoryMap[type];
+ return util.createInternal(data, categoryValue.list, categoryValue.map)
+ }
+
+ function removeCategoryInternal(type, id) {
+ var categoryValue = categoryMap[type];
+ return util.removeInternal(id, categoryValue.list, categoryValue.map);
+ }
+
+ function updateOrphan() {
+ updateOrphanInternal(metaRules, orphanMetaRules, models, "meta_rules");
+ updateOrphanInternal(subjectCategories, orphanSubjectCategories, metaRules, "subject_categories");
+ updateOrphanInternal(objectCategories, orphanObjectCategories, metaRules, "object_categories");
+ updateOrphanInternal(actionCategories, orphanActionCategories, metaRules, "action_categories");
+ }
+
+ function updateOrphanInternal(list, orphanList, parentList, childListName) {
+ orphanList.splice(0, orphanList.length);
+ util.pushAll(orphanList, list);
+ for (var i = 0; i < parentList.length; i++) {
+ var parent = parentList[i];
+ var children = parent[childListName];
+ if (children) {
+ for (var j = 0; j < children.length; j++) {
+ var child = children[j];
+ var notOrphanIndex = util.indexOf(orphanList, "id", child.id);
+ if (notOrphanIndex >= 0) {
+ orphanList.splice(notOrphanIndex, 1);
+ }
+ }
+ }
+ }
+ }
+
+
+ return {
+ initialize: loadModels,
+ createModels: createModels,
+ models: models,
+ metaRules: metaRules,
+ orphanMetaRules: orphanMetaRules,
+ orphanSubjectCategories: orphanSubjectCategories,
+ orphanObjectCategories: orphanObjectCategories,
+ orphanActionCategories: orphanActionCategories,
+ subjectCategories: subjectCategories,
+ objectCategories: objectCategories,
+ actionCategories: actionCategories,
+ getModel: function getModel(id) {
+ return modelsMap[id];
+ },
+ createModel: function createModel(model) {
+ model.meta_rules = [];
+ modelResource.create(null, model, success, util.displayErrorFunction('Unable to create model'));
+
+ function success(data) {
+ createModelInternal(data.models);
+ util.displaySuccess('Model created');
+ }
+ },
+ removeModel: function removeModel(model) {
+ modelResource.remove({ id: model.id }, null, success, util.displayErrorFunction('Unable to remove model'));
+
+ function success(data) {
+ removeModelInternal(model.id);
+ updateOrphan();
+ util.displaySuccess('Model removed');
+ }
+ },
+ updateModel: function updateModel(model) {
+ util.mapItemToId(model.meta_rules)
+ modelResource.update({ id: model.id }, model, success, util.displayErrorFunction('Unable to update model'));
+
+ function success(data) {
+ updateModelInternal(data.models)
+ updateOrphan();
+ util.displaySuccess('Model updated');
+ }
+ },
+ getMetaRule: function getMetaRule(id) {
+ 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];
+ }, util.displayErrorFunction('Unable to create meta rule'))
+ },
+ updateMetaRule: function updateMetaRule(metaRule) {
+ util.mapItemToId(metaRule.subject_categories);
+ util.mapItemToId(metaRule.object_categories);
+ util.mapItemToId(metaRule.action_categories);
+ metaRuleResource.update({ id: metaRule.id }, metaRule, success, util.displayErrorFunction('Unable to update meta rule'));
+
+ function success(data) {
+ updateMetaRuleInternal(data.meta_rules);
+ updateOrphan();
+ util.displaySuccess('Meta Rule updated');
+ }
+ },
+ removeMetaRule: function removeMetaRule(metaRule) {
+ metaRuleResource.remove({ id: metaRule.id }, null, success, util.displayErrorFunction('Unable to remove meta rule'));
+
+ function success(data) {
+ removeMetaRuleInternal(metaRule.id);
+ updateOrphan();
+ util.displaySuccess('Meta Rule removed');
+ }
+ },
+ getCategory: function getCategory(type, id) {
+ return categoryMap[type].map[id];
+ },
+ createCategory: function createCategory(type, category) {
+ var categoryValue = categoryMap[type];
+ return categoryValue.resource.create({}, category).$promise.then(function (data) {
+ util.displaySuccess('Category created');
+ return createCategoryInternal(type, data[categoryValue.listName])[0];
+ }, util.displayErrorFunction('Unable to create category'))
+ },
+ removeCategory: function removeCategory(type, category) {
+ var categoryValue = categoryMap[type];
+ categoryValue.resource.remove({ id: category.id }, null, success, util.displayErrorFunction('Unable to remove category'));
+
+ function success(data) {
+ removeCategoryInternal(type, category.id);
+ updateOrphan();
+ util.displaySuccess('Category removed');
+ }
+ },
+ }
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_dashboard/moon/static/moon/model/model.service.spec.js b/old/moon_dashboard/moon/static/moon/model/model.service.spec.js
new file mode 100755
index 00000000..04d47793
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/model/model.service.spec.js
@@ -0,0 +1,288 @@
+(function () {
+ 'use strict';
+
+ describe('moon.model.service', function () {
+ var service, $httpBackend, URI;
+ var modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData;
+
+ function initData() {
+ modelsData = {
+ models:
+ { 'modelId1': { name: 'model1', description: 'mDescription1', meta_rules: ['metaRuleId1'] } }
+ };
+
+ subjectCategoriesData = {
+ subject_categories:
+ {
+ 'subjectCategoryId1': { name: 'subjectCategory1', description: 'scDescription1' },
+ 'subjectCategoryId2': { name: 'subjectCategory2', description: 'scDescription2' }
+ },
+ };
+ objectCategoriesData = {
+ object_categories:
+ {
+ 'objectCategoryId1': { name: 'objectCategory1', description: 'ocDescription1' },
+ 'objectCategoryId2': { name: 'objectCategory2', description: 'ocDescription2' }
+ }
+ };
+ actionCategoriesData = {
+ action_categories:
+ {
+ 'actionCategoryId1': { name: 'actionCategory1', description: 'acDescription1' },
+ 'actionCategoryId2': { name: 'actionCategory2', description: 'acDescription2' }
+ }
+ };
+ metaRulesData = {
+ meta_rules:
+ {
+ 'metaRuleId1': { name: 'metaRule1', description: 'mrDescription1', subject_categories: ['subjectCategoryId1'], object_categories: ['objectCategoryId1'], action_categories: ['actionCategoryId1'] },
+ 'metaRuleId2': { name: 'metaRule2', description: 'mrDescription2', subject_categories: [], object_categories: [], action_categories: [] }
+ }
+ };
+ }
+
+ beforeEach(module('horizon.app.core'));
+ beforeEach(module('horizon.framework'));
+ beforeEach(module('moon'));
+
+ beforeEach(inject(function ($injector) {
+ service = $injector.get('moon.model.service');
+ $httpBackend = $injector.get('$httpBackend');
+ URI = $injector.get('moon.URI');
+ }));
+
+ afterEach(function () {
+ $httpBackend.verifyNoOutstandingExpectation();
+ $httpBackend.verifyNoOutstandingRequest();
+ });
+
+ it('should initialize', function () {
+ initData();
+ $httpBackend.expectGET(URI.API + '/subject_categories').respond(200, subjectCategoriesData);
+ $httpBackend.expectGET(URI.API + '/object_categories').respond(200, objectCategoriesData);
+ $httpBackend.expectGET(URI.API + '/action_categories').respond(200, actionCategoriesData);
+ $httpBackend.expectGET(URI.API + '/meta_rules').respond(200, metaRulesData);
+ $httpBackend.expectGET(URI.API + '/models').respond(200, modelsData);
+
+ service.initialize();
+ $httpBackend.flush();
+
+ expect(service.models.length).toBe(1);
+ var model = service.models[0];
+ expect(model.id).toBe('modelId1');
+ expect(model.name).toBe('model1');
+ expect(model.description).toBe('mDescription1');
+
+ expect(service.metaRules.length).toBe(2);
+ expect(model.meta_rules.length).toBe(1);
+ var metaRule = model.meta_rules[0];
+ expect(metaRule.id).toBe('metaRuleId1');
+ expect(metaRule.name).toBe('metaRule1');
+ expect(metaRule.description).toBe('mrDescription1');
+
+ expect(service.subjectCategories.length).toBe(2);
+ expect(metaRule.subject_categories.length).toBe(1);
+ var subjectCategory = metaRule.subject_categories[0];
+ expect(subjectCategory.id).toBe('subjectCategoryId1');
+ expect(subjectCategory.name).toBe('subjectCategory1');
+ expect(subjectCategory.description).toBe('scDescription1');
+
+ expect(service.objectCategories.length).toBe(2);
+ expect(metaRule.object_categories.length).toBe(1);
+ var objectCategory = metaRule.object_categories[0];
+ expect(objectCategory.id).toBe('objectCategoryId1');
+ expect(objectCategory.name).toBe('objectCategory1');
+ expect(objectCategory.description).toBe('ocDescription1');
+
+ expect(service.actionCategories.length).toBe(2);
+ expect(metaRule.action_categories.length).toBe(1);
+ var actionCategory = metaRule.action_categories[0];
+ expect(actionCategory.id).toBe('actionCategoryId1');
+ expect(actionCategory.name).toBe('actionCategory1');
+ expect(actionCategory.description).toBe('acDescription1');
+
+ expect(service.orphanMetaRules.length).toBe(1);
+ metaRule = service.orphanMetaRules[0];
+ expect(metaRule.id).toBe('metaRuleId2');
+ expect(metaRule.name).toBe('metaRule2');
+ expect(metaRule.description).toBe('mrDescription2');
+
+ expect(service.orphanSubjectCategories.length).toBe(1);
+ subjectCategory = service.orphanSubjectCategories[0];
+ expect(subjectCategory.id).toBe('subjectCategoryId2');
+ expect(subjectCategory.name).toBe('subjectCategory2');
+ expect(subjectCategory.description).toBe('scDescription2');
+
+ expect(service.orphanObjectCategories.length).toBe(1);
+ objectCategory = service.orphanObjectCategories[0];
+ expect(objectCategory.id).toBe('objectCategoryId2');
+ expect(objectCategory.name).toBe('objectCategory2');
+ expect(objectCategory.description).toBe('ocDescription2');
+
+ expect(service.orphanActionCategories.length).toBe(1);
+ actionCategory = service.orphanActionCategories[0];
+ expect(actionCategory.id).toBe('actionCategoryId2');
+ expect(actionCategory.name).toBe('actionCategory2');
+ expect(actionCategory.description).toBe('acDescription2');
+
+ });
+
+
+
+ it('should create model', function () {
+ var modelCreatedData = {
+ models:
+ { 'modelId1': { name: 'model1', description: 'mDescription1', meta_rules: [] } }
+ };
+
+ $httpBackend.expectPOST(URI.API + '/models').respond(200, modelCreatedData);
+
+ service.createModel({ name: 'model1', description: 'mDescription1' });
+ $httpBackend.flush();
+
+ expect(service.models.length).toBe(1);
+ var model = service.models[0];
+ expect(model.id).toBe('modelId1');
+ expect(model.name).toBe('model1');
+ expect(model.description).toBe('mDescription1');
+ });
+
+ it('should remove model', function () {
+ initData();
+ service.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+
+ $httpBackend.expectDELETE(URI.API + '/models/modelId1').respond(200);
+
+ service.removeModel({ id: 'modelId1' });
+ $httpBackend.flush();
+
+ expect(service.models.length).toBe(0);
+
+ expect(service.orphanMetaRules.length).toBe(2);
+ });
+
+ it('should update model', function () {
+ initData();
+ var modelUpdatedData = {
+ models:
+ { 'modelId1': { name: 'model2', description: 'mDescription2', meta_rules: ['metaRuleId2'] } }
+ };
+ service.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+
+ $httpBackend.expectPATCH(URI.API + '/models/modelId1').respond(200, modelUpdatedData);
+
+ service.updateModel({ id: 'modelId1', name: 'model2', description: 'mDescription2', meta_rules: service.getMetaRule('metaRuleId2') });
+ $httpBackend.flush();
+
+ expect(service.models.length).toBe(1);
+ var model = service.models[0];
+ expect(model.id).toBe('modelId1');
+ expect(model.name).toBe('model2');
+ expect(model.description).toBe('mDescription2');
+
+ expect(model.meta_rules.length).toBe(1);
+ var metaRule = model.meta_rules[0];
+ expect(metaRule.id).toBe('metaRuleId2');
+
+ expect(service.orphanMetaRules.length).toBe(1);
+ metaRule = service.orphanMetaRules[0];
+ expect(metaRule.id).toBe('metaRuleId1');
+ });
+
+ it('should create meta rule', function () {
+ var metaRuleCreatedData = {
+ meta_rules:
+ { 'metaRuleId1': { name: 'metaRule1', description: 'mrDescription1' } }
+ };
+
+ $httpBackend.expectPOST(URI.API + '/meta_rules').respond(200, metaRuleCreatedData);
+
+ service.createMetaRule({ name: 'metaRule1', description: 'mrDescription1' });
+ $httpBackend.flush();
+
+ expect(service.metaRules.length).toBe(1);
+ var metaRule = service.metaRules[0];
+ expect(metaRule.id).toBe('metaRuleId1');
+ expect(metaRule.name).toBe('metaRule1');
+ expect(metaRule.description).toBe('mrDescription1');
+ });
+
+ it('should update meta rule', function () {
+ initData();
+ var metaRuleUpdatedData = {
+ meta_rules:
+ { 'metaRuleId1': { name: 'metaRule2', description: 'mrDescription2', subject_categories: ['subjectCategoryId2'], object_categories: ['objectCategoryId2'], action_categories: ['actionCategoryId2'] } }
+ };
+ service.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+
+ $httpBackend.expectPATCH(URI.API + '/meta_rules/metaRuleId1').respond(200, metaRuleUpdatedData);
+
+ service.updateMetaRule({ id: 'metaRuleId1', name: 'metaRule2', description: 'mrDescription2', subject_categories: [service.getCategory('subject', 'subjectCategoryId2')], object_categories: [service.getCategory('object', 'objectCategoryId2')], action_categories: [service.getCategory('action','actionCategoryId2')] });
+ $httpBackend.flush();
+
+ var metaRule = service.getMetaRule('metaRuleId1');
+ expect(metaRule.id).toBe('metaRuleId1');
+ expect(metaRule.name).toBe('metaRule2');
+ expect(metaRule.description).toBe('mrDescription2');
+
+ expect(service.orphanSubjectCategories.length).toBe(1);
+ var subjectCategory = service.orphanSubjectCategories[0];
+ expect(subjectCategory.id).toBe('subjectCategoryId1');
+
+ expect(service.orphanObjectCategories.length).toBe(1);
+ var objectCategory = service.orphanObjectCategories[0];
+ expect(objectCategory.id).toBe('objectCategoryId1');
+
+ expect(service.orphanActionCategories.length).toBe(1);
+ var actionCategory = service.orphanActionCategories[0];
+ expect(actionCategory.id).toBe('actionCategoryId1');
+ });
+
+ it('should remove meta rule', function () {
+ initData();
+ service.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+
+ $httpBackend.expectDELETE(URI.API + '/meta_rules/metaRuleId2').respond(200);
+
+ service.removeMetaRule(service.getMetaRule('metaRuleId2'));
+ $httpBackend.flush();
+
+ expect(service.metaRules.length).toBe(1);
+ expect(service.orphanMetaRules.length).toBe(0);
+ });
+
+ it('should create category', function () {
+ var categoryCreatedData = {
+ subject_categories:
+ { 'subjectCategoryId1': { name: 'subjectCategory1', description: 'scDescription1' } }
+ };
+
+ $httpBackend.expectPOST(URI.API + '/subject_categories').respond(200, categoryCreatedData);
+
+ service.createCategory('subject', { name: 'subjectCategory1', description: 'scDescription1' });
+ $httpBackend.flush();
+
+ expect(service.subjectCategories.length).toBe(1);
+ var subjectCategory = service.subjectCategories[0];
+ expect(subjectCategory.id).toBe('subjectCategoryId1');
+ expect(subjectCategory.name).toBe('subjectCategory1');
+ expect(subjectCategory.description).toBe('scDescription1');
+ });
+
+ it('should remove category', function () {
+ initData();
+ service.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+
+ $httpBackend.expectDELETE(URI.API + '/subject_categories/subjectCategoryId2').respond(200);
+
+ service.removeCategory('subject', service.getCategory('subject', 'subjectCategoryId2'));
+ $httpBackend.flush();
+
+ expect(service.subjectCategories.length).toBe(1);
+ expect(service.orphanSubjectCategories.length).toBe(0);
+ });
+
+ });
+
+
+})(); \ No newline at end of file
diff --git a/old/moon_dashboard/moon/static/moon/pdp/pdp.controller.js b/old/moon_dashboard/moon/static/moon/pdp/pdp.controller.js
new file mode 100644
index 00000000..1859b1f8
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/pdp/pdp.controller.js
@@ -0,0 +1,125 @@
+(function () {
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('moon.pdp.controller',
+ controller);
+
+ controller.$inject = ['moon.util.service', 'moon.pdp.service', 'horizon.framework.widgets.form.ModalFormService'];
+
+ function controller(util, pdpService, ModalFormService) {
+ var self = this;
+ self.model = pdpService;
+ pdpService.initialize();
+
+ self.createPdp = function createPdp() {
+ 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 pdp = { name: '', description: '' };
+ var config = {
+ title: gettext('Create PDP'),
+ schema: schema,
+ form: ['name', { key: 'description', type: 'textarea' }],
+ model: pdp
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ pdpService.createPdp(form.model);
+ }
+ }
+
+ self.updatePdp = function updatePdp(pdp) {
+ 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 config = {
+ title: gettext('Update PDP'),
+ schema: schema,
+ form: ['name', { key: 'description', type: 'textarea' }],
+ model: angular.copy(pdp)
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ pdpService.updatePdp(form.model);
+ }
+ }
+
+ self.removePdp = function removePdp(pdp) {
+ if (confirm(gettext('Are you sure to delete this PDP?')))
+ pdpService.removePdp(pdp);
+ }
+
+ self.addPolicy = function addPolicy(pdp) {
+ var schema = {
+ type: "object",
+ properties: {
+ id: { type: "string", title: gettext("Select a Policy:") }
+ },
+ required: ['id']
+ };
+ var titleMap = util.arrayToTitleMap(pdpService.policies)
+ var config = {
+ title: gettext('Add Policy'),
+ schema: schema,
+ form: [{ key: 'id', type: 'select', titleMap: titleMap }],
+ model: {}
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ var pdpCopy = angular.copy(pdp);
+ pdpCopy.security_pipeline.push(pdpService.getPolicy(form.model.id));
+ pdpService.updatePdp(pdpCopy);
+ }
+ }
+
+ self.removePolicyFromPdp = function removePolicyFromPdp(pdp, policy) {
+ if (confirm(gettext('Are you sure to remove this Policy from PDP?'))) {
+ var pdpCopy = angular.copy(pdp);
+ pdpCopy.security_pipeline.splice(pdp.security_pipeline.indexOf(policy), 1);
+ pdpService.updatePdp(pdpCopy);
+ }
+ }
+
+ self.changeProject = function changeProject(pdp) {
+ var schema = {
+ type: "object",
+ properties: {
+ id: { type: "string", title: gettext("Select a Project:") }
+ },
+ required: ['id']
+ };
+ var model = {id : pdp.keystone_project_id};
+
+ var titleMap = util.arrayToTitleMap(pdpService.projects)
+ var config = {
+ title: gettext('Change Project'),
+ schema: schema,
+ form: [{ key: 'id', type: 'select', titleMap: titleMap }],
+ model: model
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ var pdpCopy = angular.copy(pdp);
+ pdpCopy.project = pdpService.getProject(form.model.id);
+ pdpService.updatePdp(pdpCopy);
+ }
+ }
+
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_dashboard/moon/static/moon/pdp/pdp.html b/old/moon_dashboard/moon/static/moon/pdp/pdp.html
new file mode 100644
index 00000000..2456a261
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/pdp/pdp.html
@@ -0,0 +1,41 @@
+<div ng-controller="moon.pdp.controller as ctrl">
+ <div class="clearfix list-group">
+ <div class="pull-right">
+ <input type="search" class="form-control filter" placeholder="Filter" ng-model="filterText">
+ <button type="button" class="btn btn-default" ng-click="ctrl.createPdp()">
+ <span class="fa fa-plus"></span>
+ <translate>Create PDP</translate>
+ </button>
+ </div>
+ </div>
+ <div class="list-group">
+ <div ng-repeat="pdp in ctrl.model.pdps | orderBy:'name' | filter:filterText " class="list-group-item">
+ <h3 class="list-group-item-heading inline">{$ pdp.name $}</h3>
+ <div class="pull-right">
+ <button type="button" class="fa fa-trash" ng-click="ctrl.removePdp(pdp)" title="{$ 'Remove PDP' | translate $}"></button>
+ <button type="button" class="fa fa-edit" ng-click="ctrl.updatePdp(pdp)" title="{$ 'Edit PDP' | translate $}"></button>
+ </div>
+ <p class="list-group-item-text">{$ pdp.description $}</p>
+ <h4 class="list-group-item-text">
+ <translate>Project: {$ pdp.project ? pdp.project.name : 'none' $}</translate>
+ <button type="button" class="fa fa-edit" ng-click="ctrl.changeProject(pdp)" title="{$ 'Change project' | translate $}"></button>
+ </h4>
+
+ <details class="list-group-item-text">
+ <summary>
+ <h4 class="inline">{$ pdp.security_pipeline.length $}
+ <translate>policy(ies)</translate>
+ </h4>
+ <button type="button" class="fa fa-plus " ng-click="ctrl.addPolicy(pdp)" title="{$ 'Add Policy' | translate $}"></button>
+ </summary>
+ <div class="list-group">
+ <div ng-repeat="policy in pdp.security_pipeline | orderBy:'name'" class="list-group-item">
+ <h3 class="list-group-item-heading inline">{$ policy.name $}</h3>
+ <button type="button" class="fa fa-trash pull-right" ng-click="ctrl.removePolicyFromPdp(pdp, policy)" title="{$ 'Remove Policy' | translate $}"></button>
+ <p class="list-group-item-text">{$ policy.description $}</p>
+ </div>
+ </div>
+ </details>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/old/moon_dashboard/moon/static/moon/pdp/pdp.service.js b/old/moon_dashboard/moon/static/moon/pdp/pdp.service.js
new file mode 100755
index 00000000..e18971be
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/pdp/pdp.service.js
@@ -0,0 +1,123 @@
+(function () {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('moon.pdp.service', pdpService);
+
+ pdpService.$inject = ['moon.util.service', '$resource', 'moon.URI', '$q', 'horizon.app.core.openstack-service-api.keystone'];
+
+ function pdpService(util, $resource, URI, $q, keystone) {
+ var host = URI.API;
+
+ var pdpResource = $resource(host + '/pdp/' + ':id', {}, {
+ get: { method: 'GET' },
+ query: { method: 'GET' },
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' },
+ update: { method: 'PATCH' }
+ });
+
+ var policyResource = $resource(host + '/policies/' + ':id', {}, {
+ query: { method: 'GET' },
+ });
+
+ var pdpsMap = {};
+ var pdps = [];
+ var policiesMap = {};
+ var policies = [];
+ var projectsMap = {};
+ var projects = [];
+
+ function loadPdps() {
+ var queries = {
+ pdps: pdpResource.query().$promise,
+ policies: policyResource.query().$promise,
+ projects: keystone.getProjects()
+ }
+
+ $q.all(queries).then(function (result) {
+ createPdps(result.pdps, result.policies, result.projects.data)
+ console.log('moon', 'pdps initialized', pdps)
+ })
+ }
+
+ function createPdps(pdpsData, policiesData, projectsData) {
+ pdps.splice(0, pdps.length);
+ policies.splice(0, policies.length);
+ projects.splice(0, projects.length);
+ util.cleanObject(pdpsMap);
+ util.cleanObject(policiesMap);
+ util.cleanObject(projectsMap)
+
+ util.createInternal(policiesData.policies, policies, policiesMap);
+ util.pushAll(projects, projectsData.items);
+ util.addToMap(projects, projectsMap);
+ createPdpInternal(pdpsData.pdps);
+ }
+
+ function mapPdp(pdp) {
+ util.mapIdToItem(pdp.security_pipeline, policiesMap);
+ pdp.project = null;
+ if (pdp.keystone_project_id) {
+ pdp.project = projectsMap[pdp.keystone_project_id];
+ }
+ }
+
+ function createPdpInternal(data) {
+ return util.createInternal(data, pdps, pdpsMap, mapPdp);
+ }
+
+ function updatePdpInternal(data) {
+ return util.updateInternal(data, pdpsMap, mapPdp);
+ }
+
+ function removePdpInternal(id) {
+ return util.removeInternal(id, pdps, pdpsMap);
+ }
+
+ return {
+ initialize: loadPdps,
+ createPdps: createPdps,
+ pdps: pdps,
+ policies: policies,
+ projects: projects,
+ createPdp: function createPdp(pdp) {
+ pdp.keystone_project_id = null;
+ pdp.security_pipeline = [];
+ pdpResource.create(null, pdp, success, util.displayErrorFunction('Unable to create PDP'));
+
+ function success(data) {
+ createPdpInternal(data.pdps);
+ util.displaySuccess('PDP created');
+ }
+ },
+ removePdp: function removePdp(pdp) {
+ pdpResource.remove({ id: pdp.id }, null, success, util.displayErrorFunction('Unable to remove PDP'));
+
+ function success(data) {
+ removePdpInternal(pdp.id);
+ util.displaySuccess('PDP removed');
+ }
+ },
+ updatePdp: function updatePdp(pdp) {
+ util.mapItemToId(pdp.security_pipeline);
+ pdp.keystone_project_id = pdp.project ? pdp.project.id : null;
+ pdpResource.update({ id: pdp.id }, pdp, success, util.displayErrorFunction('Unable to update PDP'));
+
+ function success(data) {
+ updatePdpInternal(data.pdps)
+ util.displaySuccess('PDP updated');
+ }
+ },
+ getPolicy: function getPolicy(id) {
+ return policiesMap[id];
+ },
+ getProject: function getProject(id) {
+ return projectsMap[id];
+ },
+ }
+
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_dashboard/moon/static/moon/pdp/pdp.service.spec.js b/old/moon_dashboard/moon/static/moon/pdp/pdp.service.spec.js
new file mode 100755
index 00000000..4208467f
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/pdp/pdp.service.spec.js
@@ -0,0 +1,143 @@
+(function () {
+ 'use strict';
+
+ describe('moon.pdp.service', function () {
+ var service, $httpBackend, URI;
+ var pdpsData, policiesData, projectsData;
+
+
+ function initData() {
+ pdpsData = {
+ pdps:
+ { 'pdpId1': { name: 'pdp1', description: 'pdpDescription1', security_pipeline: ['policyId1'], keystone_project_id: 'projectId1' } }
+ };
+
+ policiesData = {
+ policies:
+ {
+ 'policyId1': { name: 'policy1', description: 'pDescription1' },
+ 'policyId2': { name: 'policy2', description: 'pDescription2' }
+ }
+ };
+
+ projectsData = {
+ items: [
+ { name: "project1", id: "projectId1" },
+ { name: "project2", id: "projectId2" }
+ ]
+ };
+
+ }
+
+ beforeEach(module('horizon.app.core'));
+ beforeEach(module('horizon.framework'));
+ beforeEach(module('moon'));
+
+ beforeEach(inject(function ($injector) {
+ service = $injector.get('moon.pdp.service');
+ $httpBackend = $injector.get('$httpBackend');
+ URI = $injector.get('moon.URI');
+ }));
+
+ afterEach(function () {
+ $httpBackend.verifyNoOutstandingExpectation();
+ $httpBackend.verifyNoOutstandingRequest();
+ });
+
+ it('should initialize', function () {
+ initData();
+ $httpBackend.expectGET(URI.API + '/pdp').respond(200, pdpsData);
+ $httpBackend.expectGET(URI.API + '/policies').respond(200, policiesData);
+ $httpBackend.expectGET('/api/keystone/projects/').respond(200, projectsData);
+
+
+ service.initialize();
+ $httpBackend.flush();
+
+ expect(service.pdps.length).toBe(1);
+ var pdp = service.pdps[0];
+ expect(pdp.id).toBe('pdpId1');
+ expect(pdp.name).toBe('pdp1');
+ expect(pdp.description).toBe('pdpDescription1');
+ expect(pdp.security_pipeline.length).toBe(1);
+ expect(pdp.security_pipeline[0].id).toBe('policyId1');
+ expect(pdp.keystone_project_id).toBe('projectId1');
+ expect(pdp.project.id).toBe('projectId1');
+
+ expect(service.policies.length).toBe(2);
+ var policy = service.policies[0];
+ expect(policy.id).toBe('policyId1');
+ expect(policy.name).toBe('policy1');
+ expect(policy.description).toBe('pDescription1');
+
+
+ expect(service.projects.length).toBe(2);
+ var project = service.projects[0];
+ expect(project.id).toBe('projectId1');
+ expect(project.name).toBe('project1');
+
+ });
+
+
+
+ it('should create pdp', function () {
+ var pdpCreatedData = {
+ pdps:
+ { 'pdpId1': { name: 'pdp1', description: 'pdpDescription1', security_pipeline: [], keystone_project_id: null } }
+ };
+
+ $httpBackend.expectPOST(URI.API + '/pdp').respond(200, pdpCreatedData);
+
+ service.createPdp({ name: 'pdp1', description: 'pdpDescription1' });
+ $httpBackend.flush();
+
+ expect(service.pdps.length).toBe(1);
+ var pdp = service.pdps[0];
+ expect(pdp.id).toBe('pdpId1');
+ expect(pdp.name).toBe('pdp1');
+ expect(pdp.description).toBe('pdpDescription1');
+ expect(pdp.project).toBe(null);
+ expect(pdp.security_pipeline.length).toBe(0);
+ });
+
+ it('should remove pdp', function () {
+ initData();
+ service.createPdps(pdpsData, policiesData, projectsData);
+
+ $httpBackend.expectDELETE(URI.API + '/pdp/pdpId1').respond(200);
+
+ service.removePdp({ id: 'pdpId1' });
+ $httpBackend.flush();
+
+ expect(service.pdps.length).toBe(0);
+ });
+
+ it('should update pdp', function () {
+ initData();
+ var pdpUpdatedData = {
+ pdps:
+ { 'pdpId1': { name: 'pdp2', description: 'pdpDescription2', security_pipeline: ['policyId2'], keystone_project_id: 'projectId2' } }
+ };
+ service.createPdps(pdpsData, policiesData, projectsData);
+
+ $httpBackend.expectPATCH(URI.API + '/pdp/pdpId1').respond(200, pdpUpdatedData);
+
+ service.updatePdp({ id: 'pdpId1', name: 'pdp2', description: 'pdpDescription2', security_pipeline: [service.getPolicy('policyId2')], project: service.getProject('projectId2') });
+ $httpBackend.flush();
+
+ expect(service.pdps.length).toBe(1);
+ var pdp = service.pdps[0];
+ expect(pdp.id).toBe('pdpId1');
+ expect(pdp.name).toBe('pdp2');
+ expect(pdp.description).toBe('pdpDescription2');
+ expect(pdp.project.id).toBe('projectId2');
+ expect(pdp.security_pipeline.length).toBe(1);
+ expect(pdp.security_pipeline[0].id).toBe('policyId2');
+
+ });
+
+
+ });
+
+
+})(); \ No newline at end of file
diff --git a/old/moon_dashboard/moon/static/moon/policy/policy.controller.js b/old/moon_dashboard/moon/static/moon/policy/policy.controller.js
new file mode 100644
index 00000000..a3cc18f1
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/policy/policy.controller.js
@@ -0,0 +1,341 @@
+(function () {
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('moon.policy.controller',
+ controller);
+
+ controller.$inject = ['moon.util.service', 'moon.policy.service', 'moon.model.service', 'horizon.framework.widgets.form.ModalFormService'];
+
+ function controller(util, policyService, modelService, ModalFormService) {
+ var self = this;
+ var genres = [{ value: 'admin', name: gettext('admin') }, { value: 'authz', name: gettext('authz') }];
+ self.model = policyService;
+ self.selectedRule = null;
+ self.currentData = null;
+ policyService.initialize();
+
+ var dataTitleMaps = {};
+
+ var categoryMap = {
+ subject: {
+ perimeterId: 'subject_id'
+ },
+ object: {
+ perimeterId: 'object_id'
+ },
+ action: {
+ perimeterId: 'action_id'
+ },
+ }
+
+ function createAddDataButton(type, index, category, config, policy) {
+ config.form.push({
+ 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, 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 = {
+ title: gettext('Create Data of ' + category.name + ' category'),
+ schema: schema,
+ form: ['name', { key: 'description', type: 'textarea' }],
+ model: data
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ policyService.createData(type, policy, category, form.model).then(
+ function (data) {
+ util.pushAll(dataTitleMaps[category.id], util.arrayToTitleMap(data));
+ formModel[key] = data[0].id
+ }
+ );
+ }
+ }
+ }
+
+ function getOrCreateDataTitleMap(category, data, policy) {
+ var result = dataTitleMaps[category.id];
+ if (!result) {
+ result = util.arrayToTitleMap(data);
+ dataTitleMaps[category.id] = result;
+ }
+ return result;
+ }
+
+ function createDataSelect(type, categories, data, config, policy) {
+ for (var i = 0; i < categories.length; i++) {
+ var category = categories[i];
+ 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);
+ }
+ }
+
+ function pushData(type, model, array) {
+ var i = 0;
+ while ((type + i) in model) {
+ array.push(model[type + i]);
+ i++;
+ }
+ }
+
+ self.createPolicy = function createPolicy() {
+ var schema = {
+ type: "object",
+ properties: {
+ name: { type: "string", minLength: 2, title: gettext("Name") },
+ 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)
+ var config = {
+ title: gettext('Create Policy'),
+ schema: schema,
+ form: ['name', { key: 'description', type: 'textarea' }, { key: 'genre', type: 'select', titleMap: genres }, { key: 'model_id', type: 'select', titleMap: titleMap }],
+ model: policy
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ policyService.createPolicy(form.model);
+ }
+ }
+
+ self.updatePolicy = function updatePolicy(policy) {
+ var schema = {
+ type: "object",
+ properties: {
+ 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'),
+ schema: schema,
+ form: ['name', { key: 'description', type: 'textarea' }, { key: 'genre', type: 'select', titleMap: genres }],
+ model: { name: policy.name, description: policy.description, model_id: policy.model_id, id: policy.id, genre: policy.genre }
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ policyService.updatePolicy(form.model);
+ }
+ }
+
+ self.addRuleWithMetaRule = function addRuleWithMetaRule(policy, metaRule) {
+ var schema = {
+ type: "object",
+ properties: {
+ instructions: { type: "string", title: gettext("Instructions") }
+ },
+ required: ['instructions']
+ };
+
+ var config = {
+ title: gettext('Add Rule'),
+ schema: schema,
+ form: [],
+ model: {
+ instructions: '[{"decision": "grant"}]'
+ }
+ };
+ dataTitleMaps = {};
+ createDataSelect('subject', metaRule.subject_categories, policy.subjectData, config, policy);
+ createDataSelect('object', metaRule.object_categories, policy.objectData, config, policy);
+ createDataSelect('action', metaRule.action_categories, policy.actionData, config, policy);
+ config.form.push({ key: 'instructions', type: 'textarea' })
+
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ var rule = { enabled: true };
+ rule.instructions = JSON.parse(form.model.instructions);
+ rule.meta_rule_id = metaRule.id;
+ rule.policy_id = policy.id;
+ rule.rule = [];
+ pushData('subject', form.model, rule.rule);
+ pushData('object', form.model, rule.rule);
+ pushData('action', form.model, rule.rule);
+ policyService.addRuleToPolicy(policy, rule);
+ }
+ }
+
+ 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);
+ var config = {
+ title: gettext('Add Rule'),
+ schema: schema,
+ form: [{ key: 'metaRuleId', type: 'select', titleMap: titleMap }],
+ model: rule
+ };
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ self.addRuleWithMetaRule(policy, modelService.getMetaRule(form.model.metaRuleId));
+ }
+ }
+
+ self.removePolicy = function removePolicy(policy) {
+ if (confirm(gettext('Are you sure to delete this Policy? (Associated perimeter, data an PDP will be deleted too)')))
+ policyService.removePolicy(policy);
+ }
+
+ self.populatePolicy = function populatePolicy(policy) {
+ policyService.populatePolicy(policy);
+ }
+
+ self.removeRuleFromPolicy = function removeRuleFromPolicy(policy, rule) {
+ if (confirm(gettext('Are you sure to delete this Rule?')))
+ policyService.removeRuleFromPolicy(policy, rule);
+ }
+
+ self.showRule = function showRule(rule) {
+ self.selectedRule = rule;
+ self.currentData = null;
+ }
+
+ self.hideRule = function hideRule() {
+ self.selectedRule = null;
+ self.currentData = null;
+ }
+
+ self.assignData = function assignData(type, policy, data) {
+ self.currentData = {
+ data: data,
+ type: type,
+ loading: true,
+ perimeters: [],
+ allPerimeters: [],
+ assignments: [],
+ }
+
+ policyService.loadPerimetersAndAssignments(type, policy).then(function (values) {
+ var category = categoryMap[type];
+ self.currentData.loading = false;
+ self.currentData.perimeters = values.perimeters;
+ 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]];
+ self.currentData.assignments.push(perimeter);
+ self.currentData.perimeters.splice(self.currentData.perimeters.indexOf(perimeter), 1);
+ }
+ }
+ })
+ }
+
+ self.createPerimeter = function createPerimeter(type, policy) {
+ var schema = {
+ type: "object",
+ 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 = {
+ title: gettext('Create Perimeter'),
+ schema: schema,
+ form: ['name', { key: 'description', type: 'textarea' }],
+ model: perimeter
+ };
+ if (type == 'subject') {
+ config.form.push('email');
+ }
+
+ ModalFormService.open(config).then(submit);
+
+ function submit(form) {
+ policyService.createPerimeter(type, policy, form.model).then(function (perimeters) {
+ util.pushAll(self.currentData.perimeters, perimeters);
+ })
+ }
+ }
+
+ 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);
+ self.currentData.perimeters.splice(self.currentData.perimeters.indexOf(perimeter), 1);
+ })
+ }
+
+ self.unassign = function unassign(type, policy, perimeter, data) {
+ policyService.removeAssignment(type, policy, perimeter, data).then(function () {
+ self.currentData.perimeters.push(perimeter);
+ 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/old/moon_dashboard/moon/static/moon/policy/policy.html b/old/moon_dashboard/moon/static/moon/policy/policy.html
new file mode 100644
index 00000000..ba13bec2
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/policy/policy.html
@@ -0,0 +1,214 @@
+<div ng-controller="moon.policy.controller as ctrl">
+ <div class="clearfix list-group">
+ <div class="pull-right">
+ <input type="search" class="form-control filter" placeholder="Filter" ng-model="filterText">
+ <button type="button" class="btn btn-default" ng-click="ctrl.createPolicy()">
+ <span class="fa fa-plus"></span>
+ <translate>Create Policy</translate>
+ </button>
+ </div>
+ </div>
+
+ <div class="list-group">
+ <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>
+ <button type="button" class="fa fa-edit" title="{$ 'Edit Policy' | translate $}" ng-click="ctrl.updatePolicy(policy)"></button>
+ </div>
+ <p class="list-group-item-text">{$ policy.description $}</p>
+ <h4 class="list-group-item-text">
+ <translate>Model: {$ policy.model ? policy.model.name : 'none' $}</translate>
+ </h4>
+ <h4 class="list-group-item-text">
+ <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>
+ <button type="button" class="fa fa-plus " ng-click="ctrl.addRule(policy)" title="{$ 'Add Rule' | translate $}"></button>
+ </summary>
+ <div class="list-group">
+ <p ng-if="!policy.rules" class="list-group-item-text" translate>Loading rules...</p>
+ <div ng-if="policy.rules" ng-repeat="rule in policy.rules | orderBy:'name'" class="list-group-item">
+ <div class="list-group-item-heading" ng-if="ctrl.selectedRule != rule">
+ <div class="inline-block width-200">
+ <b>
+ <translate>Metarule: </translate>
+ </b> {$ rule.metaRule.name $}
+ </div>
+ <b>
+ <translate>Rule: </translate>
+ </b>
+ <span ng-repeat="data in rule.subjectData">
+ <span>{$ data.name $}{$ $last ? '' : ', ' $}</span>
+ </span> |
+ <span ng-repeat="data in rule.actionData">
+ <span>{$ data.name $}{$ $last ? '' : ', ' $}</span>
+ </span> |
+ <span ng-repeat="data in rule.objectData">
+ <span>{$ data.name $}{$ $last ? '' : ', ' $}</span>
+ </span>
+ <div class="pull-right">
+ <button type="button" class="fa fa-trash pull-right" ng-click="ctrl.removeRuleFromPolicy(policy, rule)" title="{$ 'Remove Rule' | translate $}"></button>
+ <button type="button" class="fa fa-eye pull-right" ng-click="ctrl.showRule(rule)" title="{$ 'Show Rule' | translate $}"></button>
+ </div>
+ </div>
+
+ <div ng-if="ctrl.selectedRule == rule">
+ <h3 class="list-group-item-heading inline">
+ <translate>Metarule: </translate> {$ rule.metaRule.name $}</h3>
+ <div class="pull-right">
+ <button type="button" class="fa fa-trash pull-right" ng-click="ctrl.removeRuleFromPolicy(policy, rule)" title="{$ 'Remove Rule' | translate $}"></button>
+ <button type="button" class="fa fa-eye-slash pull-right" ng-click="ctrl.hideRule()" title="{$ 'Hide Rule' | translate $}"></button>
+ </div>
+ <p class="list-group-item-text">
+ <table class="table">
+ <thead>
+ <tr>
+ <th>
+ <span translate>Subjects</span>
+ </th>
+ <th>
+ <span translate>Objects</span>
+ </th>
+ <th>
+ <span translate>Actions</span>
+ </th>
+ <th>
+ <span translate>Instructions</span>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <p ng-repeat="data in rule.subjectData">
+ <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"
+ title="{$ 'Close' | translate $}"></button>
+ </p>
+ </td>
+ <td>
+ <p ng-repeat="data in rule.objectData">
+ <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"
+ title="{$ 'Close' | translate $}"></button>
+ </p>
+ </td>
+ <td>
+ <p ng-repeat="data in rule.actionData">
+ <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"
+ title="{$ 'Close' | translate $}"></button>
+ </p>
+ </td>
+ <td>
+ <pre ng-bind="rule.instructions | json "></pre>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <div ng-if="ctrl.currentData && ctrl.currentData.loading" class="row padding-10">
+ <h4 translate>Loading...</h4>
+ </div>
+ <div ng-if="ctrl.currentData && !ctrl.currentData.loading" class="row">
+ <div class="padding-10">
+ <h3>
+ <translate>Assign perimeters to</translate> {$ ctrl.currentData.data.name $}</h3>
+ <input type="search" class="form-control filter" placeholder="Filter" ng-model="filterPerimeter">
+ <button type="button" class="btn btn-default" ng-click="ctrl.createPerimeter(ctrl.currentData.type, policy)">
+ <span class="fa fa-plus"></span>
+ <translate>Create Perimeter</translate>
+ </button>
+ </div>
+ <div>
+ <div class="col-lg-4">
+ <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">
+ <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>
+ </div>
+ <p translate class="mt-5">Click to unassign</p>
+ </div>
+ </div>
+ </div>
+ </p>
+ </div>
+ </div>
+ </div>
+ </details>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/old/moon_dashboard/moon/static/moon/policy/policy.service.js b/old/moon_dashboard/moon/static/moon/policy/policy.service.js
new file mode 100755
index 00000000..3781156d
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/policy/policy.service.js
@@ -0,0 +1,428 @@
+(function () {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('moon.policy.service', policyService);
+
+ policyService.$inject = ['moon.util.service', 'moon.model.service', '$resource', 'moon.URI', '$q', 'horizon.framework.widgets.toast.service'];
+
+ function policyService(util, modelService, $resource, URI, $q, toast) {
+ var host = URI.API;
+
+ var policyResource = $resource(host + '/policies/' + ':id', {}, {
+ get: { method: 'GET' },
+ query: { method: 'GET' },
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' },
+ update: { method: 'PATCH' }
+ });
+
+ var policyRulesResource = $resource(host + '/policies/' + ':policy_id' + '/rules/' + ':rule_id', {}, {
+ get: { method: 'GET' },
+ query: { method: 'GET' },
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ });
+
+ 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' + '/' + ':data_id', {}, {
+ query: {method: 'GET'},
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ })
+
+ 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/' + ':perimeter_id', {}, {
+ query: {method: 'GET'},
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ })
+
+ 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/' + ':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', {}, {
+ query: {method: 'GET'},
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ })
+
+ var policyObjectAssignmentsResource = $resource(host + '/policies/' + ':policy_id' + '/object_assignments/' + ':perimeter_id' + '/' + ':category_id' + '/' + ':data_id', {}, {
+ query: {method: 'GET'},
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ })
+
+ var policyActionAssignmentsResource = $resource(host + '/policies/' + ':policy_id' + '/action_assignments/' + ':perimeter_id' + '/' + ':category_id' + '/' + ':data_id', {}, {
+ query: {method: 'GET'},
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ })
+
+
+ var categoryMap = {
+ 'subject': {
+ resource: policySubjectDataResource,
+ arrayName: "subjectData",
+ mapName: "subjectDataMap",
+ responseName: "subject_data",
+ policyPerimeterResource: policySubjectPerimetersResource,
+ perimeterResource: subjectPerimetersResource,
+ assignmentResource: policySubjectAssignmentsResource,
+ perimeterResponseName: "subjects",
+ assignmentResponseName: "subject_assignments",
+ unusedArrayName: "unusedSubjectData",
+ },
+ 'object': {
+ resource: policyObjectDataResource,
+ arrayName: "objectData",
+ mapName: "objectDataMap",
+ responseName: "object_data",
+ policyPerimeterResource: policyObjectPerimetersResource,
+ perimeterResource: objectPerimetersResource,
+ assignmentResource: policyObjectAssignmentsResource,
+ perimeterResponseName: "objects",
+ assignmentResponseName: "object_assignments",
+ unusedArrayName: "unusedObjectData",
+ },
+ 'action': {
+ resource: policyActionDataResource,
+ arrayName: "actionData",
+ mapName: "actionDataMap",
+ responseName: "action_data",
+ policyPerimeterResource: policyActionPerimetersResource,
+ perimeterResource: actionPerimetersResource,
+ assignmentResource: policyActionAssignmentsResource,
+ perimeterResponseName: "actions",
+ assignmentResponseName: "action_assignments",
+ unusedArrayName: "unusedActionData",
+ }
+ }
+
+ var policiesMap = {};
+ var policies = [];
+
+ function loadPolicies() {
+ var queries = {
+ policies: policyResource.query().$promise,
+ models: modelService.initialize(),
+ }
+
+ $q.all(queries).then(function (result) {
+ createPolicies(result.policies);
+ console.log('moon', 'policies initialized')
+ })
+ }
+
+ function createPolicies(policiesData) {
+ policies.splice(0, policies.length);
+ util.cleanObject(policiesMap);
+ createPolicyInternal(policiesData.policies);
+ }
+
+ function mapPolicy(policy) {
+ if (policy.model_id) {
+ policy.model = modelService.getModel(policy.model_id);
+ }
+ }
+
+ function createPolicyInternal(data) {
+ return util.createInternal(data, policies, policiesMap, mapPolicy);
+ }
+
+ function removePolicyInternal(id) {
+ return util.removeInternal(id, policies, policiesMap);
+ }
+
+ function updatePolicyInternal(data) {
+ return util.updateInternal(data, policiesMap, mapPolicy);
+ }
+
+ function removeRuleInternal(policy, rule) {
+ policy.rules.splice(policy.rules.indexOf(rule), 1);
+ updateUnusedData(policy);
+ }
+
+ function loadPolicyRule(policy) {
+ if (!policy.rules) {
+ var queries = {
+ rules: policyRulesResource.query({ policy_id: policy.id }).$promise,
+ subjectData: policySubjectDataResource.query({ policy_id: policy.id }).$promise,
+ objectData: policyObjectDataResource.query({ policy_id: policy.id }).$promise,
+ actionData: policyActionDataResource.query({ policy_id: policy.id }).$promise,
+ }
+
+ $q.all(queries).then(function (result) {
+ 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 : [];
+ policy.subjectData = util.mapToArray(policy.subjectDataMap);
+ policy.objectDataMap = objectsData.object_data.length > 0 ? objectsData.object_data[0].data : [];
+ 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);
+ }
+ }
+
+ function populateRule(policy, rule) {
+ if (rule.meta_rule_id) {
+ rule.metaRule = modelService.getMetaRule(rule.meta_rule_id);
+ }
+ if (rule.metaRule) {
+ var j = 0;
+ var k, id;
+ rule.subjectData = [];
+ rule.objectData = [];
+ rule.actionData = [];
+ for (k = 0; k < rule.metaRule.subject_categories.length; k++) {
+ id = rule.rule[j + k];
+ rule.subjectData.push(policy.subjectDataMap[id]);
+ }
+ j += k;
+ for (k = 0; k < rule.metaRule.object_categories.length; k++) {
+ id = rule.rule[j + k];
+ rule.objectData.push(policy.objectDataMap[id]);
+ }
+ j += k;
+ for (k = 0; k < rule.metaRule.action_categories.length; k++) {
+ id = rule.rule[j + k];
+ rule.actionData.push(policy.actionDataMap[id]);
+ }
+ }
+ return rule;
+ }
+
+ return {
+ initialize: loadPolicies,
+ createPolicies: createPolicies,
+ policies: policies,
+ getPolicy: function getPolicy(id) {
+ return policiesMap[id];
+ },
+ createPolicy: function createPolicy(policy) {
+ policyResource.create(null, policy, success, util.displayErrorFunction('Unable to create Policy'));
+
+ function success(data) {
+ createPolicyInternal(data.policies);
+ util.displaySuccess('Policy created');
+ }
+ },
+ removePolicy: function removePolicy(policy) {
+ policyResource.remove({ id: policy.id }, null, success, util.displayErrorFunction('Unable to remove Policy'));
+
+ function success(data) {
+ removePolicyInternal(policy.id);
+ util.displaySuccess('Policy removed');
+ }
+ },
+ updatePolicy: function updatePolicy(policy) {
+ policyResource.update({ id: policy.id }, policy, success, util.displayErrorFunction('Unable to update Policy'));
+
+ function success(data) {
+ updatePolicyInternal(data.policies)
+ util.displaySuccess('Policy updated');
+ }
+ },
+ populatePolicy: loadPolicyRule,
+ createRules: createRules,
+ addRuleToPolicy: function addRuleToPolicy(policy, rule) {
+ policyRulesResource.create({ policy_id: policy.id }, rule, success, util.displayErrorFunction('Unable to create Rule'));
+
+ function success(data) {
+ var rules = util.mapToArray(data.rules);
+ for (var i = 0; i < rules.length; i++) {
+ var rule = rules[i];
+ policy.rules.push(populateRule(policy, rule))
+ }
+ util.displaySuccess('Rule created');
+ updateUnusedData(policy);
+ }
+ },
+ removeRuleFromPolicy: function removeRuleFromPolicy(policy, rule) {
+ policyRulesResource.remove({ policy_id: policy.id, rule_id: rule.id }, null, success, util.displayErrorFunction('Unable to remove Rule'));
+
+ function success(data) {
+ removeRuleInternal(policy, rule);
+ util.displaySuccess('Rule removed');
+ }
+ },
+ createData: function createData(type, policy, category, dataCategory) {
+ var categoryValue = categoryMap[type];
+ return categoryValue.resource.create({ policy_id: policy.id, category_id: category.id }, dataCategory).$promise.then(
+ 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.policyPerimeterResource.create({ policy_id: policy.id }, perimeter).$promise.then(
+ function (data) {
+ util.displaySuccess('Perimeter created');
+ return util.mapToArray(data[categoryValue.perimeterResponseName]);
+ },
+ 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 = {
+ allPerimeters: categoryValue.perimeterResource.query().$promise,
+ perimeters: categoryValue.policyPerimeterResource.query({ policy_id: policy.id }).$promise,
+ assignments: categoryValue.assignmentResource.query({ policy_id: policy.id }).$promise,
+ }
+
+ return $q.all(queries).then(function (data) {
+ var result = {};
+ 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'))
+
+ },
+ createAssignment: function createAssignment(type, policy, perimeter, data) {
+ var categoryValue = categoryMap[type];
+ var assignment = {
+ "id": perimeter.id,
+ "category_id": data.category_id,
+ "data_id": data.id,
+ "policy_id": policy.id
+ }
+ return categoryValue.assignmentResource.create({ policy_id: policy.id }, assignment).$promise.then(
+ function (data) {
+ util.displaySuccess('Assignment created');
+ return util.mapToArray(data[categoryValue.assignmentResponseName]);
+ },
+ util.displayErrorFunction('Unable to create Assignment')
+ )
+ },
+ removeAssignment: function removeAssignment(type, policy, perimeter, data) {
+ var categoryValue = categoryMap[type];
+
+ return categoryValue.assignmentResource.remove({ policy_id: policy.id, perimeter_id: perimeter.id, category_id: data.category_id, data_id: data.id }, null).$promise.then(
+ function (data) {
+ util.displaySuccess('Assignment removed');
+ },
+ util.displayErrorFunction('Unable to remove Assignment')
+ )
+ },
+ }
+
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_dashboard/moon/static/moon/policy/policy.service.spec.js b/old/moon_dashboard/moon/static/moon/policy/policy.service.spec.js
new file mode 100755
index 00000000..8d0ca8bf
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/policy/policy.service.spec.js
@@ -0,0 +1,487 @@
+(function () {
+ 'use strict';
+
+ describe('moon.policy.service', function () {
+ var service, modelService, $httpBackend, URI;
+ var policiesData;
+ var modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData;
+ var rulesData, subjectsData, objectsData, actionsData;
+
+
+ function initData() {
+ policiesData = {
+ policies:
+ {
+ 'policyId1': { name: 'policy1', description: 'pDescription1', genre: 'genre1', model_id: 'modelId1' },
+ }
+ };
+
+ modelsData = {
+ models:
+ { 'modelId1': { name: 'model1', description: 'mDescription1', meta_rules: ['metaRuleId1'] } }
+ };
+
+ subjectCategoriesData = {
+ subject_categories:
+ {
+ 'subjectCategoryId1': { name: 'subjectCategory1', description: 'scDescription1' },
+ 'subjectCategoryId2': { name: 'subjectCategory2', description: 'scDescription2' }
+ },
+ };
+ objectCategoriesData = {
+ object_categories:
+ {
+ 'objectCategoryId1': { name: 'objectCategory1', description: 'ocDescription1' },
+ 'objectCategoryId2': { name: 'objectCategory2', description: 'ocDescription2' }
+ }
+ };
+ actionCategoriesData = {
+ action_categories:
+ {
+ 'actionCategoryId1': { name: 'actionCategory1', description: 'acDescription1' },
+ 'actionCategoryId2': { name: 'actionCategory2', description: 'acDescription2' }
+ }
+ };
+ metaRulesData = {
+ meta_rules:
+ {
+ 'metaRuleId1': { name: 'metaRule1', description: 'mrDescription1', subject_categories: ['subjectCategoryId1'], object_categories: ['objectCategoryId1'], action_categories: ['actionCategoryId1'] },
+ 'metaRuleId2': { name: 'metaRule2', description: 'mrDescription2', subject_categories: [], object_categories: [], action_categories: [] }
+ }
+ };
+ }
+
+ function initRuleData() {
+ rulesData = {
+ rules: {
+ rules: [
+ { meta_rule_id: 'metaRuleId1', rule: ['subjectId1', 'objectId1', 'actionId1'], id: 'ruleId1', instructions: { test: 'test' } }
+ ]
+ }
+ };
+
+ subjectsData = {
+ subject_data:
+ [
+ {
+ data: {
+ 'subjectId1': { name: 'subject1', description: 'sDescription1' },
+ }
+ }
+ ]
+ };
+ objectsData = {
+ object_data:
+ [
+ {
+ data: {
+ 'objectId1': { name: 'object1', description: 'oDescription1' },
+ }
+ }
+ ]
+ };
+ actionsData = {
+ action_data:
+ [
+ {
+ data: {
+ 'actionId1': { name: 'action1', description: 'aDescription1' },
+ }
+ }
+ ]
+ };
+ }
+
+ beforeEach(module('horizon.app.core'));
+ beforeEach(module('horizon.framework'));
+ beforeEach(module('moon'));
+
+ beforeEach(inject(function ($injector) {
+ service = $injector.get('moon.policy.service');
+ modelService = $injector.get('moon.model.service');
+ $httpBackend = $injector.get('$httpBackend');
+ URI = $injector.get('moon.URI');
+ }));
+
+ afterEach(function () {
+ $httpBackend.verifyNoOutstandingExpectation();
+ $httpBackend.verifyNoOutstandingRequest();
+ });
+
+ it('should initialize', function () {
+ initData();
+ $httpBackend.expectGET(URI.API + '/policies').respond(200, policiesData);
+ $httpBackend.expectGET(URI.API + '/subject_categories').respond(200, subjectCategoriesData);
+ $httpBackend.expectGET(URI.API + '/object_categories').respond(200, objectCategoriesData);
+ $httpBackend.expectGET(URI.API + '/action_categories').respond(200, actionCategoriesData);
+ $httpBackend.expectGET(URI.API + '/meta_rules').respond(200, metaRulesData);
+ $httpBackend.expectGET(URI.API + '/models').respond(200, modelsData);
+
+
+ service.initialize();
+ $httpBackend.flush();
+
+ expect(service.policies.length).toBe(1);
+ var policy = service.policies[0];
+ expect(policy.id).toBe('policyId1');
+ expect(policy.name).toBe('policy1');
+ expect(policy.description).toBe('pDescription1');
+ expect(policy.genre).toBe('genre1');
+ expect(policy.model.id).toBe('modelId1');
+
+ });
+
+
+
+ it('should create policy', function () {
+ initData();
+ modelService.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+
+ var policyCreatedData = {
+ policies:
+ { 'policyId1': { name: 'policy1', description: 'pDescription1', genre: 'genre1', model_id: 'modelId1' } }
+ };
+
+ $httpBackend.expectPOST(URI.API + '/policies').respond(200, policyCreatedData);
+
+ service.createPolicy({ name: 'policy1', description: 'pDescription1', genre: 'genre1', model: modelService.getModel('modelId1') });
+ $httpBackend.flush();
+
+ expect(service.policies.length).toBe(1);
+ var policy = service.policies[0];
+ expect(policy.id).toBe('policyId1');
+ expect(policy.name).toBe('policy1');
+ expect(policy.description).toBe('pDescription1');
+ expect(policy.genre).toBe('genre1');
+ expect(policy.model.id).toBe('modelId1');
+ });
+
+ it('should remove policy', function () {
+ initData();
+ modelService.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+ service.createPolicies(policiesData);
+
+ $httpBackend.expectDELETE(URI.API + '/policies/policyId1').respond(200);
+
+ service.removePolicy({ id: 'policyId1' });
+ $httpBackend.flush();
+
+ expect(service.policies.length).toBe(0);
+ });
+
+ it('should update policy', function () {
+ initData();
+ var policyUpdatedData = {
+ policies:
+ { 'policyId1': { name: 'policy2', description: 'pDescription2', genre: 'genre2', model_id: 'modelId1' } }
+ };
+ modelService.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+ service.createPolicies(policiesData);
+
+ $httpBackend.expectPATCH(URI.API + '/policies/policyId1').respond(200, policyUpdatedData);
+
+ service.updatePolicy({ id: 'policyId1', name: 'policy2', description: 'pDescription2', genre: 'genre2', model: modelService.getModel('modelId1') });
+ $httpBackend.flush();
+
+ expect(service.policies.length).toBe(1);
+ var policy = service.policies[0];
+ expect(policy.id).toBe('policyId1');
+ expect(policy.name).toBe('policy2');
+ expect(policy.description).toBe('pDescription2');
+ expect(policy.genre).toBe('genre2');
+ expect(policy.model.id).toBe('modelId1');
+
+ });
+
+
+ it('should populate policy', function () {
+ initData();
+ initRuleData();
+ modelService.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+ service.createPolicies(policiesData);
+
+ var policy = service.getPolicy('policyId1')
+
+ $httpBackend.expectGET(URI.API + '/policies/policyId1/rules').respond(200, rulesData);
+ $httpBackend.expectGET(URI.API + '/policies/policyId1/subject_data').respond(200, subjectsData);
+ $httpBackend.expectGET(URI.API + '/policies/policyId1/object_data').respond(200, objectsData);
+ $httpBackend.expectGET(URI.API + '/policies/policyId1/action_data').respond(200, actionsData);
+
+ service.populatePolicy(policy);
+ $httpBackend.flush();
+
+ expect(policy.rules.length).toBe(1);
+ var rule = policy.rules[0];
+ expect(rule.id).toBe('ruleId1');
+ expect(rule.metaRule.id).toBe('metaRuleId1');
+ expect(rule.instructions.test).toBe('test');
+ expect(rule.subjectData.length).toBe(1);
+ expect(rule.subjectData[0].id).toBe('subjectId1');
+ expect(rule.objectData.length).toBe(1);
+ expect(rule.objectData[0].id).toBe('objectId1');
+ expect(rule.actionData.length).toBe(1);
+ expect(rule.actionData[0].id).toBe('actionId1');
+
+ expect(policy.subjectData.length).toBe(1);
+ var subjectData = policy.subjectData[0];
+ expect(subjectData.id).toBe('subjectId1');
+ expect(subjectData.name).toBe('subject1');
+ expect(subjectData.description).toBe('sDescription1');
+
+ expect(policy.objectData.length).toBe(1);
+ var objectData = policy.objectData[0];
+ expect(objectData.id).toBe('objectId1');
+ expect(objectData.name).toBe('object1');
+ expect(objectData.description).toBe('oDescription1');
+
+ expect(policy.actionData.length).toBe(1);
+ var actionData = policy.actionData[0];
+ expect(actionData.id).toBe('actionId1');
+ expect(actionData.name).toBe('action1');
+ expect(actionData.description).toBe('aDescription1');
+
+ });
+
+
+ it('should add rule to policy', function () {
+ initData();
+ initRuleData();
+ modelService.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+ service.createPolicies(policiesData);
+
+
+ var ruleCreatedData = {
+ rules: {
+ 'ruleId1': { meta_rule_id: 'metaRuleId1', rule: ['subjectId1', 'objectId1', 'actionId1'], instructions: { test: 'test' } }
+ }
+ };
+
+ var policy = service.getPolicy('policyId1');
+
+ service.createRules(policy, null, subjectsData, objectsData, actionsData);
+
+ $httpBackend.expectPOST(URI.API + '/policies/policyId1/rules').respond(200, ruleCreatedData);
+
+ service.addRuleToPolicy(policy, { meta_rule_id: 'metaRuleId1', rule: ['subjectId1', 'objectId1', 'actionId1'], instructions: { test: 'test' } });
+ $httpBackend.flush();
+
+ expect(policy.rules.length).toBe(1);
+ var rule = policy.rules[0];
+ expect(rule.id).toBe('ruleId1');
+ expect(rule.metaRule.id).toBe('metaRuleId1');
+ expect(rule.subjectData.length).toBe(1);
+ expect(rule.subjectData[0].id).toBe('subjectId1');
+ expect(rule.objectData.length).toBe(1);
+ expect(rule.objectData[0].id).toBe('objectId1');
+ expect(rule.actionData.length).toBe(1);
+ expect(rule.actionData[0].id).toBe('actionId1');
+
+ });
+
+ it('should remove rule from policy', function () {
+ initData();
+ initRuleData();
+ modelService.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+ service.createPolicies(policiesData);
+
+ var policy = service.getPolicy('policyId1');
+
+ service.createRules(policy, rulesData, subjectsData, objectsData, actionsData);
+
+ $httpBackend.expectDELETE(URI.API + '/policies/policyId1/rules/ruleId1').respond(200);
+
+ service.removeRuleFromPolicy(policy, { id: 'ruleId1' });
+ $httpBackend.flush();
+
+ expect(policy.rules.length).toBe(0);
+ });
+
+
+ it('should create data', function () {
+ initData();
+ initRuleData();
+ modelService.createModels(modelsData, metaRulesData, subjectCategoriesData, objectCategoriesData, actionCategoriesData);
+ service.createPolicies(policiesData);
+
+
+ var dataCreatedData = {
+ subject_data: {
+ data: {
+ 'subjectId1': { name: 'subject1', description: 'sDescription1' },
+ }
+ }
+ };
+
+ var policy = service.getPolicy('policyId1');
+ policy.subjectData = [];
+ policy.subjectDataMap = {};
+
+ $httpBackend.expectPOST(URI.API + '/policies/policyId1/subject_data/subjectCategoryId1').respond(200, dataCreatedData);
+
+ service.createData('subject', policy, modelService.getCategory('subject', 'subjectCategoryId1'), { name: 'subject1', description: 'sDescription1' });
+ $httpBackend.flush();
+
+ expect(policy.subjectData.length).toBe(1);
+ var subjectData = policy.subjectData[0];
+ expect(subjectData.id).toBe('subjectId1');
+ expect(subjectData.name).toBe('subject1');
+ expect(subjectData.description).toBe('sDescription1');
+
+ });
+
+ 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();
+ });
+
+
+ });
+
+
+})(); \ No newline at end of file
diff --git a/old/moon_dashboard/moon/static/moon/scss/moon.scss b/old/moon_dashboard/moon/static/moon/scss/moon.scss
new file mode 100644
index 00000000..3cdbb6e3
--- /dev/null
+++ b/old/moon_dashboard/moon/static/moon/scss/moon.scss
@@ -0,0 +1,58 @@
+.inline {
+ display: inline;
+}
+
+.inline-block {
+ display: inline-block;
+}
+
+summary{
+ outline:none;
+ margin-bottom: 10px;
+}
+
+details {
+ cursor: default;
+}
+
+.filter {
+ display: inline-block;
+ width: auto;
+ vertical-align: middle;
+}
+
+.categories td {
+ width: 33%;
+}
+
+.width-200 {
+ width: 200px;
+}
+
+.height-200 {
+ height: 200px;
+}
+
+.border {
+ border: 1px #DDD solid;
+}
+
+.padding-10 {
+ padding: 10px;
+}
+
+.scroll {
+ overflow-y: auto;
+}
+
+.mt-5 {
+ margin-top: 5px;
+}
+
+.input-file {
+ display: none !important;
+}
+
+.overflow-hidden {
+ overflow: hidden;
+} \ No newline at end of file
diff --git a/old/moon_dashboard/moon/templates/moon/base.html b/old/moon_dashboard/moon/templates/moon/base.html
new file mode 100644
index 00000000..f07a01ba
--- /dev/null
+++ b/old/moon_dashboard/moon/templates/moon/base.html
@@ -0,0 +1,11 @@
+{% load horizon %}{% jstemplate %}[% extends 'base.html' %]
+
+[% block sidebar %]
+ [% include 'horizon/common/_sidebar.html' %]
+[% endblock %]
+
+[% block main %]
+ [% include "horizon/_messages.html" %]
+ [% block {{ dash_name }}_main %][% endblock %]
+[% endblock %]
+{% endjstemplate %}
diff --git a/old/moon_dashboard/run.sh b/old/moon_dashboard/run.sh
new file mode 100644
index 00000000..9a68ca6e
--- /dev/null
+++ b/old/moon_dashboard/run.sh
@@ -0,0 +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}
+
+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/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 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 "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+
+tox -e runserver -- 0.0.0.0:8000
diff --git a/old/moon_dashboard/setup.cfg b/old/moon_dashboard/setup.cfg
new file mode 100644
index 00000000..9cf3f779
--- /dev/null
+++ b/old/moon_dashboard/setup.cfg
@@ -0,0 +1,24 @@
+[metadata]
+name = moon
+version=1.5.0
+summary = A dashboard plugin for Moon
+description-file =
+ README.rst
+author = Jonathan Gourdin
+author_email = jonathan.gourdin@orange.com
+home-page = https://docs.openstack.org/horizon/latest/
+classifiers = [
+ Environment :: OpenStack
+ Framework :: Django
+ Intended Audience :: Developers
+ Intended Audience :: System Administrators
+ License :: OSI Approved :: Apache Software License
+ Operating System :: POSIX :: Linux
+ Programming Language :: Python
+ Programming Language :: Python :: 2
+ Programming Language :: Python :: 2.7
+ Programming Language :: Python :: 3.5
+
+[files]
+packages =
+ moon \ No newline at end of file
diff --git a/old/moon_dashboard/setup.py b/old/moon_dashboard/setup.py
new file mode 100644
index 00000000..4794e334
--- /dev/null
+++ b/old/moon_dashboard/setup.py
@@ -0,0 +1,14 @@
+# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
+import setuptools
+
+# In python < 2.7.4, a lazy loading of package `pbr` will break
+# setuptools if some other modules registered functions in `atexit`.
+# solution from: http://bugs.python.org/issue15881#msg170215
+try:
+ import multiprocessing # noqa
+except ImportError:
+ pass
+
+setuptools.setup(
+ setup_requires=['pbr>=1.8'],
+ pbr=True) \ No newline at end of file
diff --git a/old/moon_forming/.gitignore b/old/moon_forming/.gitignore
new file mode 100644
index 00000000..7bff7318
--- /dev/null
+++ b/old/moon_forming/.gitignore
@@ -0,0 +1,105 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+
diff --git a/old/moon_forming/Changelog b/old/moon_forming/Changelog
new file mode 100644
index 00000000..a107efd9
--- /dev/null
+++ b/old/moon_forming/Changelog
@@ -0,0 +1,11 @@
+CHANGES
+=======
+
+1.4.0
+-----
+- Update the python_moondb version to 1.2.10
+
+1.4.1
+-----
+- Update the python_moondb version to 1.2.16
+
diff --git a/old/moon_forming/Dockerfile b/old/moon_forming/Dockerfile
new file mode 100644
index 00000000..3a39880b
--- /dev/null
+++ b/old/moon_forming/Dockerfile
@@ -0,0 +1,17 @@
+FROM python:3
+
+
+LABEL Name=Forming
+LABEL Description="Configuration job for the Moon platform"
+LABEL Maintainer="Thomas Duval"
+LABEL Url="https://wiki.opnfv.org/display/moon/Moon+Project+Proposal"
+
+USER root
+
+WORKDIR /usr/src/app
+RUN pip install --no-cache-dir --upgrade requests pytest pyyaml python_moonutilities python_moondb python_moonclient
+
+ADD . /root
+WORKDIR /root
+
+CMD /bin/bash /root/config_moon.sh
diff --git a/old/moon_forming/README.md b/old/moon_forming/README.md
new file mode 100644
index 00000000..9b755d96
--- /dev/null
+++ b/old/moon_forming/README.md
@@ -0,0 +1,47 @@
+# Moon Forming
+moon_forming is a container to automatize the configuration of the Moon platform
+
+## Run
+```bash
+docker run wukongsun/moon_forming:latest
+```
+
+## Consul
+The Moon platform is already configured after the installation.
+If you want to see or modify the configuration, go with a web browser
+to the following page: `http://localhost:30006`.
+
+With the consul server, you can update the configuration in the `KEY/VALUE` tab.
+There are some configuration items, lots of them are only read when a new K8S pod is started
+and not during its life cycle.
+
+**WARNING: some confidential information are put here in clear text.
+This is a known security issue.**
+
+### Keystone
+If you have your own Keystone server, you can point Moon to your Keystone in the
+`openstack/keystone` element: `http://localhost:30005/ui/#/dc1/kv/openstack/keystone/edit`.
+This configuration element is read every time Moon need it, specially when adding users.
+
+### Database
+The database can also be modified through: `http://localhost:30005/ui/#/dc1/kv/database/edit`.
+
+**WARNING: the password is in clear text, this is a known security issue.**
+
+If you want to use your own database server, change the configuration:
+
+ {"url": "mysql+pymysql://my_user:my_secret_password@my_server/moon", "driver": "sql"}
+
+Then you have to rebuild the database before using it.
+This can be done with the following commands:
+```bash
+kubectl delete -f $MOON_HOME/tools/moon_kubernetes/templates/moon_forming.yaml
+kubectl create -f $MOON_HOME/tools/moon_kubernetes/templates/moon_forming.yaml
+```
+
+## Functional tests
+
+```bash
+cd $MOON_HOME/moon_manager
+bash ../tests/functional/run_tests_for_component.sh
+```
diff --git a/old/moon_forming/conf2consul.py b/old/moon_forming/conf2consul.py
new file mode 100644
index 00000000..df7a6b18
--- /dev/null
+++ b/old/moon_forming/conf2consul.py
@@ -0,0 +1,104 @@
+import os
+import sys
+import requests
+import yaml
+import logging
+import json
+import base64
+
+__version__ = "1.4.1"
+
+logging.basicConfig(level=logging.INFO)
+log = logging.getLogger("moon.conf2consul")
+requests_log = logging.getLogger("requests.packages.urllib3")
+requests_log.setLevel(logging.WARNING)
+requests_log.propagate = True
+
+if len(sys.argv) == 2:
+ if os.path.isfile(sys.argv[1]):
+ CONF_FILENAME = sys.argv[1]
+ CONSUL_HOST = "consul"
+ else:
+ CONF_FILENAME = "moon.conf"
+ CONSUL_HOST = sys.argv[1]
+ CONSUL_PORT = 8500
+else:
+ CONSUL_HOST = sys.argv[1] if len(sys.argv) > 1 else "consul"
+ CONSUL_PORT = sys.argv[2] if len(sys.argv) > 2 else 8500
+ CONF_FILENAME = sys.argv[3] if len(sys.argv) > 3 else "moon.conf"
+HEADERS = {"content-type": "application/json"}
+
+
+def search_config_file():
+ data_config = None
+ for _file in (
+ CONF_FILENAME,
+ "conf/moon.conf",
+ "../moon.conf",
+ "../conf/moon.conf",
+ "/etc/moon/moon.conf",
+ ):
+ try:
+ data_config = yaml.safe_load(open(_file))
+ except FileNotFoundError:
+ data_config = None
+ continue
+ else:
+ break
+ if not data_config:
+ raise Exception("Configuration file not found...")
+ return data_config
+
+
+def put(key, value):
+ url = "http://{host}:{port}/v1/kv/{key}".format(host=CONSUL_HOST, port=CONSUL_PORT, key=key)
+ log.info(url)
+ req = requests.put(
+ url,
+ headers=HEADERS,
+ json=value
+ )
+ if req.status_code != 200:
+ raise Exception("Error connecting to Consul ({}, {})".format(req.status_code, req.text))
+
+
+def get(key):
+ url = "http://{host}:{port}/v1/kv/{key}".format(host=CONSUL_HOST, port=CONSUL_PORT, key=key)
+ req = requests.get(url)
+ data = req.json()
+ for item in data:
+ log.info("{} {} -> {}".format(
+ req.status_code,
+ item["Key"],
+ json.loads(base64.b64decode(item["Value"]).decode("utf-8"))
+ ))
+ yield json.loads(base64.b64decode(item["Value"]).decode("utf-8"))
+
+
+def main():
+ data_config = search_config_file()
+ req = requests.head("http://{}:{}/ui/".format(CONSUL_HOST, CONSUL_PORT))
+ if req.status_code != 200:
+ log.critical("Consul is down...")
+ log.critical("request info: {}/{}".format(req, req.text))
+ sys.exit(1)
+
+ put("database", data_config["database"])
+ # put("messenger", data_config["messenger"])
+ # put("slave", data_config["slave"])
+ # put("docker", data_config["docker"])
+ put("logging", data_config["logging"])
+ # put("components_port_start", data_config["components"]["port_start"])
+
+ for _key, _value in data_config["components"].items():
+ put("components/{}".format(_key), data_config["components"][_key])
+
+ # for _key, _value in data_config["plugins"].items():
+ # put("plugins/{}".format(_key), data_config["plugins"][_key])
+
+ for _key, _value in data_config["openstack"].items():
+ put("openstack/{}".format(_key), data_config["openstack"][_key])
+
+
+main()
+
diff --git a/old/moon_forming/config_moon.sh b/old/moon_forming/config_moon.sh
new file mode 100644
index 00000000..0a55898f
--- /dev/null
+++ b/old/moon_forming/config_moon.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+
+populate_args=$*
+
+echo "Waiting for Consul (http://consul:8500)"
+while ! python -c "import requests; req = requests.get('http://consul:8500')" 2>/dev/null ; do
+ sleep 5 ;
+ echo -n "."
+done
+echo "."
+echo "Consul (http://consul:8500) is up."
+
+python3 /root/conf2consul.py /etc/moon/moon.conf
+
+echo "Waiting for DB (tcp://db:3306)"
+while ! python -c "import socket, sys; s = socket.socket(socket.AF_INET, socket.SOCK_STREAM); s.connect(('db', 3306)); sys.exit(0)" 2>/dev/null ; do
+ sleep 5 ;
+ echo -n "."
+done
+echo "."
+echo "Database (http://db:3306) is up."
+
+moon_db_manager upgrade
+
+echo "Waiting for Keystone (http://keystone:5000)"
+while ! python -c "import requests; req = requests.get('http://keystone:5000')" 2>/dev/null ; do
+ sleep 5 ;
+ echo -n "."
+done
+echo "."
+echo "Keystone (http://keystone:5000) is up."
+
+echo "Waiting for Manager (http://manager:8082)"
+while ! python -c "import requests; req = requests.get('http://manager:8082')" 2>/dev/null ; do
+ sleep 5 ;
+ echo -n "."
+done
+echo "."
+echo "Manager (http://manager:8082) is up."
diff --git a/old/moon_gui/.gitignore b/old/moon_gui/.gitignore
new file mode 100644
index 00000000..04bca1bc
--- /dev/null
+++ b/old/moon_gui/.gitignore
@@ -0,0 +1,4 @@
+db.sqlite3
+idea/*
+node_modules/*
+dist/ \ No newline at end of file
diff --git a/old/moon_gui/.jshintrc b/old/moon_gui/.jshintrc
new file mode 100644
index 00000000..b9955f87
--- /dev/null
+++ b/old/moon_gui/.jshintrc
@@ -0,0 +1,59 @@
+
+{
+ "bitwise": true,
+ "camelcase": false,
+ "curly": true,
+ "eqeqeq": true,
+ "esversion": 6,
+ "forin": true,
+ "freeze": true,
+ "immed": true,
+ "indent": 4,
+ "latedef": "nofunc",
+ "newcap": true,
+ "noarg": true,
+ "noempty": true,
+ "nonbsp": true,
+ "nonew": true,
+ "plusplus": false,
+ "quotmark": "single",
+ "undef": true,
+ "unused": false,
+ "strict": true,
+ "maxparams": 20,
+ "maxdepth": 5,
+ "maxstatements": 40,
+ "maxcomplexity": 8,
+ "maxlen": 160,
+ "asi": false,
+ "boss": false,
+ "debug": false,
+ "eqnull": true,
+ "esnext": false,
+ "evil": false,
+ "expr": false,
+ "funcscope": false,
+ "globalstrict": false,
+ "iterator": false,
+ "lastsemic": false,
+ "laxbreak": false,
+ "laxcomma": false,
+ "loopfunc": true,
+ "maxerr": 50,
+ "moz": false,
+ "multistr": false,
+ "notypeof": false,
+ "proto": false,
+ "scripturl": false,
+ "shadow": false,
+ "sub": true,
+ "supernew": false,
+ "validthis": true,
+ "noyield": false,
+ "browser": true,
+ "node": true,
+ "globals": {
+ "angular": false,
+ "_": false
+ }
+} \ No newline at end of file
diff --git a/old/moon_gui/DEV.md b/old/moon_gui/DEV.md
new file mode 100644
index 00000000..1bd1ef4c
--- /dev/null
+++ b/old/moon_gui/DEV.md
@@ -0,0 +1,49 @@
+# How-to develop on the Moon platform
+
+## Install the platform
+
+Follow the `moon/moonv4/README.md` file.
+
+## GUI
+
+The GUI code is located at `moon/moonv4/moon_gui`
+The configuration values is at `moonv4/moon_gui/static/app/moon.constants.js`
+
+To be able to only develop the GUI, you can install the Moon platform and run the GUI outside the platform.
+To link the outside GUI to the Moon Manager, you must update the configuration values and specially the
+following variables :
+
+- `{{MANAGER_HOST}}` : the hostname of the Manager (example: 127.0.0.1)
+- `{{MANAGER_PORT}}` : the TCP port of the Manager (30001)
+- `{{KEYSTONE_HOST}}` : the hostname of the Keystone server (example: 127.0.0.1)
+- `{{KEYSTONE_PORT}}` : the TCP port of the Keystone server (30006)
+
+To run the GUI service, follow the `README.md` file.
+
+## Current bugs
+
+1) ~~Models -> "`List of Meta rules`", after updating the meta_rule
+"`Actions` -> `edit`" and clicking on `close`, the main screen doesn't refresh~~
+
+2) ~~idem if we want to remove the meta_rule~~
+
+3) ~~after deleting an action perimeter (`Policy` -> `Add an action` -> `select a perimeter` and delete it),
+the dropdown list is not updated~~
+
+4) ~~when adding a data subject (`Policy` -> `Data` -> `Add a Data Subject`), only the right category names must
+be listed in `Catagory list`. Hide the categories that doesn't belong to that policy.~~
+
+5) ~~idem for object data~~
+
+6) ~~idem for action data~~
+
+7) ~~after adding data (subject, object, action), the dropdown list in `Rules` -> `Add a rules` are not updated
+if the page is not manually refresh by the user and if the `Rules` window is already showing.~~
+
+8) ~~typographic error in `Add a rules`~~
+
+9) ~~in `Data` -> `Add a Data Object`, the `Create Data` never create the data in the backend~~
+
+10) ~~Move the `project` tabular to the end~~
+
+11) create a simplified version (to be discussed)
diff --git a/old/moon_gui/Dockerfile b/old/moon_gui/Dockerfile
new file mode 100644
index 00000000..428e1037
--- /dev/null
+++ b/old/moon_gui/Dockerfile
@@ -0,0 +1,18 @@
+FROM ubuntu:latest
+
+RUN apt update && apt install git nodejs nodejs-legacy npm apache2 -y
+RUN npm install --global gulp-cli
+
+ENV MANAGER_HOST="127.0.0.1"
+ENV MANAGER_PORT=8080
+ENV KEYSTONE_HOST="127.0.0.1"
+ENV KEYSTONE_PORT=5000
+
+ADD . /root
+WORKDIR /root/
+
+RUN npm install
+
+#CMD ["gulp"]
+#CMD ["gulp", "webServerDelivery"]
+CMD ["sh", "/root/run.sh"] \ No newline at end of file
diff --git a/old/moon_gui/README.md b/old/moon_gui/README.md
new file mode 100644
index 00000000..ea46b079
--- /dev/null
+++ b/old/moon_gui/README.md
@@ -0,0 +1,71 @@
+# GUI for the Moon project
+This directory contains all the code for the Moon project
+It is designed to provide a running GUI of the Moon platform instance.
+
+## Usage
+- Prerequist
+ - `sudo apt-get install nodejs nodejs-legacy`
+ - `sudo npm install --global gulp-cli`
+- Install all packages
+ - `cd $MOON_HOME/moon_gui`
+ - `sudo npm install`
+- Run the GUI
+ - `gulp webServerDelivery`
+ - Open your web browser
+
+## Configuration
+- build the delivery package: `gulp delivery`
+- launch the Web Server: `gulp webServerDelivery`
+
+## Development
+- during the development it is possible to use following commands: `gulp build`
+- launch a Web Server: `gulp webServer`
+- Gulp webServer will refresh the browser when a file related to the application changed
+- it is possible to change some constants (API endpoints): `$MOON_HOME/moon_gui/static/app/moon.constants.js`
+
+## CORS
+The GUI need to connect itself to Keystone and Moon.
+Opening CORS to the GUI WebServer is required.
+- modify Keystone: `$MOON_HOME/tools/moon_keystone/run.sh`
+- modify Moon: `$MOON_HOME/moon_interface/interface/http_server.py`
+
+## Usage
+After authentication, you will see 4 tabs: Project, Models, Policies, PDP:
+
+* *Projects*: configure mapping between Keystone projects and PDP (Policy Decision Point)
+* *Models*: configure templates of policies (for example RBAC or MLS)
+* *Policies*: applied models or instantiated models ;
+on one policy, you map a authorisation model and set subject, objects and action that will
+rely on that model
+* *PDP*: Policy Decision Point, this is the link between Policies and Keystone Project
+
+In the following paragraphs, we will add a new user in OpenStack and allow her to list
+all VM on the OpenStack platform.
+
+First, add a new user and a new project in the OpenStack platform:
+
+ openstack user create --password-prompt demo_user
+ openstack project create demo
+ DEMO_USER=$(openstack user list | grep demo_user | cut -d " " -f 2)
+ DEMO_PROJECT=$(openstack project list | grep demo | cut -d " " -f 2)
+ openstack role add --user $DEMO_USER --project $DEMO_PROJECT admin
+
+You have to add the same user in the Moon interface:
+
+1. go to the `Projects` tab in the Moon interface
+1. go to the line corresponding to the new project and click to the `Map to a PDP` link
+1. select in the combobox the MLS PDP and click `OK`
+1. in the Moon interface, go to the `Policy` tab
+1. go to the line corresponding to the MLS policy and click on the `actions->edit` button
+1. scroll to the `Perimeters` line and click on the `show` link to show the perimeter configuration
+1. go to the `Add a subject` line and click on `Add a new perimeter`
+1. set the name of that subject to `demo_user` (*the name must be strictly identical*)
+1. in the combobox named `Policy list` select the `MLS` policy and click on the `+` button
+1. click on the yellow `Add Perimeter` button
+1. go to the `Assignment` line and click on the `show` button
+1. under the `Add a Assignments Subject` select the MLS policy,
+the new user (`demo_user`), the category `subject_category_level`
+1. in the `Select a Data` line, choose the `High` scope and click on the `+` link
+1. click on the yellow `Create Assignments` button
+1. if you go to the OpenStack platform, the `demo_user` is now allow to connect
+to the Nova component (test with `openstack server list` connected with the `demo_user`) \ No newline at end of file
diff --git a/old/moon_gui/delivery/assets/css/main.css b/old/moon_gui/delivery/assets/css/main.css
new file mode 100644
index 00000000..3aefca39
--- /dev/null
+++ b/old/moon_gui/delivery/assets/css/main.css
@@ -0,0 +1,10 @@
+/*!
+ * Bootstrap v3.2.0 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ *//*! normalize.css v3.0.1 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}@media print{*{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:transparent}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:focus,a:hover{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}cite{font-style:normal}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#428bca}a.text-primary:hover{color:#3071a9}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}blockquote:after,blockquote:before{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#777;opacity:1}.form-control:-ms-input-placeholder{color:#777}.form-control::-webkit-input-placeholder{color:#777}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{line-height:34px}input[type=date].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm,input[type=time].input-sm{line-height:30px}input[type=date].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg,input[type=time].input-lg{line-height:46px}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;min-height:20px;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.form-horizontal .form-group-sm .form-control,.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-horizontal .form-group-lg .form-control,.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:25px;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{top:0;right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.3px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active:focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.active,.btn-default:active,.btn-default:focus,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary.active,.btn-primary:active,.btn-primary:focus,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#3071a9;border-color:#285e8e}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.active,.btn-success:active,.btn-success:focus,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.active,.btn-info:active,.btn-info:focus,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.active,.btn-warning:active,.btn-warning:focus,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.active,.btn-danger:active,.btn-danger:focus,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#428bca;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group-vertical>.btn:focus,.btn-group>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn>input[type=checkbox],[data-toggle=buttons]>.btn>input[type=radio]{position:absolute;z-index:-1;opacity:0}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030;-webkit-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#777}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#777}.navbar-inverse .navbar-nav>li>a{color:#777}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#777}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#777}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#428bca;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#428bca}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.nav-pills>.active>a>.badge,a.list-group-item.active>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar[aria-valuenow="1"],.progress-bar[aria-valuenow="2"]{min-width:30px}.progress-bar[aria-valuenow="0"]{min-width:30px;color:#777;background-color:transparent;background-image:none;-webkit-box-shadow:none;box-shadow:none}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#428bca}.panel-primary>.panel-heading .badge{color:#428bca;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate3d(0,-25%,0);-o-transform:translate3d(0,-25%,0);transform:translate3d(0,-25%,0)}.modal.in .modal-dialog{-webkit-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.in{opacity:.5}.modal-header{min-height:16.42857143px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-size:12px;line-height:1.4;visibility:visible;opacity:0}.tooltip.in{opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;margin-top:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed;-webkit-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}.ng-table th{text-align:center;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ng-table th.sortable{cursor:pointer}.ng-table th.sortable .sort-indicator{padding-right:18px;position:relative}.ng-table th.sortable .sort-indicator:after,.ng-table th.sortable .sort-indicator:before{content:"";border-width:0 4px 4px;border-style:solid;border-color:#000 transparent;visibility:visible;right:5px;top:50%;position:absolute;opacity:.3;margin-top:-4px}.ng-table th.sortable .sort-indicator:before{margin-top:2px;border-bottom:none;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000}.ng-table th.sortable .sort-indicator:hover:after,.ng-table th.sortable .sort-indicator:hover:before{opacity:1;visibility:visible}.ng-table th.sortable.sort-asc,.ng-table th.sortable.sort-desc{background-color:rgba(141,192,219,.25);text-shadow:0 1px 1px rgba(255,255,255,.75)}.ng-table th.sortable.sort-asc .sort-indicator:after,.ng-table th.sortable.sort-desc .sort-indicator:after{margin-top:-2px}.ng-table th.sortable.sort-asc .sort-indicator:before,.ng-table th.sortable.sort-desc .sort-indicator:before{visibility:hidden}.ng-table th.sortable.sort-asc .sort-indicator:after,.ng-table th.sortable.sort-asc .sort-indicator:hover:after{visibility:visible;-khtml-opacity:.6;-moz-opacity:.6;opacity:.6}.ng-table th.sortable.sort-desc .sort-indicator:after{border-bottom:none;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000;visibility:visible;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;-khtml-opacity:.6;-moz-opacity:.6;opacity:.6}.ng-table th.filter .input-filter{margin:0;display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.ng-table+.pagination{margin-top:0}@media only screen and (max-width:800px){.ng-table-responsive{border-bottom:1px solid #999}.ng-table-responsive tr{border-top:1px solid #999;border-left:1px solid #999;border-right:1px solid #999}.ng-table-responsive td:before{position:absolute;padding:8px;left:0;top:0;width:50%;white-space:nowrap;text-align:left;font-weight:700}.ng-table-responsive thead tr th{text-align:left}.ng-table-responsive thead tr.ng-table-filters th{padding:0}.ng-table-responsive thead tr.ng-table-filters th form>div{padding:8px}.ng-table-responsive td{border:none;border-bottom:1px solid #eee;position:relative;padding-left:50%;white-space:normal;text-align:left}.ng-table-responsive td:before{content:attr(data-title-text)}.ng-table-responsive,.ng-table-responsive tbody,.ng-table-responsive td,.ng-table-responsive th,.ng-table-responsive thead,.ng-table-responsive tr{display:block}}.select2-container{margin:0;position:relative;display:inline-block;zoom:1;vertical-align:middle}.select2-container,.select2-drop,.select2-search,.select2-search input{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.select2-container .select2-choice{display:block;height:26px;padding:0 0 0 8px;overflow:hidden;position:relative;border:1px solid #aaa;white-space:nowrap;line-height:26px;color:#444;text-decoration:none;border-radius:4px;background-clip:padding-box;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#fff;background-image:-webkit-gradient(linear,left bottom,left top,color-stop(0,#eee),color-stop(.5,#fff));background-image:-webkit-linear-gradient(center bottom,#eee 0,#fff 50%);background-image:-moz-linear-gradient(center bottom,#eee 0,#fff 50%);background-image:linear-gradient(to top,#eee 0,#fff 50%)}html[dir=rtl] .select2-container .select2-choice{padding:0 8px 0 0}.select2-container.select2-drop-above .select2-choice{border-bottom-color:#aaa;border-radius:0 0 4px 4px;background-image:-webkit-gradient(linear,left bottom,left top,color-stop(0,#eee),color-stop(.9,#fff));background-image:-webkit-linear-gradient(center bottom,#eee 0,#fff 90%);background-image:-moz-linear-gradient(center bottom,#eee 0,#fff 90%);background-image:linear-gradient(to bottom,#eee 0,#fff 90%)}.select2-container.select2-allowclear .select2-choice .select2-chosen{margin-right:42px}.select2-container .select2-choice>.select2-chosen{margin-right:26px;display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;float:none;width:auto}html[dir=rtl] .select2-container .select2-choice>.select2-chosen{margin-left:26px;margin-right:0}.select2-container .select2-choice abbr{display:none;width:12px;height:12px;position:absolute;right:24px;top:8px;font-size:1px;text-decoration:none;border:0;background:url(select2.png) right top no-repeat;cursor:pointer;outline:0}.select2-container.select2-allowclear .select2-choice abbr{display:inline-block}.select2-container .select2-choice abbr:hover{background-position:right -11px;cursor:pointer}.select2-drop-mask{border:0;margin:0;padding:0;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:9998;background-color:#fff}.select2-drop{width:100%;margin-top:-1px;position:absolute;z-index:9999;top:100%;background:#fff;color:#000;border:1px solid #aaa;border-top:0;border-radius:0 0 4px 4px;-webkit-box-shadow:0 4px 5px rgba(0,0,0,.15);box-shadow:0 4px 5px rgba(0,0,0,.15)}.select2-drop.select2-drop-above{margin-top:1px;border-top:1px solid #aaa;border-bottom:0;border-radius:4px 4px 0 0;-webkit-box-shadow:0 -4px 5px rgba(0,0,0,.15);box-shadow:0 -4px 5px rgba(0,0,0,.15)}.select2-drop-active{border:1px solid #5897fb;border-top:none}.select2-drop.select2-drop-above.select2-drop-active{border-top:1px solid #5897fb}.select2-drop-auto-width{border-top:1px solid #aaa;width:auto}.select2-drop-auto-width .select2-search{padding-top:4px}.select2-container .select2-choice .select2-arrow{display:inline-block;width:18px;height:100%;position:absolute;right:0;top:0;border-left:1px solid #aaa;border-radius:0 4px 4px 0;background-clip:padding-box;background:#ccc;background-image:-webkit-gradient(linear,left bottom,left top,color-stop(0,#ccc),color-stop(.6,#eee));background-image:-webkit-linear-gradient(center bottom,#ccc 0,#eee 60%);background-image:-moz-linear-gradient(center bottom,#ccc 0,#eee 60%);background-image:linear-gradient(to top,#ccc 0,#eee 60%)}html[dir=rtl] .select2-container .select2-choice .select2-arrow{left:0;right:auto;border-left:none;border-right:1px solid #aaa;border-radius:4px 0 0 4px}.select2-container .select2-choice .select2-arrow b{display:block;width:100%;height:100%;background:url(select2.png) no-repeat 0 1px}html[dir=rtl] .select2-container .select2-choice .select2-arrow b{background-position:2px 1px}.select2-search{display:inline-block;width:100%;min-height:26px;margin:0;padding-left:4px;padding-right:4px;position:relative;z-index:10000;white-space:nowrap}.select2-search input{width:100%;height:auto!important;min-height:26px;padding:4px 20px 4px 5px;margin:0;outline:0;font-family:sans-serif;font-size:1em;border:1px solid #aaa;border-radius:0;-webkit-box-shadow:none;box-shadow:none;background:#fff url(select2.png) no-repeat 100% -22px;background:url(select2.png) no-repeat 100% -22px,-webkit-gradient(linear,left bottom,left top,color-stop(.85,#fff),color-stop(.99,#eee));background:url(select2.png) no-repeat 100% -22px,-webkit-linear-gradient(center bottom,#fff 85%,#eee 99%);background:url(select2.png) no-repeat 100% -22px,-moz-linear-gradient(center bottom,#fff 85%,#eee 99%);background:url(select2.png) no-repeat 100% -22px,linear-gradient(to bottom,#fff 85%,#eee 99%) 0 0}html[dir=rtl] .select2-search input{padding:4px 5px 4px 20px;background:#fff url(select2.png) no-repeat -37px -22px;background:url(select2.png) no-repeat -37px -22px,-webkit-gradient(linear,left bottom,left top,color-stop(.85,#fff),color-stop(.99,#eee));background:url(select2.png) no-repeat -37px -22px,-webkit-linear-gradient(center bottom,#fff 85%,#eee 99%);background:url(select2.png) no-repeat -37px -22px,-moz-linear-gradient(center bottom,#fff 85%,#eee 99%);background:url(select2.png) no-repeat -37px -22px,linear-gradient(to bottom,#fff 85%,#eee 99%) 0 0}.select2-drop.select2-drop-above .select2-search input{margin-top:4px}.select2-search input.select2-active{background:#fff url(select2-spinner.gif) no-repeat 100%;background:url(select2-spinner.gif) no-repeat 100%,-webkit-gradient(linear,left bottom,left top,color-stop(.85,#fff),color-stop(.99,#eee));background:url(select2-spinner.gif) no-repeat 100%,-webkit-linear-gradient(center bottom,#fff 85%,#eee 99%);background:url(select2-spinner.gif) no-repeat 100%,-moz-linear-gradient(center bottom,#fff 85%,#eee 99%);background:url(select2-spinner.gif) no-repeat 100%,linear-gradient(to bottom,#fff 85%,#eee 99%) 0 0}.select2-container-active .select2-choice,.select2-container-active .select2-choices{border:1px solid #5897fb;outline:0;-webkit-box-shadow:0 0 5px rgba(0,0,0,.3);box-shadow:0 0 5px rgba(0,0,0,.3)}.select2-dropdown-open .select2-choice{border-bottom-color:transparent;-webkit-box-shadow:0 1px 0 #fff inset;box-shadow:0 1px 0 #fff inset;border-bottom-left-radius:0;border-bottom-right-radius:0;background-color:#eee;background-image:-webkit-gradient(linear,left bottom,left top,color-stop(0,#fff),color-stop(.5,#eee));background-image:-webkit-linear-gradient(center bottom,#fff 0,#eee 50%);background-image:-moz-linear-gradient(center bottom,#fff 0,#eee 50%);background-image:linear-gradient(to top,#fff 0,#eee 50%)}.select2-dropdown-open.select2-drop-above .select2-choice,.select2-dropdown-open.select2-drop-above .select2-choices{border:1px solid #5897fb;border-top-color:transparent;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(.5,#eee));background-image:-webkit-linear-gradient(center top,#fff 0,#eee 50%);background-image:-moz-linear-gradient(center top,#fff 0,#eee 50%);background-image:linear-gradient(to bottom,#fff 0,#eee 50%)}.select2-dropdown-open .select2-choice .select2-arrow{background:0 0;border-left:none;filter:none}html[dir=rtl] .select2-dropdown-open .select2-choice .select2-arrow{border-right:none}.select2-dropdown-open .select2-choice .select2-arrow b{background-position:-18px 1px}html[dir=rtl] .select2-dropdown-open .select2-choice .select2-arrow b{background-position:-16px 1px}.select2-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.select2-results{max-height:200px;padding:0 0 0 4px;margin:4px 4px 4px 0;position:relative;overflow-x:hidden;overflow-y:auto;-webkit-tap-highlight-color:transparent}html[dir=rtl] .select2-results{padding:0 4px 0 0;margin:4px 0 4px 4px}.select2-results ul.select2-result-sub{margin:0;padding-left:0}.select2-results li{list-style:none;display:list-item;background-image:none}.select2-results li.select2-result-with-children>.select2-result-label{font-weight:700}.select2-results .select2-result-label{padding:3px 7px 4px;margin:0;cursor:pointer;min-height:1em;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.select2-results-dept-1 .select2-result-label{padding-left:20px}.select2-results-dept-2 .select2-result-label{padding-left:40px}.select2-results-dept-3 .select2-result-label{padding-left:60px}.select2-results-dept-4 .select2-result-label{padding-left:80px}.select2-results-dept-5 .select2-result-label{padding-left:100px}.select2-results-dept-6 .select2-result-label{padding-left:110px}.select2-results-dept-7 .select2-result-label{padding-left:120px}.select2-results .select2-highlighted{background:#3875d7;color:#fff}.select2-results li em{background:#feffde;font-style:normal}.select2-results .select2-highlighted em{background:0 0}.select2-results .select2-highlighted ul{background:#fff;color:#000}.select2-results .select2-ajax-error,.select2-results .select2-no-results,.select2-results .select2-searching,.select2-results .select2-selection-limit{background:#f4f4f4;display:list-item;padding-left:5px}.select2-results .select2-disabled.select2-highlighted{color:#666;background:#f4f4f4;display:list-item;cursor:default}.select2-results .select2-disabled{background:#f4f4f4;display:list-item;cursor:default}.select2-results .select2-selected{display:none}.select2-more-results.select2-active{background:#f4f4f4 url(select2-spinner.gif) no-repeat 100%}.select2-results .select2-ajax-error{background:rgba(255,50,50,.2)}.select2-more-results{background:#f4f4f4;display:list-item}.select2-container.select2-container-disabled .select2-choice{background-color:#f4f4f4;background-image:none;border:1px solid #ddd;cursor:default}.select2-container.select2-container-disabled .select2-choice .select2-arrow{background-color:#f4f4f4;background-image:none;border-left:0}.select2-container.select2-container-disabled .select2-choice abbr{display:none}.select2-container-multi .select2-choices{height:auto!important;height:1%;margin:0;padding:0 5px 0 0;position:relative;border:1px solid #aaa;cursor:text;overflow:hidden;background-color:#fff;background-image:-webkit-gradient(linear,0 0,0 100%,color-stop(1%,#eee),color-stop(15%,#fff));background-image:-webkit-linear-gradient(top,#eee 1%,#fff 15%);background-image:-moz-linear-gradient(top,#eee 1%,#fff 15%);background-image:linear-gradient(to bottom,#eee 1%,#fff 15%)}html[dir=rtl] .select2-container-multi .select2-choices{padding:0 0 0 5px}.select2-locked{padding:3px 5px 3px 5px!important}.select2-container-multi .select2-choices{min-height:26px}.select2-container-multi.select2-container-active .select2-choices{border:1px solid #5897fb;outline:0;-webkit-box-shadow:0 0 5px rgba(0,0,0,.3);box-shadow:0 0 5px rgba(0,0,0,.3)}.select2-container-multi .select2-choices li{float:left;list-style:none}html[dir=rtl] .select2-container-multi .select2-choices li{float:right}.select2-container-multi .select2-choices .select2-search-field{margin:0;padding:0;white-space:nowrap}.select2-container-multi .select2-choices .select2-search-field input{padding:5px;margin:1px 0;font-family:sans-serif;font-size:100%;color:#666;outline:0;border:0;-webkit-box-shadow:none;box-shadow:none;background:0 0!important}.select2-container-multi .select2-choices .select2-search-field input.select2-active{background:#fff url(select2-spinner.gif) no-repeat 100%!important}.select2-default{color:#999!important}.select2-container-multi .select2-choices .select2-search-choice{padding:3px 5px 3px 18px;margin:3px 0 3px 5px;position:relative;line-height:13px;color:#333;cursor:default;border:1px solid #aaa;border-radius:3px;-webkit-box-shadow:0 0 2px #fff inset,0 1px 0 rgba(0,0,0,.05);box-shadow:0 0 2px #fff inset,0 1px 0 rgba(0,0,0,.05);background-clip:padding-box;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#e4e4e4;background-image:-webkit-gradient(linear,0 0,0 100%,color-stop(20%,#f4f4f4),color-stop(50%,#f0f0f0),color-stop(52%,#e8e8e8),color-stop(100%,#eee));background-image:-webkit-linear-gradient(top,#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);background-image:-moz-linear-gradient(top,#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);background-image:linear-gradient(to bottom,#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%)}html[dir=rtl] .select2-container-multi .select2-choices .select2-search-choice{margin:3px 5px 3px 0;padding:3px 18px 3px 5px}.select2-container-multi .select2-choices .select2-search-choice .select2-chosen{cursor:default}.select2-container-multi .select2-choices .select2-search-choice-focus{background:#d4d4d4}.select2-search-choice-close{display:block;width:12px;height:13px;position:absolute;right:3px;top:4px;font-size:1px;outline:0;background:url(select2.png) right top no-repeat}html[dir=rtl] .select2-search-choice-close{right:auto;left:3px}.select2-container-multi .select2-search-choice-close{left:3px}html[dir=rtl] .select2-container-multi .select2-search-choice-close{left:auto;right:2px}.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover{background-position:right -11px}.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close{background-position:right -11px}.select2-container-multi.select2-container-disabled .select2-choices{background-color:#f4f4f4;background-image:none;border:1px solid #ddd;cursor:default}.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice{padding:3px 5px 3px 5px;border:1px solid #ddd;background-image:none;background-color:#f4f4f4}.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close{display:none;background:0 0}.select2-result-selectable .select2-match,.select2-result-unselectable .select2-match{text-decoration:underline}.select2-offscreen,.select2-offscreen:focus{clip:rect(0 0 0 0)!important;width:1px!important;height:1px!important;border:0!important;margin:0!important;padding:0!important;overflow:hidden!important;position:absolute!important;outline:0!important;left:0!important;top:0!important}.select2-display-none{display:none}.select2-measure-scrollbar{position:absolute;top:-10000px;left:-10000px;width:100px;height:100px;overflow:scroll}@media only screen and (-webkit-min-device-pixel-ratio:1.5),only screen and (min-resolution:2dppx){.select2-container .select2-choice .select2-arrow b,.select2-container .select2-choice abbr,.select2-search input,.select2-search-choice-close{background-image:url(select2x2.png)!important;background-repeat:no-repeat!important;background-size:60px 40px!important}.select2-search input{background-position:100% -21px!important}}/*!
+ * ui-select
+ * http://github.com/angular-ui/ui-select
+ * Version: 0.12.1 - 2015-07-28T03:50:59.080Z
+ * License: MIT
+ */.ui-select-highlight{font-weight:700}.ui-select-offscreen{clip:rect(0 0 0 0)!important;width:1px!important;height:1px!important;border:0!important;margin:0!important;padding:0!important;overflow:hidden!important;position:absolute!important;outline:0!important;left:0!important;top:0!important}.ng-dirty.ng-invalid>a.select2-choice{border-color:#d44950}.select2-result-single{padding-left:0}.select2-locked>.select2-search-choice-close{display:none}.select-locked>.ui-select-match-close{display:none}body>.select2-container.open{z-index:9999}.ui-select-container[theme=select2].direction-up .ui-select-match{border-radius:4px;border-top-left-radius:0;border-top-right-radius:0}.ui-select-container[theme=select2].direction-up .ui-select-dropdown{border-radius:4px;border-bottom-left-radius:0;border-bottom-right-radius:0;border-top-width:1px;border-top-style:solid;box-shadow:0 -4px 8px rgba(0,0,0,.25);margin-top:-4px}.ui-select-container[theme=select2].direction-up .ui-select-dropdown .select2-search{margin-top:4px}.ui-select-container[theme=select2].direction-up.select2-dropdown-open .ui-select-match{border-bottom-color:#5897fb}.selectize-input.selectize-focus{border-color:#007fbb!important}.selectize-control>.selectize-input>input{width:100%}.selectize-control>.selectize-dropdown{width:100%}.ng-dirty.ng-invalid>div.selectize-input{border-color:#d44950}.ui-select-container[theme=selectize].direction-up .ui-select-dropdown{box-shadow:0 -4px 8px rgba(0,0,0,.25);margin-top:-2px}.btn-default-focus{color:#333;background-color:#ebebeb;border-color:#adadad;text-decoration:none;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.ui-select-bootstrap .ui-select-toggle{position:relative}.ui-select-bootstrap .ui-select-toggle>.caret{position:absolute;height:10px;top:50%;right:10px;margin-top:-2px}.input-group>.ui-select-bootstrap.dropdown{position:static}.input-group>.ui-select-bootstrap>input.ui-select-search.form-control{border-radius:4px;border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.ui-select-bootstrap>input.ui-select-search.form-control.direction-up{border-radius:4px!important;border-top-right-radius:0!important;border-bottom-right-radius:0!important}.ui-select-bootstrap>.ui-select-match>.btn{text-align:left!important}.ui-select-bootstrap>.ui-select-match>.caret{position:absolute;top:45%;right:15px}.ui-select-bootstrap>.ui-select-choices{width:100%;height:auto;max-height:200px;overflow-x:hidden;margin-top:-1px}body>.ui-select-bootstrap.open{z-index:1000}.ui-select-multiple.ui-select-bootstrap{height:auto;padding:3px 3px 0 3px}.ui-select-multiple.ui-select-bootstrap input.ui-select-search{background-color:transparent!important;border:none;outline:0;height:1.666666em;margin-bottom:3px}.ui-select-multiple.ui-select-bootstrap .ui-select-match .close{font-size:1.6em;line-height:.75}.ui-select-multiple.ui-select-bootstrap .ui-select-match-item{outline:0;margin:0 3px 3px 0}.ui-select-multiple .ui-select-match-item{position:relative}.ui-select-multiple .ui-select-match-item.dropping-before:before{content:"";position:absolute;top:0;right:100%;height:100%;margin-right:2px;border-left:1px solid #428bca}.ui-select-multiple .ui-select-match-item.dropping-after:after{content:"";position:absolute;top:0;left:100%;height:100%;margin-left:2px;border-right:1px solid #428bca}.ui-select-bootstrap .ui-select-choices-row>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.ui-select-bootstrap .ui-select-choices-row>a:focus,.ui-select-bootstrap .ui-select-choices-row>a:hover{text-decoration:none;color:#262626;background-color:#f5f5f5}.ui-select-bootstrap .ui-select-choices-row.active>a{color:#fff;text-decoration:none;outline:0;background-color:#428bca}.ui-select-bootstrap .ui-select-choices-row.active.disabled>a,.ui-select-bootstrap .ui-select-choices-row.disabled>a{color:#777;cursor:not-allowed;background-color:#fff}.ui-select-match.ng-hide-add,.ui-select-search.ng-hide-add{display:none!important}.ui-select-bootstrap.ng-dirty.ng-invalid>button.btn.ui-select-match{border-color:#d44950}.ui-select-container[theme=bootstrap].direction-up .ui-select-dropdown{box-shadow:0 -4px 8px rgba(0,0,0,.25)}.selectize-control.plugin-drag_drop.multi>.selectize-input>div.ui-sortable-placeholder{visibility:visible!important;background:#f2f2f2!important;background:rgba(0,0,0,.06)!important;border:0 none!important;-webkit-box-shadow:inset 0 0 12px 4px #fff;box-shadow:inset 0 0 12px 4px #fff}.selectize-control.plugin-drag_drop .ui-sortable-placeholder::after{content:'!';visibility:hidden}.selectize-control.plugin-drag_drop .ui-sortable-helper{-webkit-box-shadow:0 2px 5px rgba(0,0,0,.2);box-shadow:0 2px 5px rgba(0,0,0,.2)}.selectize-dropdown-header{position:relative;padding:5px 8px;border-bottom:1px solid #d0d0d0;background:#f8f8f8;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0}.selectize-dropdown-header-close{position:absolute;right:8px;top:50%;color:#303030;opacity:.4;margin-top:-12px;line-height:20px;font-size:20px!important}.selectize-dropdown-header-close:hover{color:#000}.selectize-dropdown.plugin-optgroup_columns .optgroup{border-right:1px solid #f2f2f2;border-top:0 none;float:left;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.selectize-dropdown.plugin-optgroup_columns .optgroup:last-child{border-right:0 none}.selectize-dropdown.plugin-optgroup_columns .optgroup:before{display:none}.selectize-dropdown.plugin-optgroup_columns .optgroup-header{border-top:0 none}.selectize-control.plugin-remove_button [data-value]{position:relative;padding-right:24px!important}.selectize-control.plugin-remove_button [data-value] .remove{z-index:1;position:absolute;top:0;right:0;bottom:0;width:17px;text-align:center;font-weight:700;font-size:12px;color:inherit;text-decoration:none;vertical-align:middle;display:inline-block;padding:2px 0 0 0;border-left:1px solid #0073bb;-webkit-border-radius:0 2px 2px 0;-moz-border-radius:0 2px 2px 0;border-radius:0 2px 2px 0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.selectize-control.plugin-remove_button [data-value] .remove:hover{background:rgba(0,0,0,.05)}.selectize-control.plugin-remove_button [data-value].active .remove{border-left-color:#00578d}.selectize-control.plugin-remove_button .disabled [data-value] .remove:hover{background:0 0}.selectize-control.plugin-remove_button .disabled [data-value] .remove{border-left-color:#aaa}.selectize-control{position:relative}.selectize-dropdown,.selectize-input,.selectize-input input{color:#303030;font-family:inherit;font-size:13px;line-height:18px;-webkit-font-smoothing:inherit}.selectize-control.single .selectize-input.input-active,.selectize-input{background:#fff;cursor:text;display:inline-block}.selectize-input{border:1px solid #d0d0d0;padding:8px 8px;display:inline-block;width:100%;overflow:hidden;position:relative;z-index:1;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.1);box-shadow:inset 0 1px 1px rgba(0,0,0,.1);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.selectize-control.multi .selectize-input.has-items{padding:5px 8px 2px}.selectize-input.full{background-color:#fff}.selectize-input.disabled,.selectize-input.disabled *{cursor:default!important}.selectize-input.focus{-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.15)}.selectize-input.dropdown-active{-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0}.selectize-input>*{vertical-align:baseline;display:-moz-inline-stack;display:inline-block;zoom:1}.selectize-control.multi .selectize-input>div{cursor:pointer;margin:0 3px 3px 0;padding:2px 6px;background:#1da7ee;color:#fff;border:1px solid #0073bb}.selectize-control.multi .selectize-input>div.active{background:#92c836;color:#fff;border:1px solid #00578d}.selectize-control.multi .selectize-input.disabled>div,.selectize-control.multi .selectize-input.disabled>div.active{color:#fff;background:#d2d2d2;border:1px solid #aaa}.selectize-input>input{display:inline-block!important;padding:0!important;min-height:0!important;max-height:none!important;max-width:100%!important;margin:0 1px!important;text-indent:0!important;border:0 none!important;background:0 0!important;line-height:inherit!important;-webkit-user-select:auto!important;-webkit-box-shadow:none!important;box-shadow:none!important}.selectize-input>input::-ms-clear{display:none}.selectize-input>input:focus{outline:0!important}.selectize-input::after{content:' ';display:block;clear:left}.selectize-input.dropdown-active::before{content:' ';display:block;position:absolute;background:#f0f0f0;height:1px;bottom:0;left:0;right:0}.selectize-dropdown{position:absolute;z-index:10;border:1px solid #d0d0d0;background:#fff;margin:-1px 0 0 0;border-top:0 none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.1);box-shadow:0 1px 3px rgba(0,0,0,.1);-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px}.selectize-dropdown [data-selectable]{cursor:pointer;overflow:hidden}.selectize-dropdown [data-selectable] .highlight{background:rgba(125,168,208,.2);-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}.selectize-dropdown .optgroup-header,.selectize-dropdown [data-selectable]{padding:5px 8px}.selectize-dropdown .optgroup:first-child .optgroup-header{border-top:0 none}.selectize-dropdown .optgroup-header{color:#303030;background:#fff;cursor:default}.selectize-dropdown .active{background-color:#f5fafd;color:#495c68}.selectize-dropdown .active.create{color:#495c68}.selectize-dropdown .create{color:rgba(48,48,48,.5)}.selectize-dropdown-content{overflow-y:auto;overflow-x:hidden;max-height:200px}.selectize-control.single .selectize-input,.selectize-control.single .selectize-input input{cursor:pointer}.selectize-control.single .selectize-input.input-active,.selectize-control.single .selectize-input.input-active input{cursor:text}.selectize-control.single .selectize-input:after{content:' ';display:block;position:absolute;top:50%;right:15px;margin-top:-3px;width:0;height:0;border-style:solid;border-width:5px 5px 0 5px;border-color:grey transparent transparent transparent}.selectize-control.single .selectize-input.dropdown-active:after{margin-top:-4px;border-width:0 5px 5px 5px;border-color:transparent transparent grey transparent}.selectize-control.rtl.single .selectize-input:after{left:15px;right:auto}.selectize-control.rtl .selectize-input>input{margin:0 4px 0 -2px!important}.selectize-control .selectize-input.disabled{opacity:.5;background-color:#fafafa}.selectize-control.multi .selectize-input.has-items{padding-left:5px;padding-right:5px}.selectize-control.multi .selectize-input.disabled [data-value]{color:#999;text-shadow:none;background:0 0;-webkit-box-shadow:none;box-shadow:none}.selectize-control.multi .selectize-input.disabled [data-value],.selectize-control.multi .selectize-input.disabled [data-value] .remove{border-color:#e6e6e6}.selectize-control.multi .selectize-input.disabled [data-value] .remove{background:0 0}.selectize-control.multi .selectize-input [data-value]{text-shadow:0 1px 0 rgba(0,51,83,.3);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background-color:#1b9dec;background-image:-moz-linear-gradient(top,#1da7ee,#178ee9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#1da7ee),to(#178ee9));background-image:-webkit-linear-gradient(top,#1da7ee,#178ee9);background-image:-o-linear-gradient(top,#1da7ee,#178ee9);background-image:linear-gradient(to bottom,#1da7ee,#178ee9);background-repeat:repeat-x;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 1px rgba(255,255,255,.03);box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 1px rgba(255,255,255,.03)}.selectize-control.multi .selectize-input [data-value].active{background-color:#0085d4;background-image:-moz-linear-gradient(top,#008fd8,#0075cf);background-image:-webkit-gradient(linear,0 0,0 100%,from(#008fd8),to(#0075cf));background-image:-webkit-linear-gradient(top,#008fd8,#0075cf);background-image:-o-linear-gradient(top,#008fd8,#0075cf);background-image:linear-gradient(to bottom,#008fd8,#0075cf);background-repeat:repeat-x}.selectize-control.single .selectize-input{-webkit-box-shadow:0 1px 0 rgba(0,0,0,.05),inset 0 1px 0 rgba(255,255,255,.8);box-shadow:0 1px 0 rgba(0,0,0,.05),inset 0 1px 0 rgba(255,255,255,.8);background-color:#f9f9f9;background-image:-moz-linear-gradient(top,#fefefe,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fefefe),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fefefe,#f2f2f2);background-image:-o-linear-gradient(top,#fefefe,#f2f2f2);background-image:linear-gradient(to bottom,#fefefe,#f2f2f2);background-repeat:repeat-x}.selectize-control.single .selectize-input,.selectize-dropdown.single{border-color:#b8b8b8}.selectize-dropdown .optgroup-header{padding-top:7px;font-weight:700;font-size:.85em}.selectize-dropdown .optgroup{border-top:1px solid #f0f0f0}.selectize-dropdown .optgroup:first-child{border-top:0 none}.am-fade-and-scale{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-fill-mode:backwards;animation-fill-mode:backwards}.am-fade-and-scale.am-fade-and-scale-add,.am-fade-and-scale.ng-enter,.am-fade-and-scale.ng-hide-remove,.am-fade-and-scale.ng-move{-webkit-animation-name:fadeAndScaleIn;animation-name:fadeAndScaleIn}.am-fade-and-scale.am-fade-and-scale-remove,.am-fade-and-scale.ng-hide,.am-fade-and-scale.ng-leave{-webkit-animation-name:fadeAndScaleOut;animation-name:fadeAndScaleOut}.am-fade-and-scale.ng-enter{visibility:hidden;-webkit-animation-name:fadeAndScaleIn;animation-name:fadeAndScaleIn;-webkit-animation-play-state:paused;animation-play-state:paused}.am-fade-and-scale.ng-enter.ng-enter-active{visibility:visible;-webkit-animation-play-state:running;animation-play-state:running}.am-fade-and-scale.ng-leave{-webkit-animation-name:fadeAndScaleOut;animation-name:fadeAndScaleOut;-webkit-animation-play-state:paused;animation-play-state:paused}.am-fade-and-scale.ng-leave.ng-leave-active{-webkit-animation-play-state:running;animation-play-state:running}@-webkit-keyframes fadeAndScaleIn{from{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}to{opacity:1}}@keyframes fadeAndScaleIn{from{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}to{opacity:1}}@-webkit-keyframes fadeAndScaleOut{from{opacity:1}to{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}}@keyframes fadeAndScaleOut{from{opacity:1}to{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}}.am-fade-and-slide-top{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-fill-mode:backwards;animation-fill-mode:backwards}.am-fade-and-slide-top.am-fade-and-slide-top-add,.am-fade-and-slide-top.ng-hide-remove,.am-fade-and-slide-top.ng-move{-webkit-animation-name:fadeAndSlideFromTop;animation-name:fadeAndSlideFromTop}.am-fade-and-slide-top.am-fade-and-slide-top-remove,.am-fade-and-slide-top.ng-hide{-webkit-animation-name:fadeAndSlideToTop;animation-name:fadeAndSlideToTop}.am-fade-and-slide-top.ng-enter{visibility:hidden;-webkit-animation-name:fadeAndSlideFromTop;animation-name:fadeAndSlideFromTop;-webkit-animation-play-state:paused;animation-play-state:paused}.am-fade-and-slide-top.ng-enter.ng-enter-active{visibility:visible;-webkit-animation-play-state:running;animation-play-state:running}.am-fade-and-slide-top.ng-leave{-webkit-animation-name:fadeAndSlideToTop;animation-name:fadeAndSlideToTop;-webkit-animation-play-state:paused;animation-play-state:paused}.am-fade-and-slide-top.ng-leave.ng-leave-active{-webkit-animation-play-state:running;animation-play-state:running}.am-fade-and-slide-right{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-fill-mode:backwards;animation-fill-mode:backwards}.am-fade-and-slide-right.am-fade-and-slide-right-add,.am-fade-and-slide-right.ng-hide-remove,.am-fade-and-slide-right.ng-move{-webkit-animation-name:fadeAndSlideFromRight;animation-name:fadeAndSlideFromRight}.am-fade-and-slide-right.am-fade-and-slide-right-remove,.am-fade-and-slide-right.ng-hide{-webkit-animation-name:fadeAndSlideToRight;animation-name:fadeAndSlideToRight}.am-fade-and-slide-right.ng-enter{visibility:hidden;-webkit-animation-name:fadeAndSlideFromRight;animation-name:fadeAndSlideFromRight;-webkit-animation-play-state:paused;animation-play-state:paused}.am-fade-and-slide-right.ng-enter.ng-enter-active{visibility:visible;-webkit-animation-play-state:running;animation-play-state:running}.am-fade-and-slide-right.ng-leave{-webkit-animation-name:fadeAndSlideToRight;animation-name:fadeAndSlideToRight;-webkit-animation-play-state:paused;animation-play-state:paused}.am-fade-and-slide-right.ng-leave.ng-leave-active{-webkit-animation-play-state:running;animation-play-state:running}.am-fade-and-slide-bottom{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-fill-mode:backwards;animation-fill-mode:backwards}.am-fade-and-slide-bottom.am-fade-and-slide-bottom-add,.am-fade-and-slide-bottom.ng-hide-remove,.am-fade-and-slide-bottom.ng-move{-webkit-animation-name:fadeAndSlideFromBottom;animation-name:fadeAndSlideFromBottom}.am-fade-and-slide-bottom.am-fade-and-slide-bottom-remove,.am-fade-and-slide-bottom.ng-hide{-webkit-animation-name:fadeAndSlideToBottom;animation-name:fadeAndSlideToBottom}.am-fade-and-slide-bottom.ng-enter{visibility:hidden;-webkit-animation-name:fadeAndSlideFromBottom;animation-name:fadeAndSlideFromBottom;-webkit-animation-play-state:paused;animation-play-state:paused}.am-fade-and-slide-bottom.ng-enter.ng-enter-active{visibility:visible;-webkit-animation-play-state:running;animation-play-state:running}.am-fade-and-slide-bottom.ng-leave{-webkit-animation-name:fadeAndSlideToBottom;animation-name:fadeAndSlideToBottom;-webkit-animation-play-state:paused;animation-play-state:paused}.am-fade-and-slide-bottom.ng-leave.ng-leave-active{-webkit-animation-play-state:running;animation-play-state:running}.am-fade-and-slide-left{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-fill-mode:backwards;animation-fill-mode:backwards}.am-fade-and-slide-left.am-fade-and-slide-left-add,.am-fade-and-slide-left.ng-hide-remove,.am-fade-and-slide-left.ng-move{-webkit-animation-fill-mode:backwards;animation-fill-mode:backwards;-webkit-animation-name:fadeAndSlideFromLeft;animation-name:fadeAndSlideFromLeft}.am-fade-and-slide-left.am-fade-and-slide-left-remove,.am-fade-and-slide-left.ng-hide{-webkit-animation-name:fadeAndSlideToLeft;animation-name:fadeAndSlideToLeft}.am-fade-and-slide-left.ng-enter{visibility:hidden;-webkit-animation-name:fadeAndSlideFromLeft;animation-name:fadeAndSlideFromLeft;-webkit-animation-play-state:paused;animation-play-state:paused}.am-fade-and-slide-left.ng-enter.ng-enter-active{visibility:visible;-webkit-animation-play-state:running;animation-play-state:running}.am-fade-and-slide-left.ng-leave{-webkit-animation-name:fadeAndSlideToLeft;animation-name:fadeAndSlideToLeft;-webkit-animation-play-state:paused;animation-play-state:paused}.am-fade-and-slide-left.ng-leave.ng-leave-active{-webkit-animation-play-state:running;animation-play-state:running}@-webkit-keyframes fadeAndSlideFromTop{from{opacity:0;-webkit-transform:translateY(-20%);transform:translateY(-20%)}to{opacity:1}}@keyframes fadeAndSlideFromTop{from{opacity:0;-webkit-transform:translateY(-20%);transform:translateY(-20%)}to{opacity:1}}@-webkit-keyframes fadeAndSlideToTop{from{opacity:1}to{opacity:0;-webkit-transform:translateY(-20%);transform:translateY(-20%)}}@keyframes fadeAndSlideToTop{from{opacity:1}to{opacity:0;-webkit-transform:translateY(-20%);transform:translateY(-20%)}}@-webkit-keyframes fadeAndSlideFromRight{from{opacity:0;-webkit-transform:translateX(20%);transform:translateX(20%)}to{opacity:1}}@keyframes fadeAndSlideFromRight{from{opacity:0;-webkit-transform:translateX(20%);transform:translateX(20%)}to{opacity:1}}@-webkit-keyframes fadeAndSlideToRight{from{opacity:1}to{opacity:0;-webkit-transform:translateX(20%);transform:translateX(20%)}}@keyframes fadeAndSlideToRight{from{opacity:1}to{opacity:0;-webkit-transform:translateX(20%);transform:translateX(20%)}}@-webkit-keyframes fadeAndSlideFromBottom{from{opacity:0;-webkit-transform:translateY(20%);transform:translateY(20%)}to{opacity:1}}@keyframes fadeAndSlideFromBottom{from{opacity:0;-webkit-transform:translateY(20%);transform:translateY(20%)}to{opacity:1}}@-webkit-keyframes fadeAndSlideToBottom{from{opacity:1}to{opacity:0;-webkit-transform:translateY(20%);transform:translateY(20%)}}@keyframes fadeAndSlideToBottom{from{opacity:1}to{opacity:0;-webkit-transform:translateY(20%);transform:translateY(20%)}}@-webkit-keyframes fadeAndSlideFromLeft{from{opacity:0;-webkit-transform:translateX(-20%);transform:translateX(-20%)}to{opacity:1}}@keyframes fadeAndSlideFromLeft{from{opacity:0;-webkit-transform:translateX(-20%);transform:translateX(-20%)}to{opacity:1}}@-webkit-keyframes fadeAndSlideToLeft{from{opacity:1}to{opacity:0;-webkit-transform:translateX(-20%);transform:translateX(-20%)}}@keyframes fadeAndSlideToLeft{from{opacity:1}to{opacity:0;-webkit-transform:translateX(-20%);transform:translateX(-20%)}}.am-fade{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:backwards;animation-fill-mode:backwards;opacity:1}.am-fade.am-fade-add,.am-fade.ng-hide-remove,.am-fade.ng-move{-webkit-animation-name:fadeIn;animation-name:fadeIn}.am-fade.am-fade-remove,.am-fade.ng-hide{-webkit-animation-name:fadeOut;animation-name:fadeOut}.am-fade.ng-enter{visibility:hidden;-webkit-animation-name:fadeIn;animation-name:fadeIn;-webkit-animation-play-state:paused;animation-play-state:paused}.am-fade.ng-enter.ng-enter-active{visibility:visible;-webkit-animation-play-state:running;animation-play-state:running}.am-fade.ng-leave{-webkit-animation-name:fadeOut;animation-name:fadeOut;-webkit-animation-play-state:paused;animation-play-state:paused}.am-fade.ng-leave.ng-leave-active{-webkit-animation-play-state:running;animation-play-state:running}@-webkit-keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes fadeIn{from{opacity:0}to{opacity:1}}@-webkit-keyframes fadeOut{from{opacity:1}to{opacity:0}}@keyframes fadeOut{from{opacity:1}to{opacity:0}}.aside-backdrop.am-fade,.modal-backdrop.am-fade{background:rgba(0,0,0,.5);-webkit-animation-duration:.15s;animation-duration:.15s}.aside-backdrop.am-fade.ng-leave,.modal-backdrop.am-fade.ng-leave{-webkit-animation-delay:.3s;animation-delay:.3s}.am-flip-x{-webkit-animation-duration:.4s;animation-duration:.4s;-webkit-animation-timing-function:ease;animation-timing-function:ease;-webkit-animation-fill-mode:backwards;animation-fill-mode:backwards}.am-flip-x.am-flip-x-add,.am-flip-x.ng-hide-remove,.am-flip-x.ng-move{-webkit-animation-name:flipInXBounce;animation-name:flipInXBounce}.am-flip-x.am-flip-x-remove,.am-flip-x.ng-hide{-webkit-animation-name:flipOutX;animation-name:flipOutX}.am-flip-x.ng-enter{visibility:hidden;-webkit-animation-name:flipInXBounce;animation-name:flipInXBounce;-webkit-animation-play-state:paused;animation-play-state:paused}.am-flip-x.ng-enter.ng-enter-active{visibility:visible;-webkit-animation-play-state:running;animation-play-state:running}.am-flip-x.ng-leave{-webkit-animation-name:flipOutX;animation-name:flipOutX;-webkit-animation-play-state:paused;animation-play-state:paused}.am-flip-x.ng-leave.ng-leave-active{-webkit-animation-play-state:running;animation-play-state:running}.am-flip-x-linear{-webkit-animation-duration:.4s;animation-duration:.4s;-webkit-animation-timing-function:ease;animation-timing-function:ease;-webkit-animation-fill-mode:backwards;animation-fill-mode:backwards}.am-flip-x-linear.am-flip-x-add,.am-flip-x-linear.ng-hide-remove,.am-flip-x-linear.ng-move{-webkit-animation-name:flipInX;animation-name:flipInX}.am-flip-x-linear.am-flip-x-remove,.am-flip-x-linear.ng-hide{-webkit-animation-name:flipOutX;animation-name:flipOutX}.am-flip-x-linear.ng-enter{visibility:hidden;-webkit-animation-name:flipInX;animation-name:flipInX;-webkit-animation-play-state:paused;animation-play-state:paused}.am-flip-x-linear.ng-enter.ng-enter-active{visibility:visible;-webkit-animation-play-state:running;animation-play-state:running}.am-flip-x-linear.ng-leave{-webkit-animation-name:flipOutX;animation-name:flipOutX;-webkit-animation-play-state:paused;animation-play-state:paused}.am-flip-x-linear.ng-leave.ng-leave-active{-webkit-animation-play-state:running;animation-play-state:running}@-webkit-keyframes flipInX{from{opacity:0;-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg)}to{opacity:1;-webkit-transform:perspective(400px) rotateX(0);transform:perspective(400px) rotateX(0)}}@keyframes flipInX{from{opacity:0;-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg)}to{opacity:1;-webkit-transform:perspective(400px) rotateX(0);transform:perspective(400px) rotateX(0)}}@-webkit-keyframes flipInXBounce{from{opacity:0;-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg)}40%{-webkit-transform:perspective(400px) rotateX(-10deg);transform:perspective(400px) rotateX(-10deg)}70%{-webkit-transform:perspective(400px) rotateX(10deg);transform:perspective(400px) rotateX(10deg)}to{opacity:1;-webkit-transform:perspective(400px) rotateX(0);transform:perspective(400px) rotateX(0)}}@keyframes flipInXBounce{from{opacity:0;-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg)}40%{-webkit-transform:perspective(400px) rotateX(-10deg);transform:perspective(400px) rotateX(-10deg)}70%{-webkit-transform:perspective(400px) rotateX(10deg);transform:perspective(400px) rotateX(10deg)}to{opacity:1;-webkit-transform:perspective(400px) rotateX(0);transform:perspective(400px) rotateX(0)}}@-webkit-keyframes flipOutX{from{opacity:1;-webkit-transform:perspective(400px) rotateX(0);transform:perspective(400px) rotateX(0)}to{opacity:0;-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg)}}@keyframes flipOutX{from{opacity:1;-webkit-transform:perspective(400px) rotateX(0);transform:perspective(400px) rotateX(0)}to{opacity:0;-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg)}}.am-slide-top{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-fill-mode:backwards;animation-fill-mode:backwards}.am-slide-top.am-slide-top-add,.am-slide-top.ng-hide-remove,.am-slide-top.ng-move{-webkit-animation-name:slideFromTop;animation-name:slideFromTop}.am-slide-top.am-slide-top-remove,.am-slide-top.ng-hide{-webkit-animation-name:slideToTop;animation-name:slideToTop}.am-slide-top.ng-enter{visibility:hidden;-webkit-animation-name:slideFromTop;animation-name:slideFromTop;-webkit-animation-play-state:paused;animation-play-state:paused}.am-slide-top.ng-enter.ng-enter-active{visibility:visible;-webkit-animation-play-state:running;animation-play-state:running}.am-slide-top.ng-leave{-webkit-animation-name:slideToTop;animation-name:slideToTop;-webkit-animation-play-state:paused;animation-play-state:paused}.am-slide-top.ng-leave.ng-leave-active{-webkit-animation-play-state:running;animation-play-state:running}.am-slide-right{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-fill-mode:backwards;animation-fill-mode:backwards}.am-slide-right.am-slide-right-add,.am-slide-right.ng-hide-remove,.am-slide-right.ng-move{-webkit-animation-name:slideFromRight;animation-name:slideFromRight}.am-slide-right.am-slide-right-remove,.am-slide-right.ng-hide{-webkit-animation-name:slideToRight;animation-name:slideToRight}.am-slide-right.ng-enter{visibility:hidden;-webkit-animation-name:slideFromRight;animation-name:slideFromRight;-webkit-animation-play-state:paused;animation-play-state:paused}.am-slide-right.ng-enter.ng-enter-active{visibility:visible;-webkit-animation-play-state:running;animation-play-state:running}.am-slide-right.ng-leave{-webkit-animation-name:slideToRight;animation-name:slideToRight;-webkit-animation-play-state:paused;animation-play-state:paused}.am-slide-right.ng-leave.ng-leave-active{-webkit-animation-play-state:running;animation-play-state:running}.am-slide-bottom{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-fill-mode:backwards;animation-fill-mode:backwards}.am-slide-bottom.am-slide-bottom-add,.am-slide-bottom.ng-hide-remove,.am-slide-bottom.ng-move{-webkit-animation-name:slideFromBottom;animation-name:slideFromBottom}.am-slide-bottom.am-slide-bottom-remove,.am-slide-bottom.ng-hide{-webkit-animation-name:slideToBottom;animation-name:slideToBottom}.am-slide-bottom.ng-enter{visibility:hidden;-webkit-animation-name:slideFromBottom;animation-name:slideFromBottom;-webkit-animation-play-state:paused;animation-play-state:paused}.am-slide-bottom.ng-enter.ng-enter-active{visibility:visible;-webkit-animation-play-state:running;animation-play-state:running}.am-slide-bottom.ng-leave{-webkit-animation-name:slideToBottom;animation-name:slideToBottom;-webkit-animation-play-state:paused;animation-play-state:paused}.am-slide-bottom.ng-leave.ng-leave-active{-webkit-animation-play-state:running;animation-play-state:running}.am-slide-left{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-fill-mode:backwards;animation-fill-mode:backwards}.am-slide-left.am-slide-left-add,.am-slide-left.ng-hide-remove,.am-slide-left.ng-move{-webkit-animation-name:slideFromLeft;animation-name:slideFromLeft}.am-slide-left.am-slide-left-remove,.am-slide-left.ng-hide{-webkit-animation-name:slideToLeft;animation-name:slideToLeft}.am-slide-left.ng-enter{visibility:hidden;-webkit-animation-name:slideFromLeft;animation-name:slideFromLeft;-webkit-animation-play-state:paused;animation-play-state:paused}.am-slide-left.ng-enter.ng-enter-active{visibility:visible;-webkit-animation-play-state:running;animation-play-state:running}.am-slide-left.ng-leave{-webkit-animation-name:slideToLeft;animation-name:slideToLeft;-webkit-animation-play-state:paused;animation-play-state:paused}.am-slide-left.ng-leave.ng-leave-active{-webkit-animation-play-state:running;animation-play-state:running}@-webkit-keyframes slideFromTop{from{-webkit-transform:translateY(-100%);transform:translateY(-100%)}}@keyframes slideFromTop{from{-webkit-transform:translateY(-100%);transform:translateY(-100%)}}@-webkit-keyframes slideToTop{to{-webkit-transform:translateY(-100%);transform:translateY(-100%)}}@keyframes slideToTop{to{-webkit-transform:translateY(-100%);transform:translateY(-100%)}}@-webkit-keyframes slideFromRight{from{-webkit-transform:translateX(100%);transform:translateX(100%)}}@keyframes slideFromRight{from{-webkit-transform:translateX(100%);transform:translateX(100%)}}@-webkit-keyframes slideToRight{to{-webkit-transform:translateX(100%);transform:translateX(100%)}}@keyframes slideToRight{to{-webkit-transform:translateX(100%);transform:translateX(100%)}}@-webkit-keyframes slideFromBottom{from{-webkit-transform:translateY(100%);transform:translateY(100%)}}@keyframes slideFromBottom{from{-webkit-transform:translateY(100%);transform:translateY(100%)}}@-webkit-keyframes slideToBottom{to{-webkit-transform:translateY(100%);transform:translateY(100%)}}@keyframes slideToBottom{to{-webkit-transform:translateY(100%);transform:translateY(100%)}}@-webkit-keyframes slideFromLeft{from{-webkit-transform:translateX(-100%);transform:translateX(-100%)}}@keyframes slideFromLeft{from{-webkit-transform:translateX(-100%);transform:translateX(-100%)}}@-webkit-keyframes slideToLeft{to{-webkit-transform:translateX(-100%);transform:translateX(-100%)}}@keyframes slideToLeft{to{-webkit-transform:translateX(-100%);transform:translateX(-100%)}}.switchery{background-color:#fff;border:1px solid #dfdfdf;border-radius:20px;cursor:pointer;display:inline-block;height:30px;position:relative;vertical-align:middle;width:50px}.switchery>small{background:#fff;border-radius:100%;box-shadow:0 1px 3px rgba(0,0,0,.4);height:30px;position:absolute;top:0;width:30px}.toast-title{font-weight:700}.toast-message{-ms-word-wrap:break-word;word-wrap:break-word}.toast-message a,.toast-message label{color:#fff}.toast-message a:hover{color:#ccc;text-decoration:none}.toast-close-button{position:relative;right:-.3em;top:-.3em;float:right;font-size:20px;font-weight:700;color:#fff;-webkit-text-shadow:0 1px 0 #fff;text-shadow:0 1px 0 #fff;opacity:.8}.toast-close-button:focus,.toast-close-button:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4}button.toast-close-button{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.toast-top-full-width{top:0;right:0;width:100%}.toast-bottom-full-width{bottom:0;right:0;width:100%}.toast-top-left{top:12px;left:12px}.toast-top-center{top:12px}.toast-top-right{top:12px;right:12px}.toast-bottom-right{right:12px;bottom:12px}.toast-bottom-center{bottom:12px}.toast-bottom-left{bottom:12px;left:12px}.toast-center{top:45%}#toast-container{position:fixed;z-index:999999}#toast-container.toast-bottom-center,#toast-container.toast-center,#toast-container.toast-top-center{width:100%;pointer-events:none}#toast-container.toast-bottom-center>div,#toast-container.toast-center>div,#toast-container.toast-top-center>div{margin:auto;pointer-events:auto}#toast-container.toast-bottom-center>button,#toast-container.toast-center>button,#toast-container.toast-top-center>button{pointer-events:auto}#toast-container *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}#toast-container>div{margin:0 0 6px;padding:15px 15px 15px 50px;width:300px;-moz-border-radius:3px 3px 3px 3px;-webkit-border-radius:3px 3px 3px 3px;border-radius:3px 3px 3px 3px;background-position:15px center;background-repeat:no-repeat;-moz-box-shadow:0 0 12px #999;-webkit-box-shadow:0 0 12px #999;box-shadow:0 0 12px #999;color:#fff;opacity:.8}#toast-container>:hover{-moz-box-shadow:0 0 12px #000;-webkit-box-shadow:0 0 12px #000;box-shadow:0 0 12px #000;opacity:1;cursor:pointer}#toast-container>.toast-info{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=)!important}#toast-container>.toast-wait{background-image:url(data:image/gif;base64,R0lGODlhIAAgAIQAAAQCBISGhMzKzERCROTm5CQiJKyurHx+fPz+/ExOTOzu7Dw+PIyOjCwqLFRWVAwKDIyKjMzOzOzq7CQmJLy6vFRSVPTy9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCQAXACwAAAAAIAAgAAAF3eAljmRpnmh6VRSVqLDpIDTixOdUlFSNUDhSQUAT7ES9GnD0SFQAKWItMqr4bqKHVPDI+WiTkaOFFVlrFe83rDrT0qeIjwrT0iLdU0GOiBxhAA4VeSk6QYeIOAsQEAuJKgw+EI8nA18IA48JBAQvFxCXDI8SNAQikV+iiaQIpheWX5mJmxKeF6g0qpQmA4yOu8C7EwYWCgZswRcTFj4KyMAGlwYxDwcHhCXMXxYxBzQHKNo+3DDeCOAn0V/TddbYJA0K48gAEAFQicMWFsfwNA3JSgAIAAFfwIMIL4QAACH5BAkJABoALAAAAAAgACAAhAQCBIyKjERCRMzOzCQiJPTy9DQyNGRmZMTCxOTm5CwqLHx+fBQWFJyenNTW1Pz6/Dw6PGxubAwKDIyOjNTS1CQmJCwuLPz+/Dw+PHRydAAAAAAAAAAAAAAAAAAAAAAAAAXboCaOZGmeaKoxWcSosMkk15W8cZ7VdZaXkcEgQtrxfD9RhHchima1GwlCGUBSFCaFxMrgRtnLFhWujWHhs2nJc8KoVlWGQnEn7/i8XgOwWAB7JwoONQ4KgSQAZRcOgHgSCwsSIhZMNRZ5CzULIgaWF5h4mhecfIQ8jXmQkiODhYeIiRYGjrG2PxgBARi3IhNMAbcCnwI5BAQpAZ8TIwK6vCQVDwUVKL+WzAANTA210g/VJ8OWxQefByQE4dZMzBoInwh4zrtgn2p725YNthUFTNRuGYB3AYGBHCEAACH5BAkJAB0ALAAAAAAgACAAhAQCBISChFRWVMzKzCQiJOTm5GxqbCwuLJSWlPz6/NTW1AwODJSSlGRmZCwqLOzu7HR2dDQ2NAQGBISGhFxaXNTS1CQmJOzq7GxubDQyNKSmpPz+/Nza3AAAAAAAAAAAAAXfYCeOZGmeaKqurHBdAiuP17Zdc0lMAVHWt9yI8LA9fCPB4xEjARoNSWpis01kBpshFahurqzsZosiGpErScMAUO0maKF8Tq/bTQCIQgFp30cQXhB1BHEcXhx0FgkJFiOHVYlzi42AgoRxeRx8fn+en3UABwedKgsBAwMBCygOCjYKDisLFV4VrCUAtVUKpSZdXl8mB8EbByQWcQPFAyYZxccdB7sV0cvBzbmvvG0LBV4FrFTBYCWuNhyyHRTFFB20trh4BxmdYl4YIqepq0IRxRE+IfDCAFQHARo0NGERAgAh+QQJCQAgACwAAAAAIAAgAIUEAgSEgoRMTkzMyswcHhzk5uR0cnQUFhRcXlwsKiz09vQMCgyMiozU1tQkJiR8fnxkZmT8/vwEBgSEhoRcWlzU0tQkIiT08vR0dnQcGhxkYmQ0MjT8+vwMDgyMjozc2twAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG+UCQcEgsGo/IpHLJXDweC6Z0+IhEHlOjRGIMWLHZoUZx0RQlAajxkFFKFFYFl5m5KNpIySU+X2bIBEoQZBBZGQdMElFhjI2Oj5AgHQEDAw8dQxYeDBaNHRVWVhWYCXsRFwmMXqFWEyAerB6MA6xWA6+xs7URt6VWqIwTu64gDh4eDp6goaORQ5OVAZjO1EgEGhB4RwAYDQ0YAEwIcBEKFEgYrBhLBORxgUYfrB9LELuF8fNDAAaVBuEg7NXCVyRdqHVCGLBiIIQAB1Yc4BXh9uEbwAXuyi2iQI7DuSwHdiFqCEGDtizLRFUDsaGAlQIbVoJYIEDAIiZBAAAh+QQJCQAbACwAAAAAIAAgAIQEAgSMioxcWlz08vQcHhysqqwMDgx8enwsKiykoqRkZmT8+vzEwsQMCgyUlpQkJiS0srQEBgSMjoxcXlz09vQkIiSsrqwUEhQ0MjRsamz8/vwAAAAAAAAAAAAAAAAAAAAF7+AmjmRpnmiqruz2PG0sIssCj4CQJAIgj4/abRNJaI6agu9kCAQaphdJgEQKUIFjgGWsahJYLdf7RTWfLKr3+jsBClVlG5Xb9eb4fImgUBBKDVB4ExRHFGwbGRQLGXMEhUgUfw2QC4IyCmSNDQtHlm2ZXgoiGQsUjW0EnUgLfyKBeYSeiHojfH61uS0GBisVEgEVLRcWRxAXKAgDRwMILMVIECgSVRIrBmS9JtRI1iMVBweuGxerSNolyszOIhjLGs0jEFXSKA8SEkMbcEgWIxfzNBxrw6AKgxIGkM05UOWALhERHJhysOThBgAVWYQAACH5BAkJABkALAAAAAAgACAAhAQGBIyKjERCRMzOzCwuLGRiZPz6/OTm5AwODLSytFRSVNTW1Dw6PHx6fAwKDJSSlERGRNTS1DQyNGxqbPz+/BQSFLy6vFRWVNza3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAXqYCaO5FgFwxBUZeu61ULNFMa+eBvQdJD/owFvFhkBBAwHsBQZUooZyWF2YOQkBNJu6ANMaQeli0AxSEwymi0DcUJeEgPlbEJFAghRe/h+Eeg/Dl9UYks5DF9VhksOAgKFi5GSSwh5kzgVCXIJNxknD5aSCTwJIw8zD5MITpanFKmSCHI8NxUPoJejNKWXLZkznL0vCJ3CxsckDpA/ChYJFzkTBgYTSxc80C4OswbLLhY8Fi/bMwYAJVgl4DTiL9LUJADrFuci1zTZLwD1IwU8BSQuWLCQb1EDHg2QiSDALYvCDAISJLDy8FIIACH5BAkJAB4ALAAAAAAgACAAhAQGBISGhFRSVNTW1CQiJKyqrGRmZOzu7CwuLIyOjGxubPz6/BQSFGRiZOTi5CwqLLy6vDQ2NIyKjFRWVCQmJKyurGxqbPT29DQyNJSSlHRydPz+/BQWFOzq7AAAAAAAAAXhoCeOJElYClGubOs117YtjWuvxCLLi3qbhc6h4FPsdorfiNI5dige43GT9AAkHUcCwCpMNxVP7tgTJY4J1uF7EBl0M8Ooueuo2SOCIkVa11kVX2E2EmgsFH4yBz4uAAkdHVstBAUHQ4xKmZqbnJ2bAhAQAiURGJ4eE0cTIxgzpp0QRxCsrp6xO7MjpaepO6unKxOhv8DFxsfIJBwaChw2DAkZDEocDjIOzi0ZMhlKUjIaLtsb3T8aR+EtDBkJ0yQUBQVQI9XX2ZsDMgMlyxr3mzE2XEgmotCGAARFIHiQ0FMIACH5BAkJABgALAAAAAAgACAAhAQCBISGhDw+POTi5CwuLLS2tPTy9BQSFJyenGRiZDQ2NIyOjLy+vPz6/BweHIyKjFRSVOzq7DQyNLy6vBQWFHRydDw6PPz+/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXXICaOZHkcZaquIjVd10SxtFrAcFGrVhBYIwoON9uNAsOA6DCEFTEKBEKxEjQvAtELNxkpGrAGNfW4Plpb2QgxRKjKzfPoVGLj3CnLNUv7hscpSDhKOxJSgDwPP0ZGAACMjAQFDQYFBJA0BAZDBpeYGBQVFUU3TV2YFAMwAzNgTQ2PkBVDFRiuQ7CYszi1pUOnkKmrM5qcnqiiTwQTDQ2Wn9DR0tPUfRKQEBEREDQSFw3XRhEwEd3f4TvjF+XWKgJ8JNnb0QkwCdUlCzAL+CQODAwc9BtIMAQAOw==)!important}#toast-container>.toast-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=)!important}#toast-container>.toast-success{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==)!important}#toast-container>.toast-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=)!important}#toast-container.toast-bottom-full-width>div,#toast-container.toast-top-full-width>div{width:96%;margin:auto}.toast{background-color:#030303}.toast-success{background-color:#51a351}.toast-error{background-color:#bd362f}.toast-info{background-color:#2f96b4}.toast-wait{background-color:#2f96b4}.toast-warning{background-color:#f89406}@media all and (max-width:240px){#toast-container>div{padding:8px 8px 8px 50px;width:11em}#toast-container .toast-close-button{right:-.2em;top:-.2em}}@media all and (min-width:241px) and (max-width:480px){#toast-container>div{padding:8px 8px 8px 50px;width:18em}#toast-container .toast-close-button{right:-.2em;top:-.2em}}@media all and (min-width:481px) and (max-width:768px){#toast-container>div{padding:15px 15px 15px 50px;width:25em}}:not(.no-enter)#toast-container>div.ng-enter,:not(.no-leave)#toast-container>div.ng-leave{-webkit-transition:1s cubic-bezier(.25,.25,.75,.75) all;-moz-transition:1s cubic-bezier(.25,.25,.75,.75) all;-ms-transition:1s cubic-bezier(.25,.25,.75,.75) all;-o-transition:1s cubic-bezier(.25,.25,.75,.75) all;transition:1s cubic-bezier(.25,.25,.75,.75) all}:not(.no-enter)#toast-container>div.ng-enter.ng-enter-active,:not(.no-leave)#toast-container>div.ng-leave{opacity:.8}:not(.no-enter)#toast-container>div.ng-enter,:not(.no-leave)#toast-container>div.ng-leave.ng-leave-active{opacity:0}html{overflow:auto;height:100%;margin:0;padding:0}body{height:100%;margin:0;padding:0;color:#323232;font-family:Arial,Helvetica,sans-serif;font-size:1em}div,input,li,span,td,textarea{font-size:1em}.container{font-size:1.2em}.footer{margin:1em 0 1em 0}input[disabled],textarea[disabled]{background-color:#f6f6f6}.strong,strong{font-weight:700}.likeH2,h1,h2,h3{color:#f60;text-align:center}h1{font-size:2em;margin:0}.likeH2,h2{font-size:1.8em;font-weight:lighter;line-height:1em;margin:0 0 1em}h3{font-size:1.6em;font-weight:lighter;line-height:1em;margin:0 0 1em;text-align:left}img{border:none;vertical-align:middle}.banner{margin:1.5em 0 1.5em 0}.sub-banner{margin:0 0 1.5em 0}.underlined{text-decoration:underline}.header img{float:left}.header h1{position:relative}hr{margin-top:10px;margin-bottom:10px}.table{text-align:left!important}.centered{text-align:center;color:#cbcbcb}.customTables,.dropdown-menu{text-align:left!important}.resourceCombo{width:100%}.top05{margin-top:.5em}.top10{margin-top:1em}.top15{margin-top:1.5em}.top20{margin-top:2em}.top25{margin-top:2.5em}.top30{margin-top:3em}.left05{margin-left:.5em}.left10{margin-left:1em}.left15{margin-left:1.5em}.left20{margin-left:2em}.left25{margin-left:2.5em}.left30{margin-left:3em}.black{color:#333}.divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.img-dashboard{padding-top:30px;margin:auto} \ No newline at end of file
diff --git a/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.eot b/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.eot
new file mode 100644
index 00000000..4a4ca865
--- /dev/null
+++ b/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.eot
Binary files differ
diff --git a/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.svg b/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.svg
new file mode 100644
index 00000000..e3e2dc73
--- /dev/null
+++ b/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.svg
@@ -0,0 +1,229 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
+<font-face units-per-em="1200" ascent="960" descent="-240" />
+<missing-glyph horiz-adv-x="500" />
+<glyph />
+<glyph />
+<glyph unicode="&#xd;" />
+<glyph unicode=" " />
+<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
+<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
+<glyph unicode="&#xa0;" />
+<glyph unicode="&#x2000;" horiz-adv-x="652" />
+<glyph unicode="&#x2001;" horiz-adv-x="1304" />
+<glyph unicode="&#x2002;" horiz-adv-x="652" />
+<glyph unicode="&#x2003;" horiz-adv-x="1304" />
+<glyph unicode="&#x2004;" horiz-adv-x="434" />
+<glyph unicode="&#x2005;" horiz-adv-x="326" />
+<glyph unicode="&#x2006;" horiz-adv-x="217" />
+<glyph unicode="&#x2007;" horiz-adv-x="217" />
+<glyph unicode="&#x2008;" horiz-adv-x="163" />
+<glyph unicode="&#x2009;" horiz-adv-x="260" />
+<glyph unicode="&#x200a;" horiz-adv-x="72" />
+<glyph unicode="&#x202f;" horiz-adv-x="260" />
+<glyph unicode="&#x205f;" horiz-adv-x="326" />
+<glyph unicode="&#x20ac;" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
+<glyph unicode="&#x2212;" d="M200 400h900v300h-900v-300z" />
+<glyph unicode="&#x25fc;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#x2601;" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
+<glyph unicode="&#x2709;" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
+<glyph unicode="&#x270f;" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
+<glyph unicode="&#xe001;" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
+<glyph unicode="&#xe002;" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
+<glyph unicode="&#xe003;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
+<glyph unicode="&#xe005;" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
+<glyph unicode="&#xe006;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
+<glyph unicode="&#xe007;" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
+<glyph unicode="&#xe008;" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
+<glyph unicode="&#xe009;" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
+<glyph unicode="&#xe010;" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe011;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe012;" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe013;" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
+<glyph unicode="&#xe014;" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
+<glyph unicode="&#xe015;" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
+<glyph unicode="&#xe016;" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
+<glyph unicode="&#xe017;" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
+<glyph unicode="&#xe018;" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
+<glyph unicode="&#xe019;" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" />
+<glyph unicode="&#xe020;" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
+<glyph unicode="&#xe021;" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
+<glyph unicode="&#xe022;" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
+<glyph unicode="&#xe023;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
+<glyph unicode="&#xe024;" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
+<glyph unicode="&#xe025;" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
+<glyph unicode="&#xe026;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
+<glyph unicode="&#xe027;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
+<glyph unicode="&#xe028;" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
+<glyph unicode="&#xe029;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
+<glyph unicode="&#xe030;" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
+<glyph unicode="&#xe031;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
+<glyph unicode="&#xe032;" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
+<glyph unicode="&#xe033;" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
+<glyph unicode="&#xe034;" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
+<glyph unicode="&#xe035;" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
+<glyph unicode="&#xe036;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
+<glyph unicode="&#xe037;" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
+<glyph unicode="&#xe038;" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
+<glyph unicode="&#xe039;" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" />
+<glyph unicode="&#xe040;" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
+<glyph unicode="&#xe041;" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
+<glyph unicode="&#xe042;" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
+<glyph unicode="&#xe043;" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
+<glyph unicode="&#xe044;" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
+<glyph unicode="&#xe045;" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
+<glyph unicode="&#xe046;" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
+<glyph unicode="&#xe047;" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
+<glyph unicode="&#xe048;" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
+<glyph unicode="&#xe049;" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
+<glyph unicode="&#xe050;" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
+<glyph unicode="&#xe051;" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
+<glyph unicode="&#xe052;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe053;" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe054;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe055;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe056;" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe057;" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" />
+<glyph unicode="&#xe058;" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" />
+<glyph unicode="&#xe059;" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
+<glyph unicode="&#xe060;" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
+<glyph unicode="&#xe062;" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
+<glyph unicode="&#xe063;" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
+<glyph unicode="&#xe064;" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
+<glyph unicode="&#xe065;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
+<glyph unicode="&#xe066;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
+<glyph unicode="&#xe067;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z" />
+<glyph unicode="&#xe068;" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
+<glyph unicode="&#xe069;" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe070;" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="&#xe071;" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
+<glyph unicode="&#xe072;" d="M200 0l900 550l-900 550v-1100z" />
+<glyph unicode="&#xe073;" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
+<glyph unicode="&#xe074;" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
+<glyph unicode="&#xe075;" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
+<glyph unicode="&#xe076;" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
+<glyph unicode="&#xe077;" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
+<glyph unicode="&#xe078;" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
+<glyph unicode="&#xe079;" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
+<glyph unicode="&#xe080;" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
+<glyph unicode="&#xe081;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
+<glyph unicode="&#xe082;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z" />
+<glyph unicode="&#xe083;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z" />
+<glyph unicode="&#xe084;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
+<glyph unicode="&#xe085;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74.5t-19 -114zM500 300h200v100h-200 v-100z" />
+<glyph unicode="&#xe086;" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
+<glyph unicode="&#xe087;" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z" />
+<glyph unicode="&#xe088;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
+<glyph unicode="&#xe089;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
+<glyph unicode="&#xe090;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
+<glyph unicode="&#xe091;" d="M0 547l600 453v-300h600v-300h-600v-301z" />
+<glyph unicode="&#xe092;" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
+<glyph unicode="&#xe093;" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
+<glyph unicode="&#xe094;" d="M104 600h296v600h300v-600h298l-449 -600z" />
+<glyph unicode="&#xe095;" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
+<glyph unicode="&#xe096;" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
+<glyph unicode="&#xe097;" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
+<glyph unicode="&#xe101;" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
+<glyph unicode="&#xe102;" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
+<glyph unicode="&#xe103;" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" />
+<glyph unicode="&#xe104;" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" />
+<glyph unicode="&#xe105;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" />
+<glyph unicode="&#xe106;" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" />
+<glyph unicode="&#xe107;" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
+<glyph unicode="&#xe108;" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
+<glyph unicode="&#xe109;" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" />
+<glyph unicode="&#xe110;" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
+<glyph unicode="&#xe111;" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
+<glyph unicode="&#xe112;" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
+<glyph unicode="&#xe113;" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
+<glyph unicode="&#xe114;" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
+<glyph unicode="&#xe115;" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
+<glyph unicode="&#xe116;" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
+<glyph unicode="&#xe117;" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
+<glyph unicode="&#xe118;" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
+<glyph unicode="&#xe119;" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
+<glyph unicode="&#xe120;" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
+<glyph unicode="&#xe121;" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
+<glyph unicode="&#xe122;" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
+<glyph unicode="&#xe123;" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
+<glyph unicode="&#xe124;" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
+<glyph unicode="&#xe125;" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
+<glyph unicode="&#xe126;" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
+<glyph unicode="&#xe127;" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
+<glyph unicode="&#xe128;" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z" />
+<glyph unicode="&#xe129;" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
+<glyph unicode="&#xe130;" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
+<glyph unicode="&#xe131;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z" />
+<glyph unicode="&#xe132;" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z" />
+<glyph unicode="&#xe133;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
+<glyph unicode="&#xe134;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
+<glyph unicode="&#xe135;" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5 t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5 q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 39 2 44q31 -13 58 -14.5t39 3.5l11 4q7 36 -16.5 53.5t-64.5 28.5t-56 23q-19 -3 -37 0 q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5zM518 916q3 12 16 30t16 25q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -24 17 -66.5t17 -43.5 q-9 2 -31 5t-36 5t-32 8t-30 14zM692 1003h1h-1z" />
+<glyph unicode="&#xe136;" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
+<glyph unicode="&#xe137;" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" />
+<glyph unicode="&#xe138;" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
+<glyph unicode="&#xe139;" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
+<glyph unicode="&#xe140;" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
+<glyph unicode="&#xe141;" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" />
+<glyph unicode="&#xe142;" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60 l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" />
+<glyph unicode="&#xe143;" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49.5t-49.5 -118.5z" />
+<glyph unicode="&#xe144;" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
+<glyph unicode="&#xe145;" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
+<glyph unicode="&#xe146;" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
+<glyph unicode="&#xe148;" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5 zM700 237q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" />
+<glyph unicode="&#xe149;" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221z" />
+<glyph unicode="&#xe150;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
+<glyph unicode="&#xe151;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
+<glyph unicode="&#xe152;" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
+<glyph unicode="&#xe153;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
+<glyph unicode="&#xe154;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
+<glyph unicode="&#xe155;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
+<glyph unicode="&#xe156;" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
+<glyph unicode="&#xe157;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
+<glyph unicode="&#xe158;" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
+<glyph unicode="&#xe159;" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
+<glyph unicode="&#xe160;" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
+<glyph unicode="&#xe161;" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
+<glyph unicode="&#xe162;" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z" />
+<glyph unicode="&#xe163;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
+<glyph unicode="&#xe164;" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
+<glyph unicode="&#xe165;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
+<glyph unicode="&#xe166;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe167;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe168;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe169;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe170;" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z" />
+<glyph unicode="&#xe171;" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
+<glyph unicode="&#xe172;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
+<glyph unicode="&#xe173;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
+<glyph unicode="&#xe174;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
+<glyph unicode="&#xe175;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
+<glyph unicode="&#xe176;" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
+<glyph unicode="&#xe177;" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
+<glyph unicode="&#xe178;" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
+<glyph unicode="&#xe179;" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z" />
+<glyph unicode="&#xe180;" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
+<glyph unicode="&#xe181;" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
+<glyph unicode="&#xe182;" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
+<glyph unicode="&#xe183;" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" />
+<glyph unicode="&#xe184;" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
+<glyph unicode="&#xe185;" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
+<glyph unicode="&#xe186;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
+<glyph unicode="&#xe187;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
+<glyph unicode="&#xe188;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
+<glyph unicode="&#xe189;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
+<glyph unicode="&#xe190;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
+<glyph unicode="&#xe191;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
+<glyph unicode="&#xe192;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
+<glyph unicode="&#xe193;" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
+<glyph unicode="&#xe194;" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
+<glyph unicode="&#xe195;" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
+<glyph unicode="&#xe197;" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z" />
+<glyph unicode="&#xe198;" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
+<glyph unicode="&#xe199;" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
+<glyph unicode="&#xe200;" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
+</font>
+</defs></svg> \ No newline at end of file
diff --git a/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.ttf b/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.ttf
new file mode 100644
index 00000000..67fa00bf
--- /dev/null
+++ b/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.ttf
Binary files differ
diff --git a/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.woff b/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.woff
new file mode 100644
index 00000000..8c54182a
--- /dev/null
+++ b/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.woff
Binary files differ
diff --git a/old/moon_gui/delivery/assets/i18n/en.json b/old/moon_gui/delivery/assets/i18n/en.json
new file mode 100755
index 00000000..4dc7cea5
--- /dev/null
+++ b/old/moon_gui/delivery/assets/i18n/en.json
@@ -0,0 +1,1357 @@
+{
+ "moon": {
+ "global": {
+ "applicationName": "Moon",
+ "404": "Page not found",
+ "error": "A global error occurs: {{stacktrace}}"
+ },
+ "compatibility": {
+ "label": "Browsers compatibility",
+ "title": "Existing browsers compatibility",
+ "content": "Moon is compliant with : <ul><li>Internet Explorer 9 or +</li><li><a href=\"http://www.mozilla.org/fr/firefox/\">Firefox</a> up-to-date</li><li><a href=\"http://chrome.google.com\">Chrome</a> up-to-date</li></ul>",
+ "close": "Close"
+ },
+ "menu": {
+ "project": "Project",
+ "pdp": "PDP",
+ "logs": "Log",
+ "policy": "Policy",
+ "model":"Model"
+ },
+ "login":{
+ "title" : "Login",
+ "titlePage" : "Login page",
+ "username" : "Username",
+ "password" : "Password",
+ "login": "Login",
+ "check": {
+ "username": {
+ "required": "Username is required"
+ },
+ "password": {
+ "required": "Password is required"
+ }
+ },
+ "error" :"Unable to login into Keystone, error code : {{errorCode}}",
+ "success" : "Connection established. Welcome to Moon GUI, \"Moon is uppon cloud\""
+ },
+ "logout": {
+ "title": "Logout",
+ "success" : "Successfully logout"
+ },
+ "dashboard":{
+ "content" : "Moon:Software-Defined Security Framework"
+ },
+ "policy":{
+ "title": "Policies",
+ "list" : {
+ "search": {
+ "placeholder": "Search Policies",
+ "reset": "Reset"
+ },
+ "table" : {
+ "name":"Name",
+ "genre" : "Genre",
+ "description": "Description",
+ "loading": {
+ "category" : "Loading Category"
+ },
+ "notFound": "There is no Policy"
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Add Policy",
+ "detail": "Consut",
+ "edit": "Edit",
+ "map" : "Map Policy to PDP",
+ "unmap" : "Unmap",
+ "delete": "Delete"
+ }
+ },
+ "unmap": {
+ "title": "Unmap Policy to PDP",
+ "content": "Are you sure you want to unmap PDP `{{pdpName}}` / Policy `{{policyName}}` ?",
+ "action": {
+ "unmap": "Unmap",
+ "cancel": "Cancel"
+ },
+ "error": "Unable to unmap PDP `{{pdpName}}` /Policy `{{policyName}}`",
+ "success": "PDP `{{pdpName}}` / Policy `{{policyName}}` successfully unmapped"
+ },
+ "map":{
+ "title": "Map a Policy to PDP `{{pdpName}}`",
+ "form" :{
+ "list": "List of Policies"
+ },
+ "action": {
+ "create": "Map Policy",
+ "cancel": "Cancel",
+ "new": "Create a Policy",
+ "list": "Map an existing Policy",
+ "map": "Map the selected Policy",
+ "delete" : "Delete the selected Policy"
+ },
+ "check": {
+ "policy":{
+ "required" : "Policy is required"
+ }
+ },
+ "error": "Unable to map Policy `{{policyName}}` to the PDP `{{pdpName}}`",
+ "success": "Policy `{{policyName}}` successfully mapped to the PDP `{{pdpName}}`"
+ },
+ "remove": {
+ "title": "Delete Policy",
+ "content": {
+ "query": "Are you sure you want to delete `{{policyName}}` Policy ?"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Policy `{{policyName}}`, error code : {{errorCode}}, message : \"{{message}}\"",
+ "success": "Model `{{policyName}}` successfully deleted"
+ },
+ "edit" : {
+ "title": "Policy `{{policyName}}` configuration",
+ "update" : "- update",
+ "show": {
+ "open": "( show )",
+ "close": "( close )"
+ },
+ "basic" : {
+ "title" : "Basic Information",
+ "form": {
+ "id": "Id",
+ "name": "Name",
+ "genre": "Genre",
+ "model": "Model",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Update"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ },
+ "genre": {
+ "required": "Genre is required"
+ }
+ },
+ "error": "Unable to update Policy `{{policyName}}`",
+ "success": "Policy `{{policyName}}` successfully updated"
+ },
+ "perimeter": {
+ "title" : "Perimeters"
+ },
+ "data": {
+ "title" : "Data"
+ },
+ "rules" : {
+ "title" : "Rules"
+ },
+ "assignments": {
+ "title" : "Assignments"
+ }
+ },
+ "add":{
+ "title": "Add new Policy",
+ "form": {
+ "name": "Name",
+ "genre": "Genre",
+ "model": "Models",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Create Policy",
+ "cancel": "Cancel"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ },
+ "genre": {
+ "required": "Genre is required"
+ },
+ "model": {
+ "required": "Model is required"
+ }
+ },
+ "error": "Unable to create Policy `{{policyName}}`",
+ "success": "Policy `{{policyName}}` successfully created"
+ },
+ "perimeter": {
+ "subject" : {
+ "title" : "List of associated Subjects",
+ "delete": {
+ "error" : "Unable to delete {{subjectName}} Subject, reason : {{reason}}",
+ "success": "Subject `{{subjectName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add a Subject"
+ },
+ "notFound": "There is no Subject"
+ },
+ "object" : {
+ "title" : "List of associated Objects",
+ "delete": {
+ "error" : "Unable to delete {{objectName}} Object, reason : {{reason}}",
+ "success": "Object `{{objectName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add an Object"
+ },
+ "notFound": "There is no Object"
+ },
+ "action" : {
+ "title" : "List of associated Actions",
+ "delete": {
+ "error" : "Unable to delete {{actionName}} Action, reason : {{reason}}",
+ "success": "Action `{{actionName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add an Action"
+ },
+ "notFound": "There is no Action"
+ },
+ "update":{
+ "error": "Unable to update Perimeter `{{perimeterName}}`",
+ "success": "Perimeter `{{perimeterName}}` successfully updated"
+ },
+ "table": {
+ "id" : "Id",
+ "name" : "Name",
+ "description" : "Description",
+ "email" : "Email",
+ "partner":{
+ "id" : "Partner Id"
+ },
+ "action": {
+ "title": "Actions",
+ "delete": "Delete",
+ "update": "Update",
+ "unmap": "Unmap"
+ }
+ },
+ "edit": {
+ "name" : "Name",
+ "description" : "Description",
+ "partnerId": "Partner Id",
+ "policies": "Policy list",
+ "email": "E-mail",
+ "selectedPolicies": "Selected Policies",
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "action": {
+ "list": "Add an existing Perimeter",
+ "new": "Add a new Perimeter",
+ "create": "Add Perimeter",
+ "add": "Add the selected Perimeter",
+ "delete" : "Delete the selected Perimeter"
+ },
+ "create":{
+ "error": "Unable to create `{{name}}`",
+ "success": "`{{name}}` successfully created"
+ },
+ "delete":{
+ "error": "Unable to delete `{{name}}`",
+ "success": "`{{name}}` successfully deleted"
+ }
+ }
+ },
+ "data": {
+ "subject" : {
+ "title" : "List of associated Data Subjects",
+ "delete": {
+ "error" : "Unable to delete {{subjectName}} Subject, reason : {{reason}}",
+ "success": "Subject `{{subjectName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add a Data Subject"
+ },
+ "notFound": "There is no Data Subject"
+ },
+ "object" : {
+ "title" : "List of associated Data Objects",
+ "delete": {
+ "error" : "Unable to delete {{objectName}} Object, reason : {{reason}}",
+ "success": "Object `{{objectName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add a Data Object"
+ },
+ "notFound": "There is no Data Object"
+ },
+ "action" : {
+ "title" : "List of associated Actions",
+ "delete": {
+ "error" : "Unable to delete {{actionName}} Action, reason : {{reason}}",
+ "success": "Action `{{actionName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add a Data Action"
+ },
+ "notFound": "There is no Data Action"
+ },
+ "table": {
+ "category" : {
+ "id" : "Category Id",
+ "name" : "Category Name"
+ },
+ "name" : "Name",
+ "description" : "Description",
+ "action": {
+ "title": "Actions",
+ "delete": "Delete",
+ "update": "Update"
+ },
+ "loading": {
+ "category" : "Loading Category"
+ }
+ },
+ "edit": {
+ "name" : "Name",
+ "description" : "Description",
+ "categories" : "Category List",
+ "policies": "Policy List",
+ "check": {
+ "name": {
+ "required": "Name is required"
+ },
+ "category":{
+ "required": "A Category is required"
+ },
+ "policy":{
+ "required": "A Policy is required"
+ }
+ },
+ "action": {
+ "list": "Add an existing Data",
+ "new": "Create a new Data",
+ "create": "Create Data",
+ "add": "Add the selected Data",
+ "delete": "Delete Data"
+ },
+ "create":{
+ "error": "Unable to create `{{name}}`",
+ "success": "`{{name}}` successfully created"
+ },
+ "delete":{
+ "error": "Unable to delete `{{name}}`",
+ "success": "`{{name}}` successfully deleted"
+ }
+ }
+ },
+ "rules": {
+ "title": "Rules",
+ "list": {
+ "search": {
+ "placeholder": "Search Rule",
+ "reset": "Reset"
+ },
+ "table": {
+ "id" : "Id",
+ "metaRule": "Meta Rule",
+ "description": "Description",
+ "enabled": "Enabled",
+ "rule": "Rule",
+ "instructions": "Instruction",
+ "notFound": "There is no Rule",
+ "loading": {
+ "metaRule" : "Loading Meta Rule"
+ },
+ "action":{
+ "title": "Actions",
+ "delete": "Delete"
+ }
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Add Rule",
+ "detail": "Consult",
+ "edit": "Edit",
+ "delete": "Delete"
+ },
+ "error": "Unable to retrieve Rule"
+ },
+ "edit": {
+ "title" : "List of associated Rules",
+ "action" : {
+ "create": "Create Rules",
+ "delete": {
+ "error" : "Unable to delete {{rulesName}} Action, reason : {{reason}}",
+ "success": "Rules `{{rulesName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add a Rule",
+ "policies": "Select a policy",
+ "instructions": "Instruction",
+ "metarules" : "Select one of the associated MetaRules",
+ "categories":{
+ "subject": "Select {{number}} Subject(s)",
+ "object": "Select {{number}} Object(s)",
+ "action": "Select {{number}} Action(s)"
+ },
+ "selectedSubjects": "Selected Subject(s)",
+ "selectedObjects": "Selected Object(s)",
+ "selectedActions": "Selected Action(s)",
+ "details":{
+ "show": "Details",
+ "close": "Close"
+ },
+ "check":{
+ "policy":{
+ "required": "A Policy is required"
+ },
+ "instructions":{
+ "required": "An Instruction in JSON format is required"
+ },
+ "metarules":{
+ "required": "A MetaRule is required"
+ },
+ "subject":{
+ "required": "{{number}} Subject(s) are required"
+ },
+ "object":{
+ "required": "{{number}} Object(s) are required"
+ },
+ "action":{
+ "required": "{{number}} Action(s) are required"
+ }
+ },
+ "create":{
+ "error": "Unable to create Rules",
+ "success": "Rules successfully created"
+ },
+ "delete":{
+ "error": "Unable to delete Rules, reason : `{{reason}}`",
+ "success": "Rules successfully deleted"
+ }
+ },
+ "notFound": "There is no Rules"
+ }
+ }
+ },
+ "assignments": {
+ "subject" : {
+ "title" : "List of associated Assignments Subjects",
+ "delete": {
+ "error" : "Unable to delete Assignments, reason : {{reason}}",
+ "success": "Assignments successfully deleted"
+ },
+ "add": {
+ "title": "Add a Assignments Subject"
+ },
+ "notFound": "There is no Assignments Subject"
+ },
+ "object" : {
+ "title" : "List of associated Assignments Objects",
+ "delete": {
+ "error" : "Unable to delete Assignments, reason : {{reason}}",
+ "success": "Assignments successfully deleted"
+ },
+ "add": {
+ "title": "Add a Assignments Object"
+ },
+ "notFound": "There is no Assignments Object"
+ },
+ "action" : {
+ "title" : "List of associated Assignments Actions",
+ "delete": {
+ "error" : "Unable to delete Assignments, reason : {{reason}}",
+ "success": "Assignments successfully deleted"
+ },
+ "add": {
+ "title": "Add a Assignments Action"
+ },
+ "notFound": "There is no Assignments Action"
+ },
+ "table": {
+ "action": {
+ "title": "Actions",
+ "delete": "Delete",
+ "update": "Update"
+ },
+ "perimeter": {
+ "name" : "Perimeter name"
+ },
+ "data": {
+ "name": "Data name"
+ },
+ "category": {
+ "name" : "Category name"
+ },
+ "loading": {
+ "category" : "Loading Category",
+ "perimeter": "Loading Perimeter",
+ "data": "Loading Data"
+ }
+ },
+ "edit": {
+ "policies": "Select a Policy",
+ "categories": "Select a Category",
+ "perimeters": "Select a Perimeter",
+ "data": "Select a Data",
+ "selectedData" : "Selected Data",
+ "check": {
+ "policy":{
+ "required": "A Policy is required"
+ },
+ "category":{
+ "required": "A Category is required"
+ },
+ "perimeter":{
+ "required": "A Perimeter is required"
+ },
+ "data":{
+ "required": "A Data is required"
+ }
+ },
+ "action": {
+ "list": "Add an existing Assignments",
+ "new": "Add a new Assignments",
+ "create": "Create Assignments",
+ "map": "Add the selected Assignments",
+ "delete": "Delete Assignments"
+ },
+ "create":{
+ "error": "Unable to create Assignments",
+ "success": "Assignments successfully created"
+ },
+ "delete":{
+ "error": "Unable to delete Assignments, reason : `{{reason}}`",
+ "success": "Assignments successfully deleted"
+ }
+ }
+ }
+ },
+ "model":{
+ "title": "Models",
+ "list": {
+ "search": {
+ "placeholder": "Search Model",
+ "reset": "Reset"
+ },
+ "table":{
+ "name":"Name",
+ "description": "Description",
+ "metaRules":{
+ "number" : "Number of Meta Rules"
+ },
+ "notFound": "There is no Models"
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Add Model",
+ "detail": "Consult",
+ "edit": "Edit",
+ "delete": "Delete"
+ },
+ "error": "Unable to retrieve Models"
+ },
+ "edit" : {
+ "title": "Model `{{modelName}}` configuration",
+ "update" : "- update",
+ "basic" : {
+ "title" : "Basic Information",
+ "form": {
+ "id": "Id",
+ "name": "Name",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Update"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "error": "Unable to update Model `{{modelName}}`",
+ "success": "Model `{{modelName}}` successfully updated"
+ },
+ "metarules": {
+ "title" : "Meta Rules"
+ }
+ },
+ "view": {
+ "title": "Model `{{modelName}}` details",
+ "name": "Name",
+ "id": "Id",
+ "description": "Description",
+ "action": {
+ "close": "Close"
+ }
+ },
+ "remove": {
+ "title": "Delete Model",
+ "content": {
+ "query": "Are you sure you want to delete `{{modelName}}` Model ?"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Model `{{modelName}}`, error code : {{errorCode}}, message : \"{{message}}\"",
+ "success": "Model `{{modelName}}` successfully deleted"
+ },
+ "metarules": {
+ "title": "List of Meta Rules",
+ "table": {
+ "name":"Name",
+ "description": "Description",
+ "metadata": {
+ "subject": {
+ "number": "Number of Subject Categories"
+ },
+ "object" : {
+ "number": "Number of Object Categories"
+ },
+ "action": {
+ "number": "Number of Action Categories"
+ }
+ },
+ "notFound": "There is no Meta Rules"
+ },
+ "edit" : {
+ "title" : "Meta Rule `{{metaRuleName}}` configuration",
+ "update": "- update",
+ "basic": {
+ "title": "Basic Information",
+ "form": {
+ "id": "Id",
+ "name": "Name",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Update"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "error": "Unable to update Meta Rule `{{metaRuleName}}`",
+ "success": "Meta Rule `{{metaRuleName}}` successfully updated"
+ }
+ },
+ "update":{
+ "error": "Unable to update Meta Rule `{{metaRuleName}}`",
+ "success": "Meta Rule `{{metaRuleName}}` successfully updated"
+ },
+ "action": {
+ "title": "Actions",
+ "edit": "Edit",
+ "remove": "Remove",
+ "settings" : "Settings",
+ "add": "Add",
+ "detail": {
+ "open": "Consult",
+ "close": "Close"
+ }
+ },
+ "add": {
+ "title": "Add new Meta Rule",
+ "form": {
+ "name": "Nom",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Add Meta Rule",
+ "cancel": "Cancel"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "error": "Unable to create Meta Rule `{{metaRuleName}}`",
+ "success": "Meta Rule `{{metaRuleName}}` successfully created"
+ },
+ "map":{
+ "title": "Add a Meta Rule",
+ "form" :{
+ "list": "List of Meta Rules"
+ },
+ "action": {
+ "create": "Add a new Meta Rule",
+ "cancel": "Cancel",
+ "new": "Add a Meta Rule",
+ "list": "Add an existing Meta Rule",
+ "add": "Add the selected Meta Rule",
+ "delete" : "Delete the selected Meta Rule"
+ },
+ "error": "Unable to map Model `{{modelName}}` to the Meta Rule `{{metaRuleName}}`",
+ "success": "Model `{{modelName}}` successfully mapped to the Meta Rule `{{metaRuleName}}`"
+ },
+ "unmap": {
+ "title": "Remove Meta Rule to Model",
+ "content": "Are you sure you want to remove Model `{{modelName}}` / Meta Rule `{{metaRuleName}}` ?",
+ "action": {
+ "unmap": "Remove",
+ "cancel": "Cancel"
+ },
+ "error": "Unable to remove Model `{{modelName}}` / Meta Rule `{{metaRuleName}}`",
+ "success": "Model `{{modelName}}` / Meta Rule `{{metaRuleName}}` successfully removed"
+ },
+ "delete":{
+ "error": "Unable to delete Meta Rule `{{metaRuleName}}`",
+ "success": "Meta Rule `{{metaRuleName}}` successfully deleted"
+ }
+ },
+ "metadata": {
+ "subject" : {
+ "title" : "List of associated Subject Categories",
+ "delete": {
+ "error" : "Unable to delete {{subjectName}} Subject, reason : {{reason}}",
+ "success": "Subject `{{subjectName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add a Subject Category"
+ },
+ "notFound": "There is no Subject"
+ },
+ "object" : {
+ "title" : "List of associated Object Categories",
+ "delete": {
+ "error" : "Unable to delete {{objectName}} Object, reason : {{reason}}",
+ "success": "Object `{{objectName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add an Object Category"
+ },
+ "notFound": "There is no Object"
+ },
+ "action" : {
+ "title" : "List of associated Action Categories",
+ "remove": "Remove",
+ "delete": {
+ "error" : "Unable to delete {{actionName}} Action, reason : {{reason}}",
+ "success": "Action `{{actionName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add an Action Category"
+ },
+ "notFound": "There is no Action"
+ },
+ "table": {
+ "id" : "Id",
+ "name" : "Name",
+ "description" : "Description",
+ "action": {
+ "title": "Actions",
+ "delete": "Delete",
+ "update": "Update"
+ }
+ },
+ "edit": {
+ "name" : "Name",
+ "description" : "Description",
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "action": {
+ "list": "Add an existing Category",
+ "new": "Add a new Category",
+ "create": "Add Category",
+ "add": "Add the selected Category",
+ "delete": "Delete"
+ },
+ "create":{
+ "error": "Unable to create Category `{{name}}`",
+ "success": "Category `{{name}}` successfully created"
+ },
+ "delete":{
+ "error": "Unable to delete Category `{{name}}`",
+ "success": "Category `{{name}}` successfully deleted"
+ }
+ }
+ },
+ "add":{
+ "title": "Add new Model",
+ "form": {
+ "name": "Name",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Create Model",
+ "cancel": "Cancel"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "error": "Unable to create Model `{{modelName}}`",
+ "success": "Model `{{modelName}}` successfully created"
+ }
+ },
+ "project": {
+ "title": "Projects",
+ "list": {
+ "search": {
+ "placeholder": "Search Projects",
+ "reset": "Reset"
+ },
+ "table": {
+ "name": "Name",
+ "domain": "Domain",
+ "managed": "Managed",
+ "enabled": "Enabled",
+ "description": "Description",
+ "mapping": "PDP",
+ "loading": {
+ "project": "Loading Projects",
+ "pdp": "Loading PDP"
+ },
+ "notFound": "There is no Projects"
+ },
+ "action": {
+ "title": "Actions",
+ "detail": "Consult",
+ "delete": "Delete",
+ "add": "Add Project",
+ "map": "Map to a PDP",
+ "unmap": "Unmap"
+ },
+ "error": "Unable to retrieve Projects"
+ },
+ "view": {
+ "title": "Project `{{projectName}}` details",
+ "action": {
+ "close": "Close"
+ },
+ "subject": {
+ "title": "Subjects",
+ "name": "Name",
+ "mail": "Email",
+ "domain": "Domain",
+ "enabled": "Enabled",
+ "error": "Unable to retrieve Subjects"
+ },
+ "object": {
+ "title": "Objects",
+ "category": "Category",
+ "description": "Description",
+ "enabled": "Enabled",
+ "name": "Name",
+ "error": "Unable to retrieve Objects",
+ "loading": "Loading Objects",
+ "notFound": "There is no Objects"
+ },
+ "role": {
+ "title": "Roles",
+ "category": "Category",
+ "value": "Value",
+ "description": "Description",
+ "assigned": "Assigned",
+ "enabled": "Enabled",
+ "error": "Unable to retrieve Roles",
+ "loading": "Loading Roles",
+ "notFound": "There is no Roles"
+ },
+ "roleAssignment": {
+ "title": "Role Assignments",
+ "category": "Category",
+ "attributes": "Attributes",
+ "description": "Description",
+ "error": "Unable to retrieve Role Assignments",
+ "loading": "Loading Role Assignments",
+ "notFound": "There is no Role Assignments"
+ },
+ "group": {
+ "title": "Groups",
+ "category": "Category",
+ "value": "Value",
+ "description": "Description",
+ "assigned": "Assigned",
+ "enabled": "Enabled",
+ "error": "Unable to retrieve Groups",
+ "loading": "Loading Groups",
+ "notFound": "There is no Groups"
+ },
+ "groupAssignment": {
+ "title": "Group Assignments",
+ "category": "Category",
+ "attributes": "Attributes",
+ "description": "Description",
+ "error": "Unable to retrieve Group Assignments",
+ "loading": "Loading Group Assignments",
+ "notFound": "There is no Group Assignments"
+ }
+ },
+ "add": {
+ "title": "Add new Project",
+ "form": {
+ "name": "Name",
+ "description": "Description",
+ "enabled": "Enabled",
+ "domain": "Domain"
+ },
+ "action": {
+ "create": "Create Project",
+ "cancel": "Cancel"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ },
+ "domain": {
+ "required": "Domain is required"
+ }
+ },
+ "error": "Unable to create Project `{{projectName}}`",
+ "success": "Project `{{projectName}}` successfully created"
+ },
+ "remove": {
+ "title": "Delete Project",
+ "content": {
+ "query": "Are you sure you want to delete `{{projectName}}` Project ?",
+ "isNotMapped": "This Project is not mapped to any PDP",
+ "isMapped": "This project is mapped to `{{pdpName}}` PDP, delete this Project, will remove the mapping."
+ },
+ "mapping":{
+ "remove":{
+ "error": "Unable to remove mapping with Pdp : `{{pdpName}}`"
+ }
+ },
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Project `{{projectName}}`, error code : {{errorCode}}, message : \"{{message}}\"",
+ "success": "Project `{{projectName}}` successfully deleted"
+ },
+ "map": {
+ "title": "Map Project `{{projectName}}` to a PDP",
+ "form": {
+ "pdp": "PDP"
+ },
+ "action": {
+ "map": "Map",
+ "cancel": "Cancel"
+ },
+ "check": {
+ "pdp": {
+ "required": "PDP is required"
+ }
+ },
+ "error": "Unable to map Project `{{projectName}}` to a PDP `{{pdpName}}`",
+ "success": "Project `{{projectName}}` successfully mapped to a PDP `{{pdpName}}`"
+ },
+ "unmap": {
+ "title": "Unmap Project and PDP",
+ "content": "Are you sure you want to unmap Project `{{projectName}}` / PDP `{{pdpName}}` ?",
+ "action": {
+ "unmap": "Unmap",
+ "cancel": "Cancel"
+ },
+ "error": "Unable to unmap Project `{{projectName}}` / PDP `{{pdpName}}`",
+ "success": "Project `{{projectName}}` / PDP `{{pdpName}}` successfully unmapped"
+ }
+ },
+ "pdp": {
+ "title": "PDPs",
+ "edit" : {
+ "title": "Pdp `{{pdpName}}` configuration",
+ "update" : "- update",
+ "basic" : {
+ "title" : "Basic Information",
+ "form": {
+ "id": "Id",
+ "name": "Name",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Update"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "error": "Unable to update PDP `{{pdpName}}`",
+ "success": "PDP `{{pdpName}}` successfully updated"
+ },
+ "policy": {
+ "title" : "Policies"
+ }
+ },
+ "list": {
+ "search": {
+ "placeholder": "Search PDPs",
+ "reset": "Reset"
+ },
+ "table": {
+ "name": "Name",
+ "security_pipeline":{
+ "number" : "Number of Securities"
+ },
+ "project": "Project",
+ "loading": {
+ "pdp": "Loading PDPs",
+ "project": "Loading Project"
+ },
+ "mapping" :{
+ "map": "Is not mapped"
+ },
+ "notFound": "There is no PDPs"
+ },
+ "action": {
+ "title": "Actions",
+ "detail": "Consult",
+ "configure": "Configure",
+ "rule": "Rules",
+ "delete": "Delete",
+ "add": "Add PDP",
+ "edit":"Editer"
+ },
+ "error": "Unable to retrieve PDPs"
+ },
+ "add": {
+ "title": "Add new PDP",
+ "form": {
+ "name": "Name",
+ "policy": "Policy",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Create PDP",
+ "cancel": "Cancel"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ },
+ "policy": {
+ "required": "Policy is required"
+ }
+ },
+ "error": "Unable to create PDP `{{pdpName}}`",
+ "success": "PDP `{{pdpName}}` successfully created"
+ },
+ "remove": {
+ "title": "Delete PDP",
+ "content": "Are you sure you want to delete `{{pdpName}}` PDP ?",
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete PDP `{{pdpName}}`",
+ "success": "PDP `{{pdpName}}` successfully deleted"
+ },
+ "configure": {
+ "title": "PDP `{{pdpName}}` configuration",
+ "action": {
+ "back": "Back to PDPs"
+ },
+ "subject": {
+ "panelTitle": "Subjects configuration",
+ "title": "Subjects",
+ "add": {
+ "title": "Add new Subject",
+ "form": {
+ "name": "Name",
+ "domain": "Domain",
+ "enabled": "Enabled",
+ "project": "Project",
+ "password": "Password",
+ "description": "Description"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "add": "Add Subject"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ },
+ "domain": {
+ "required": "Domain is required"
+ },
+ "project": {
+ "required": "Project is required"
+ },
+ "password": {
+ "required": "Password is required"
+ }
+ },
+ "error": "Unable to add Subject `{{subjectName}}`",
+ "success": "Subject `{{subjectName}}` successfully added"
+ },
+ "remove": {
+ "title": "Delete Subject",
+ "content": "Are you sure you want to delete `{{subjectName}}` subject of `{{pdpName}}` PDP ?",
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Subject `{{subjectName}}`",
+ "success": "Subject `{{subjectName}}` successfully deleted"
+ },
+ "category": {
+ "title": "Categories",
+ "add": {
+ "title": "Add new Category",
+ "form": {
+ "name": "Name"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "add": "Add Category"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "error": "Unable to add Subject Category `{{categoryName}}`",
+ "success": "Subject Category `{{categoryName}}` successfully added"
+ },
+ "remove": {
+ "title": "Delete Category",
+ "content": "Are you sure you want to delete `{{categoryName}}` subject category of `{{pdpName}}` PDP ?",
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Subject Category `{{categoryName}}`",
+ "success": "Subject Category `{{categoryName}}` successfully deleted"
+ }
+ },
+ "categoryValue": {
+ "title": "Values",
+ "add": {
+ "title": "Add new Value",
+ "form": {
+ "value": "Value"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "add": "Add Value"
+ },
+ "check": {
+ "value": {
+ "required": "Value is required"
+ }
+ },
+ "error": "Unable to add Subject Category Value`{{valueName}}`",
+ "success": "Subject Category Value `{{valueName}}` successfully added"
+ },
+ "remove": {
+ "title": "Delete Value",
+ "content": "Are you sure you want to delete `{{valueName}}` subject category value of `{{pdpName}}` PDP ?",
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Subject Category Value `{{valueName}}`",
+ "success": "Subject Category Value `{{valueName}}` successfully deleted"
+ }
+ },
+ "assignment": {
+ "title": "Subject Assignments",
+ "action": {
+ "assign": "Assign",
+ "unassign": "Unassign"
+ },
+ "list": {
+ "notFound": "There is no assignments"
+ },
+ "add": {
+ "error": "Unable to assign Subject `{{subjectName}}` / Category `{{categoryName}}` / Value `{{valueName}}`",
+ "success": "Subject `{{subjectName}}` / Category `{{categoryName}}` / Value `{{valueName}}` assignment successfully done"
+ },
+ "remove": {
+ "error": "Unable to unassign Subject `{{subjectName}}` / Category `{{categoryName}}` / Value `{{valueName}}`",
+ "success": "Subject `{{subjectName}}` / Category `{{categoryName}}` / Value `{{valueName}}` unassignment successfully done"
+ }
+ }
+ },
+ "object": {
+ "panelTitle": "Objects configuration",
+ "title": "Objects",
+ "add": {
+ "title": "Add new Object",
+ "form": {
+ "name": "Name",
+ "image": "Image",
+ "flavor": "Flavor"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "add": "Add Object"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ },
+ "image": {
+ "required": "Image is required"
+ },
+ "flavor": {
+ "required": "Flavor is required"
+ }
+ },
+ "error": "Unable to add Object `{{objectName}}`",
+ "success": "Object `{{objectName}}` successfully added"
+ },
+ "remove": {
+ "title": "Delete Object",
+ "content": "Are you sure you want to delete `{{objectName}}` object of `{{pdpName}}` PDP ?",
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Object `{{objectName}}`",
+ "success": "Object `{{objectName}}` successfully deleted"
+ },
+ "category": {
+ "title": "Categories",
+ "add": {
+ "title": "Add new Category",
+ "form": {
+ "name": "Name"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "add": "Add Category"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "error": "Unable to add Object Category `{{categoryName}}`",
+ "success": "Object Category `{{categoryName}}` successfully added"
+ },
+ "remove": {
+ "title": "Delete Category",
+ "content": "Are you sure you want to delete `{{categoryName}}` object category of `{{pdpName}}` PDP ?",
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Object Category `{{categoryName}}`",
+ "success": "Object Category `{{categoryName}}` successfully deleted"
+ }
+ },
+ "categoryValue": {
+ "title": "Values",
+ "add": {
+ "title": "Add new Value",
+ "form": {
+ "value": "Value"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "add": "Add Value"
+ },
+ "check": {
+ "value": {
+ "required": "Value is required"
+ }
+ },
+ "error": "Unable to add Object Category Value`{{valueName}}`",
+ "success": "Object Category Value `{{valueName}}` successfully added"
+ },
+ "remove": {
+ "title": "Delete Value",
+ "content": "Are you sure you want to delete `{{valueName}}` object category value of `{{pdpName}}` PDP ?",
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Object Category Value `{{valueName}}`",
+ "success": "Object Category Value `{{valueName}}` successfully deleted"
+ }
+ },
+ "assignment": {
+ "title": "Object Assignments",
+ "action": {
+ "assign": "Assign",
+ "unassign": "Unassign"
+ },
+ "list": {
+ "notFound": "There is no assignments"
+ },
+ "add": {
+ "error": "Unable to assign Object `{{objectName}}` / Category `{{categoryName}}` / Value `{{valueName}}`",
+ "success": "Object `{{objectName}}` / Category `{{categoryName}}` / Value `{{valueName}}` assignment successfully done"
+ },
+ "remove": {
+ "error": "Unable to unassign Object `{{ObjectName}}` / Category `{{categoryName}}` / Value `{{valueName}}`",
+ "success": "Object `{{objectName}}` / Category `{{categoryName}}` / Value `{{valueName}}` unassignment successfully done"
+ }
+ }
+ }
+ },
+ "rule": {
+ "title": "PDP `{{pdpName}}` rules",
+ "list": {
+ "table": {
+ "subject": "Subjects",
+ "object": "Objects",
+ "notFound": "There is no Rules"
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Add Rule",
+ "delete": "Delete Rule"
+ }
+ },
+ "add": {
+ "title": "Add new Rule",
+ "action": {
+ "create": "Create Rule",
+ "cancel": "Cancel"
+ },
+ "form": {
+ "subject": {
+ "subject": "Subjects",
+ "category": "Categories",
+ "categoryValue": "Values",
+ "action": {
+ "add": "Add",
+ "delete": "Delete"
+ }
+ },
+ "object": {
+ "object": "Objects",
+ "category": "Categories",
+ "categoryValue": "Values",
+ "action": {
+ "add": "Add",
+ "delete": "Delete"
+ }
+ }
+ },
+ "success": "Rule successfully created",
+ "error": "Unable to create Rule"
+ },
+ "delete": {
+ "title": "Delete Rule",
+ "content": "Are you sure you want to delete rule `{{ruleJson}}` of `{{pdpName}}` PDP ?",
+ "action": {
+ "delete": "Delete Rule",
+ "cancel": "Cancel"
+ },
+ "error": "Unable to delete Rule `{{ruleJson}}`",
+ "success": "Rule `{{ruleJson}}` successfully deleted"
+ },
+ "action": {
+ "back": "Back to PDPs"
+ }
+ }
+ }
+ }
+}
diff --git a/old/moon_gui/delivery/assets/i18n/fr.json b/old/moon_gui/delivery/assets/i18n/fr.json
new file mode 100755
index 00000000..85c513b3
--- /dev/null
+++ b/old/moon_gui/delivery/assets/i18n/fr.json
@@ -0,0 +1,1357 @@
+{
+ "moon": {
+ "global": {
+ "applicationName": "Moon",
+ "404": "Page non trouvée",
+ "error": "Une erreur globale est survenue: {{stacktrace}}"
+ },
+ "compatibility": {
+ "label": "Compatibilité navigateurs Web",
+ "title": "Compatibilité avec les navigateurs existants",
+ "content": "Moon est compatible avec : <ul><li>Internet Explorer 9 ou +</li><li><a href=\"http://www.mozilla.org/fr/firefox/\">Firefox</a> à jour</li><li><a href=\"http://chrome.google.com\">Chrome</a> à jour</li></ul>",
+ "close": "Fermer"
+ },
+ "menu": {
+ "project": "Project",
+ "pdp": "PDP",
+ "logs": "Log",
+ "policy": "Politique",
+ "model": "Modèle"
+ },
+ "login":{
+ "title":"Connexion",
+ "titlePage" : "Page d'idenditifcation",
+ "username" : "Nom d'utilisateur",
+ "password" : "Mot de passe",
+ "login" : "Connexion",
+ "check": {
+ "username": {
+ "required": "Le nom d'utilisateur est requis"
+ },
+ "password": {
+ "required": "Le mot de passe est requis"
+ }
+ },
+ "error" : "Impossible de se connecter à Keystone, code d'erreur {{errorCode}}",
+ "success" : "Connexion établie, Bienvenue sur la GUI de Moon, \"La lune est au dessus des nuages\""
+ },
+ "logout": {
+ "title": "Déconnexion",
+ "success" : "Déconnxion réussie"
+ },
+ "dashboard":{
+ "content" : "Moon:Software-Defined Security Framework"
+ },
+ "policy": {
+ "title": "Politiques",
+ "list" : {
+ "search": {
+ "placeholder": "Rechercher des Politiques",
+ "reset": "Effacer"
+ },
+ "table" : {
+ "name":"Nom",
+ "genre" : "Genre",
+ "description": "Description",
+ "loading": {
+ "category" : "Chargement de la Catégorie"
+ },
+ "notFound": "Il n'existe aucune Politique"
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Ajouter une Politique",
+ "detail": "Consulter",
+ "edit": "Editer",
+ "map" : "Associer une Politique à la PDP",
+ "unmap" : "Dissocier",
+ "delete": "Supprimer"
+ }
+ },
+ "unmap": {
+ "title": "Dissociation de la Policy et de la PDP",
+ "content": "Voulez-vous dissocier la PDP `{{pdpName}}` et la Policy `{{policyName}}` ?",
+ "action": {
+ "unmap": "Dissocier",
+ "cancel": "Annuler"
+ },
+ "error": "Impossible de dissocier la PDP `{{pdpName}}` et la Policy`{{policyName}}`",
+ "success": "La dissociation de la PDP `{{pdpName}}` et de la Policy `{{policyName}}` a été effectuée avec succès"
+ },
+ "map":{
+ "title": "Associer une Politique à la PDP `{{pdpName}}`",
+ "form" :{
+ "list": "Liste des Politiques"
+ },
+ "action": {
+ "create": "Associer une Politique",
+ "cancel": "Fermer",
+ "new": "Créer une Politique",
+ "list": "Associer une Politique existante",
+ "map": "Associer la Politique sélectionnée",
+ "delete" : "Supprimer la Politique sélectionnée"
+ },
+ "check": {
+ "policy":{
+ "required" : "La politique est requise"
+ }
+ },
+ "error": "Impossible d'associer la Politique `{{policyName}}` à la PDP `{{pdpName}}`",
+ "success": "L'association dde la Politique `{{policyName}}` avec la PDP `{{pdpName}}` a été effectuée avec succès"
+ },
+ "remove": {
+ "title": "Supprimer une Politique",
+ "content": {
+ "query": "Voulez-vous supprimer la Politique `{{policyName}}` ?"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer la Politique `{{policyName}}`",
+ "success": "La Politique `{{policyName}}` a été supprimée avec succès"
+ },
+ "edit" : {
+ "title": "Configuration de la Politique `{{policyName}}`",
+ "update": "- mettre à jour",
+ "show": {
+ "open": "( voir )",
+ "close": "( fermer )"
+ },
+ "basic" : {
+ "title" : "Informations de base",
+ "form": {
+ "id": "Id",
+ "name": "Nom",
+ "genre": "Genre",
+ "model": "Modèle",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Mettre à Jour"
+ },
+ "check": {
+ "name": {
+ "required": "Le Nom est requis"
+ },
+ "Genre": {
+ "required": "Le Genre est requis"
+ }
+ },
+ "error": "Impossible de mettre à jour la Politique `{{policyName}}`",
+ "success": "Le Politique `{{policyName}}` a été mise à jour avec succès"
+ },
+ "perimeter": {
+ "title" : "Périmètres"
+ },
+ "data": {
+ "title" : "Données"
+ },
+ "rules" : {
+ "title" : "Règles"
+ },
+ "assignments": {
+ "title" : "Affectations"
+ }
+ },
+ "add": {
+ "title": "Ajouter une nouvelle Politique",
+ "form": {
+ "name": "Nom",
+ "genre" : "Genre",
+ "model": "Modèles",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Créer la Politique",
+ "cancel": "Annuler"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ },
+ "genre" : {
+ "required" :"Le Genre est requis"
+ },
+ "model" : {
+ "required" :"Un Modèle est requis"
+ }
+ },
+ "error": "Impossible de créer la Politique `{{policyName}}`",
+ "success": "La Politique `{{policyName}}` a été créée avec succès"
+ },
+ "perimeter" :{
+ "subject" : {
+ "title" : "Liste des Sujets associées",
+ "delete": {
+ "error" : "Impossible de supprimer le Sujet : {{subjectName}}, la raison : {{reason}}",
+ "success": "Sujet `{{subjectName}}` a été supprimé avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Element Sujet"
+ },
+ "notFound": "Il n'existe aucun Sujet"
+ },
+ "object" : {
+ "title" : "Liste des Objets associées",
+ "delete": {
+ "error" : "Impossible de supprimer l'Objet : {{objectName}}, la raison : {{reason}}",
+ "success": "Objet `{{objectName}}` a été supprimé avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Element Objet"
+ },
+ "notFound": "Il n'existe aucun Objet"
+ },
+ "action" : {
+ "title" : "Liste des Actions associées",
+ "delete": {
+ "error" : "Impossible de supprimer l'Action : {{actionName}}, la raison : {{reason}}",
+ "success": "Action `{{actionName}}` a été supprimé avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Element Action"
+ },
+ "notFound": "Il n'existe aucune Action"
+ },
+ "update":{
+ "error": "Impossible de mettre à jour le Périmètre `{{perimeterName}}`",
+ "success": "Le Périèmtre `{{perimeterName}}` a été mis à jour"
+ },
+ "table": {
+ "id" : "Id",
+ "name" : "Nom",
+ "description" : "Description",
+ "email" : "Email",
+ "partner":{
+ "id" : "Id du Partenaire"
+ },
+ "action": {
+ "title": "Actions",
+ "delete": "Supprimer",
+ "update": "Mettre à jour",
+ "unmap": "Dissocier"
+ }
+ },
+ "edit": {
+ "name" : "Nom",
+ "description" : "Description",
+ "partnerId": "Partner Id",
+ "policies":"Liste des Politiques",
+ "email": "E-mail",
+ "selectedPolicies": "Politiques selectionnées",
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ }
+ },
+ "action": {
+ "list": "Associer un Périmètre existant",
+ "new": "Ajouter un nouveau Périmètre",
+ "create":"Ajouter le Périmètre ",
+ "map":"Asscoier le Périmètre selectionné",
+ "delete": "Supprimer"
+ },
+ "create": {
+ "error": "Impossible de créer l'Element `{{name}}`",
+ "success": "L'Element `{{name}}` a été créé avec succès"
+ },
+ "delete": {
+ "error": "Impossible de supprimer la Element `{{name}}`",
+ "success": "L'Element `{{name}}` a été supprimée avec succès"
+ }
+ }
+ },
+ "data" :{
+ "subject" : {
+ "title" : "Liste des Data Sujets associées",
+ "delete": {
+ "error" : "Impossible de supprimer la Data Sujet : {{subjectName}}, la raison : {{reason}}",
+ "success": "Data Sujet `{{subjectName}}` a été supprimée avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Data Sujet"
+ },
+ "notFound": "Il n'existe aucune Data Sujet"
+ },
+ "object" : {
+ "title" : "Liste des Data Objets associées",
+ "delete": {
+ "error" : "Impossible de supprimer la Data Objet : {{objectName}}, la raison : {{reason}}",
+ "success": "Data Objet `{{objectName}}` a été supprimée avec succès"
+ },
+ "add": {
+ "title": "Ajouter un Data Objet"
+ },
+ "notFound": "Il n'existe aucun Data Objet"
+ },
+ "action" : {
+ "title" : "Liste des Data Actions associées",
+ "delete": {
+ "error" : "Impossible de supprimer la Data Action : {{actionName}}, la raison : {{reason}}",
+ "success": "Data Action `{{actionName}}` a été supprimée avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Data Action"
+ },
+ "notFound": "Il n'existe aucune Data Action"
+ },
+ "table": {
+ "category" : {
+ "id" : "Id de la Catégorie",
+ "name" : "Nom de la Catégorie"
+ },
+ "name" : "Nom",
+ "description" : "Description",
+ "action": {
+ "title": "Actions",
+ "delete": "Supprimer",
+ "update": "Mettre à jour"
+ },
+ "loading": {
+ "category" : "Loading Catégorie"
+ }
+ },
+ "edit": {
+ "name" : "Nom",
+ "description" : "Description",
+ "categories": "Liste des Catégories",
+ "policies": "Liste des Politiques",
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ },
+ "category":{
+ "required": "Une Catégorie est requise"
+ },
+ "policy":{
+ "required": "Une Politique est requise"
+ }
+ },
+ "action": {
+ "list": "Associer une Data existante",
+ "new": "Créer une nouvelle Data",
+ "create":"Créer la Data",
+ "add":"Ajouter la Data selectionnée",
+ "delete": "Supprimer la Data"
+ },
+ "create": {
+ "error": "Impossible de créer l'Element `{{name}}`",
+ "success": "L'Element `{{name}}` a été créé avec succès"
+ },
+ "delete": {
+ "error": "Impossible de supprimer la Element `{{name}}`",
+ "success": "L'Element `{{name}}` a été supprimée avec succès"
+ }
+ }
+ },
+ "rules": {
+ "title": "Règles",
+ "list": {
+ "search": {
+ "placeholder": "Rechercher des Règles",
+ "reset": "Effacer"
+ },
+ "table": {
+ "id" : "Id",
+ "metaRule": "Meta Règle",
+ "description": "Description",
+ "enabled": "Enabled",
+ "rule": "Règle",
+ "instructions": "Instruction",
+ "notFound": "Il n'existe aucune Règle",
+ "loading": {
+ "metaRule" : "Chargement de la Meta Règle"
+ },
+ "action":{
+ "title": "Actions",
+ "delete": "Supprimer"
+ }
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Ajouter une Règle",
+ "detail": "Consulter",
+ "edit": "Editer",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de récupérer la liste des Règles"
+ },
+ "edit": {
+ "title" : "Liste des Règles associées",
+ "action" : {
+ "create": "Créer une Règles",
+ "delete": {
+ "error" : "Impossible de supprimer la Règles{{rulesName}}, raison : {{reason}}",
+ "success": "Règles`{{rulesName}}` supprimée avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Règles",
+ "policies": "Sélectionnez une Politique",
+ "instructions": "Instruction",
+ "metarules" : "Sélectionnez une des MetaRules associée(s)",
+ "categories":{
+ "subject": "Sélectionnez {{number}} Sujet(s)",
+ "object": "Sélectionnez {{number}} Object(s)",
+ "action": "Sélectionnez {{number}} Action(s)"
+ },
+ "selectedSubjects": "Sujets(s) sélectionnés",
+ "selectedObjects": "Objet(s) sélectionnés",
+ "selectedActions": "Action(s) sélectionnées",
+ "details":{
+ "show": "Détails",
+ "close": "Fermer"
+ },
+ "check":{
+ "policy":{
+ "required": "Une Politique est requise"
+ },
+ "instructions":{
+ "required": "Une Instruction au format JSON est requise"
+ },
+ "metarules":{
+ "required": "une MetaRules est requise"
+ },
+ "subject":{
+ "required": "{{number}} Sujets(s) sont requis"
+ },
+ "object":{
+ "required": "{{number}} Obje(s) sont requis"
+ },
+ "action":{
+ "required": "{{number}} Sujets(s) sont requises"
+ }
+ },
+ "create": {
+ "error": "Impossible de créer la Règles `{{name}}`",
+ "success": "La règles `{{name}}` a été créé avec succès"
+ },
+ "delete": {
+ "error": "Impossible de supprimer la Règle, raison: `{{reason}}`",
+ "success": "La Règle a été supprimée avec succès"
+ }
+ },
+ "notFound": "Il n'y a pas de Règles"
+ }
+ }
+ },
+ "assignments" :{
+ "subject" : {
+ "title" : "Liste des Affectations Sujets associées",
+ "delete": {
+ "error" : "Impossible de supprimer l'Affectations, la raison : {{reason}}",
+ "success": "Affectations a été supprimé avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Affectations Sujet"
+ },
+ "notFound": "Il n'existe aucune Affectations Sujet"
+ },
+ "object" : {
+ "title" : "Liste des Affectations Objets associées",
+ "delete": {
+ "error" : "Impossible de supprimer l'Affectations, la raison : {{reason}}",
+ "success": "Affectations a été supprimée avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Affectations Objet"
+ },
+ "notFound": "Il n'existe aucune Affectations Objet"
+ },
+ "action" : {
+ "title" : "Liste des Affectations Actions associées",
+ "delete": {
+ "error" : "Impossible de supprimer l'Affectations, la raison : {{reason}}",
+ "success": "Affectations Action a été supprimée avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Affectations Action"
+ },
+ "notFound": "Il n'existe aucune Affectations Action"
+ },
+ "table": {
+ "action": {
+ "title": "Actions",
+ "delete": "Supprimer",
+ "update": "Mettre à jour"
+ },
+ "perimeter": {
+ "name": "Nom du Périmètre"
+ },
+ "data":{
+ "name" : "Nom des Data"
+ },
+ "category": {
+ "name" : "Nom de la Catégorie"
+ },
+ "loading": {
+ "category" : "Chargement de la Catégorie",
+ "perimeter": "Chargement du Périmètre",
+ "data": "Chargement des Données"
+ }
+ },
+ "edit": {
+ "policies": "Sélectionnez une Politique",
+ "categories": "Sélectionnez une Catégorie",
+ "perimeters": "Sélectionnez un Perimètre",
+ "data": "Sélectionnez une Donnée",
+ "selectedData" : "Données Séléctionnées",
+ "check": {
+ "policy":{
+ "required": "Une Politique est requise"
+ },
+ "category":{
+ "required": "Une Catégorie est requise"
+ },
+ "perimeter":{
+ "required": "Un Perimètre est requis"
+ },
+ "data":{
+ "required": "Une Donnée est requise"
+ }
+ },
+ "action": {
+ "list": "Ajouter une Affectations existante",
+ "new": "Ajouter une nouvelle Affectations",
+ "create":"Créer l'Affectations",
+ "map":"Ajouter l'Affectations selectionnée",
+ "delete": "Supprimer l'Affectations"
+ },
+ "create": {
+ "error": "Impossible de créer l'Affectations`",
+ "success": "L'Affectations a été créé avec succès"
+ },
+ "delete": {
+ "error": "Impossible de supprimer l'Affectations, raison : `{{reason}}`",
+ "success": "L'Affectations a été supprimée avec succès"
+ }
+ }
+ }
+ },
+ "model":{
+ "title": "Modèles",
+ "list": {
+ "search": {
+ "placeholder": "Rechercher des Modèles",
+ "reset": "Effacer"
+ },
+ "table":{
+ "name":"Nom",
+ "description": "Description",
+ "metaRules":{
+ "number" : "Nombre de Meta Règles"
+ },
+ "notFound": "Il n'existe aucun Modèle"
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Ajouter un modèle",
+ "detail": "Consulter",
+ "edit": "Editer",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de récupérer la liste des Modèles"
+ },
+ "edit" : {
+ "title": "Configuration du Modèle `{{modelName}}`",
+ "update": "- mettre à jour",
+ "basic" : {
+ "title" : "Informations de base",
+ "form": {
+ "id": "Id",
+ "name": "Nom",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Mettre à Jour"
+ },
+ "check": {
+ "name": {
+ "required": "Le Nom est requis"
+ }
+ },
+ "error": "Impossible de mettre à jour le Modèle `{{modelName}}`",
+ "success": "Le Modèle `{{modelName}}` a été mis à jour avec succès"
+ },
+ "metarules": {
+ "title" : "Meta Règles"
+ }
+ },
+ "view": {
+ "title": "Détail du Modèle `{{modelName}}`",
+ "name": "Name",
+ "id": "Id",
+ "description": "Description",
+ "action": {
+ "close": "Fermer"
+ }
+ },
+ "remove": {
+ "title": "Supprimer un Modèle",
+ "content": {
+ "query": "Voulez-vous supprimer le Modèle `{{modelName}}` ?"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer le Modèle `{{modelName}}`",
+ "success": "Le Modèle `{{modelName}}` a été supprimé avec succès"
+ },
+ "metarules" :{
+ "title" : "List des Meta Règles",
+ "table":{
+ "name":"Nom",
+ "description": "Description",
+ "metadata": {
+ "subject" : {
+ "number" : "Nombre de Catégories Sujet"
+ },
+ "object" : {
+ "number" : "Nombre de Catégories Objet"
+ },
+ "action" : {
+ "number" : "Nombre de Catégories Action"
+ }
+ },
+ "notFound": "Il n'existe aucune Meta Règles"
+ },
+ "edit" : {
+ "title" : "Configuration de la Meta Règle `{{metaRuleName}}`",
+ "update": "- mettre à jour",
+ "basic" : {
+ "title" : "Informations de base",
+ "form": {
+ "id": "Id",
+ "name": "Nom",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Mettre à Jour"
+ },
+ "check": {
+ "name": {
+ "required": "Le Nom est requis"
+ }
+ },
+ "error": "Impossible de mettre à jour la Meta Règle `{{metaRuleName}}`",
+ "success": "La Meta Règle `{{metaRuleName}}` a été mis à jour avec succès"
+ }
+ },
+ "update":{
+ "error": "Impossible de mettre à jour la Meta Règle `{{metaRuleName}}`",
+ "success": "La Meta Règle `{{metaRuleName}}` a été mis à jour avec succès"
+ },
+ "action": {
+ "title": "Actions",
+ "edit": "Editer",
+ "remove": "Enlever",
+ "settings" : "Paramètres",
+ "add": "Ajouter",
+ "detail": {
+ "open": "Consulter",
+ "close": "Fermer"
+ }
+ },
+ "add":{
+ "title": "Ajouter une nouvelle Meta Règle",
+ "form": {
+ "name": "Nom",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Ajouter la Meta Règle",
+ "cancel": "Annuler"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ }
+ },
+ "error": "Impossible de créer la Meta Règle `{{metaRuleName}}`",
+ "success": "La Meta Règle `{{metaRuleName}}` a été créée avec succès"
+ },
+ "map":{
+ "title": "Ajouter une Meta Règle",
+ "form" :{
+ "list": "Liste des Meta Règles"
+ },
+ "action": {
+ "create": "Ajouter une nouvelle Meta Règle",
+ "cancel": "Fermer",
+ "new": "Ajouter une Meta Règle",
+ "list": "Ajouter une Meta Règle existante",
+ "add": "Ajouter la Meta Règle sélectionnée",
+ "delete" : "Supprimer la Meta Règle sélectionnée"
+ },
+ "error": "Impossible d'associer le Modèle `{{modelName}}` à la Meta Règle `{{metaRuleName}}`",
+ "success": "L'association du Modèle `{{modelName}}` avec la Meta Règle `{{metaRuleName}}` a été effectuée avec succès"
+ },
+ "unmap": {
+ "title": "Enlever de la Meta Règle du Modèle",
+ "content": "Voulez-vous enlever le Modèle `{{modelName}}` de la Meta Règle `{{metaRuleName}}` ?",
+ "action": {
+ "unmap": "Enlever",
+ "cancel": "Annuler"
+ },
+ "error": "Impossible d'enlever le Modèle `{{modelName}}` de la Meta Règle `{{metaRuleName}}`",
+ "success": "La dissociation du Modèle `{{modelName}}` de la Meta Règle `{{metaRuleName}}` a été effectuée avec succès"
+ },
+ "delete": {
+ "error": "Impossible de supprimer la Meta Rule `{{metaRuleName}}`",
+ "success": "La Meta Rule `{{metaRuleName}}` a été supprimée avec succès"
+ }
+ },
+ "metadata" :{
+ "subject" : {
+ "title" : "Liste des Catégories Sujet associées",
+ "delete": {
+ "error" : "Impossible de supprimer le Sujet : {{subjectName}}, la raison : {{reason}}",
+ "success": "Sujet `{{subjectName}}` a été supprimé avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Catégorie Sujet"
+ },
+ "notFound": "Il n'existe aucun Sujet"
+ },
+ "object" : {
+ "title" : "Liste des Catégories Objet associées",
+ "delete": {
+ "error" : "Impossible de supprimer l'Objet : {{objectName}}, la raison : {{reason}}",
+ "success": "Objet `{{objectName}}` a été supprimé avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Catégorie Objet"
+ },
+ "notFound": "Il n'existe aucun Objet"
+ },
+ "action" : {
+ "title" : "Liste des Catégories Action associées",
+ "remove": "Enlever",
+ "delete": {
+ "error" : "Impossible de supprimer l'Action : {{actionName}}, la raison : {{reason}}",
+ "success": "Action `{{actionName}}` a été supprimé avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Catégorie Action"
+ },
+ "notFound": "Il n'existe aucune Action"
+ },
+ "table": {
+ "id" : "Id",
+ "name" : "Nom",
+ "description" : "Description",
+ "action": {
+ "title": "Actions",
+ "delete": "Supprimer",
+ "update": "Mettre à jour"
+ }
+ },
+ "edit": {
+ "name" : "Nom",
+ "description" : "Description",
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ }
+ },
+ "action": {
+ "list": "Ajouter une Catégorie existante",
+ "new": "Ajouter une nouvelle Catégorie",
+ "create":"Ajouter la Catégorie",
+ "add":"Ajouter la Catégorie selectionnée",
+ "delete": "Supprimer"
+ },
+ "create": {
+ "error": "Impossible de créer la Catégorie `{{name}}`",
+ "success": "La Catégorie `{{name}}` a été créé avec succès"
+ },
+ "delete": {
+ "error": "Impossible de supprimer la Catégorie `{{name}}`",
+ "success": "La Catégorie `{{name}}` a été supprimée avec succès"
+ }
+ }
+ },
+ "add":{
+ "title": "Ajouter un nouveau Model",
+ "form": {
+ "name": "Nom",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Créer le Modèle",
+ "cancel": "Annuler"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ }
+ },
+ "error": "Impossible de créer le Modèle `{{modelName}}`",
+ "success": "Le Modèle `{{modelName}}` a été créé avec succès"
+ }
+ },
+ "project": {
+ "title": "Projects",
+ "list": {
+ "search": {
+ "placeholder": "Rechercher des Projects",
+ "reset": "Effacer"
+ },
+ "table": {
+ "name": "Nom",
+ "domain": "Domaine",
+ "managed": "Supervisé",
+ "enabled": "Activé",
+ "description": "Description",
+ "mapping": "PDP",
+ "loading": {
+ "project": "Chargement des Projects",
+ "pdp": "Chargement du PDP"
+ },
+ "notFound": "Il n'existe aucun Project"
+ },
+ "action": {
+ "title": "Actions",
+ "detail": "Consulter",
+ "delete": "Supprimer",
+ "add": "Ajouter un Project",
+ "map": "Associer à un PDP",
+ "unmap": "Dissocier"
+ },
+ "error": "Impossible de récupérer la liste des Projects"
+ },
+ "view": {
+ "title": "Détail du Project `{{projectName}}`",
+ "action": {
+ "close": "Fermer"
+ },
+ "subject": {
+ "title": "Sujets",
+ "name": "Nom",
+ "mail": "Email",
+ "domain": "Domaine",
+ "enabled": "Activé",
+ "error": "Impossible de récupérer la liste des Sujets"
+ },
+ "object": {
+ "title": "Objets",
+ "category": "Catégorie",
+ "description": "Description",
+ "enabled": "Activé",
+ "name": "Nom",
+ "error": "Impossible de récupérer la liste des Objets",
+ "loading": "Chargement des Objets",
+ "notFound": "Il n'existe aucun Objet"
+ },
+ "role": {
+ "title": "Roles",
+ "category": "Catégorie",
+ "value": "Valeur",
+ "description": "Description",
+ "assigned": "Affecté",
+ "enabled": "Activé",
+ "error": "Impossible de récupérer la liste des Roles",
+ "loading": "Chargement des Roles",
+ "notFound": "Il n'existe aucun Role"
+ },
+ "roleAssignment": {
+ "title": "Affectation des roles",
+ "category": "Catégorie",
+ "attributes": "Attributs",
+ "description": "Description",
+ "error": "impossible de récupérer la liste des affectations",
+ "loading": "Chargement des Affectations",
+ "notFound": "Il n'existe aucune Affectation"
+ },
+ "group": {
+ "title": "Groupes",
+ "category": "Catégorie",
+ "value": "Valeur",
+ "description": "Description",
+ "assigned": "Affecté",
+ "enabled": "Activé",
+ "error": "Impossible de récupérer la liste des Groupes",
+ "loading": "Chargement des Groupes",
+ "notFound": "Il n'existe aucun Groupe"
+ },
+ "groupAssignment": {
+ "title": "Affectation des groupes",
+ "category": "Catégorie",
+ "attributes": "Attributs",
+ "description": "Description",
+ "error": "impossible de récupérer la liste des affectations",
+ "loading": "Chargement des Affectations",
+ "notFound": "Il n'existe aucune Affectation"
+ }
+ },
+ "add": {
+ "title": "Ajouter un nouveau Project",
+ "form": {
+ "name": "Nom",
+ "description": "Description",
+ "enabled": "Activé",
+ "domain": "Domaine"
+ },
+ "action": {
+ "create": "Créer le Project",
+ "cancel": "Annuler"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ },
+ "domain": {
+ "required": "Le domaine est requis"
+ }
+ },
+ "error": "Impossible de créer le Project `{{projectName}}`",
+ "success": "Le Project `{{projectName}}` a été créé avec succès"
+ },
+ "remove": {
+ "title": "Supprimer un Project",
+ "content": {
+ "query": "Voulez-vous supprimer le Project `{{projectName}}` ?",
+ "isNotMapped": "Ce Project est associé avec aucune PDP.",
+ "isMapped": "Ce project est associé avec le PDP `{{pdpName}}`, le supprimer va supprimer le mapping associé"
+ },
+ "mapping":{
+ "remove":{
+ "error": "Impossible de supprimer la relation avec `{{pdpName}}`"
+ }
+ },
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer le Project `{{projectName}}`",
+ "success": "Le Project `{{projectName}}` a été supprimé avec succès"
+ },
+ "map": {
+ "title": "Associé le Project `{{projectName}}` avec une PDP",
+ "form": {
+ "pdp": "PDP"
+ },
+ "action": {
+ "map": "Associer",
+ "cancel": "Annuler"
+ },
+ "check": {
+ "pdp": {
+ "required": "L'PDP est requise"
+ }
+ },
+ "error": "Impossible d'associer le Project `{{projectName}}` avec la PDP `{{pdpName}}`",
+ "success": "L'association du Project `{{projectName}}` avec la PDP `{{pdpName}}` a été effectué avec succès"
+ },
+ "unmap": {
+ "title": "Dissociation Project et PDP",
+ "content": "Voulez-vous dissocier le Project `{{projectName}}` et la PDP `{{pdpName}}` ?",
+ "action": {
+ "unmap": "Dissocier",
+ "cancel": "Annuler"
+ },
+ "error": "Impossible de dissocier le Project `{{projectName}}` et la PDP `{{pdpName}}`",
+ "success": "La dissociation du Project `{{projectName}}` et de la PDP `{{pdpName}}` a été effectuée avec succès"
+ }
+ },
+ "pdp": {
+ "title": "PDPs",
+ "edit" : {
+ "title": "configuration du PDP `{{pdpName}}` ",
+ "update" : "- Mettre à jour",
+ "basic" : {
+ "title" : "Information de base",
+ "form": {
+ "id": "Id",
+ "name": "Nom",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Mettre à jour"
+ },
+ "check": {
+ "name": {
+ "required": "Le Nom est requis"
+ }
+ },
+ "error": "Impossible de mettre à jour la PDP `{{pdpName}}`",
+ "success": "La PDP `{{pdpName}}` a été mis à jour avec succès"
+ },
+ "policy": {
+ "title" : "Politiques"
+ }
+ },
+ "list": {
+ "search": {
+ "placeholder": "Rechercher des PDPs",
+ "reset": "Effacer"
+ },
+ "table": {
+ "name": "Nom",
+ "security_pipeline":{
+ "number" : "Nombre de Règles"
+ },
+ "project": "Project",
+ "loading": {
+ "pdp": "Chargement des PDPs",
+ "project": "Chargement du Project"
+ },
+ "mapping" :{
+ "map": "n'est pas associé à un projet"
+ },
+ "notFound": "Il n'existe aucune PDP"
+ },
+ "action": {
+ "title": "Actions",
+ "detail": "Consulter",
+ "configure": "Configurer",
+ "rule": "Règles",
+ "delete": "Supprimer",
+ "add": "Ajouter une PDP",
+ "edit": "Editer"
+ },
+ "error": "Impossible de récupérer la liste des PDPs"
+ },
+ "add": {
+ "title": "Ajouter une nouvelle PDP",
+ "form": {
+ "name": "Nom",
+ "policy": "Règle",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Créer la PDP",
+ "cancel": "Annuler"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ },
+ "policy": {
+ "required": "Une règle est requise"
+ }
+ },
+ "error": "Impossible de créer la PDP `{{pdpName}}`",
+ "success": "La PDP `{{pdpName}}` a été créée avec succès"
+ },
+ "remove": {
+ "title": "Supprimer une PDP",
+ "content": "Voulez-vous supprimer la PDP `{{pdpName}}` ?",
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer la PDP `{{pdpName}}`",
+ "success": "la PDP `{{pdpName}}` a été supprimé avec succès"
+ },
+ "configure": {
+ "title": "Configuration de la PDP `{{pdpName}}`",
+ "action": {
+ "back": "Liste des PDPs"
+ },
+ "subject": {
+ "panelTitle": "Configuration des Sujets",
+ "title": "Sujets",
+ "add": {
+ "title": "Ajouter un nouveau Sujet",
+ "form": {
+ "name": "Nom",
+ "domain": "Domaine",
+ "enabled": "Activé",
+ "project": "Projet",
+ "password": "Mot de passe",
+ "description": "Description"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "add": "Ajouter Sujet"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ },
+ "domain": {
+ "required": "Le domaine est requis"
+ },
+ "project": {
+ "required": "Le projet est requis"
+ },
+ "password": {
+ "required": "Le mot de passe est requis"
+ }
+ },
+ "error": "Impossible d'ajouter le Sujet `{{subjectName}}`",
+ "success": "Le Sujet `{{subjectName}}` a été ajouté avec succès"
+ },
+ "remove": {
+ "title": "Supprimer un Sujet",
+ "content": "Voulez-vous supprimer le Sujet `{{subjectName}}` de la PDP `{{pdpName}}` ?",
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer le Sujet `{{subjectName}}`",
+ "success": "Le Sujet `{{subjectName}}` a été supprimé avec succès"
+ },
+ "category": {
+ "title": "Catégories",
+ "add": {
+ "title": "Ajouter une nouvelle Catégorie",
+ "form": {
+ "name": "Nom"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "add": "Ajouter Catégorie"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ }
+ },
+ "error": "Impossible d'ajouter la Catégorie `{{categoryName}}`",
+ "success": "Catégorie `{{categoryName}}` ajoutée avec succès"
+ },
+ "remove": {
+ "title": "Supprimer une Catégorie",
+ "content": "Voulez-vous supprimer la Catégorie `{{categoryName}}` de la PDP `{{pdpName}}` ?",
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer la Catégorie `{{categoryName}}`",
+ "success": "La Catégorie `{{categoryName}}` a été supprimée avec succès"
+ }
+ },
+ "categoryValue": {
+ "title": "Valeurs",
+ "add": {
+ "title": "Ajouter une nouvelle Valeur",
+ "form": {
+ "value": "Valeur"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "add": "Ajouter Valeur"
+ },
+ "check": {
+ "value": {
+ "required": "La valeur est requise"
+ }
+ },
+ "error": "Impossible d'ajouter la Valeur `{{valueName}}`",
+ "success": "Valeur `{{valueName}}` ajoutée avec succès"
+ },
+ "remove": {
+ "title": "Supprimer une Valeur",
+ "content": "Voulez-vous supprimer la Valeur `{{valueName}}` de la PDP `{{pdpName}}` ?",
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer la Valeur `{{valueName}}`",
+ "success": "La Valeur `{{valueName}}` a été supprimée avec succès"
+ }
+ },
+ "assignment": {
+ "title": "Affectation des Sujets",
+ "action": {
+ "assign": "Affecter",
+ "unassign": "Désaffecter"
+ },
+ "list": {
+ "notFound": "Il n'existe aucune affectation"
+ },
+ "add": {
+ "error": "Impossible de réaliser l'affectation Sujet `{{subjectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}`",
+ "success": "Affectation de Sujet `{{subjectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}` réalisée avec succès"
+ },
+ "remove": {
+ "error": "Impossible de réaliser la désaffectation Sujet `{{subjectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}`",
+ "success": "Désaffectation de Sujet `{{subjectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}` réalisée avec succès"
+ }
+ }
+ },
+ "object": {
+ "panelTitle": "Configuration des Objets",
+ "title": "Objets",
+ "add": {
+ "title": "Ajouter un nouvel Objet",
+ "form": {
+ "name": "Nom",
+ "image": "Image",
+ "flavor": "Type"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "add": "Ajouter Objet"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ },
+ "image": {
+ "required": "L'image est requise"
+ },
+ "flavor": {
+ "required": "Le type est requis"
+ }
+ },
+ "error": "Impossible d'ajouter l'Objet `{{objectName}}`",
+ "success": "L'Objet `{{objectName}}` a été ajouté avec succès"
+ },
+ "remove": {
+ "title": "Supprimer un Objet",
+ "content": "Voulez-vous supprimer l'Objet `{{objectName}}` de la PDP `{{pdpName}}` ?",
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer l'Objet `{{objectName}}`",
+ "success": "L'Objet `{{objectName}}` a été supprimé avec succès"
+ },
+ "category": {
+ "title": "Catégories",
+ "add": {
+ "title": "Ajouter une nouvelle Catégorie",
+ "form": {
+ "name": "Nom"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "add": "Ajouter Catégorie"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ }
+ },
+ "error": "Impossible d'ajouter la Catégorie `{{categoryName}}`",
+ "success": "Catégorie `{{categoryName}}` ajoutée avec succès"
+ },
+ "remove": {
+ "title": "Supprimer une Catégorie",
+ "content": "Voulez-vous supprimer la Catégorie `{{categoryName}}` de la PDP `{{pdpName}}` ?",
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer la Catégorie `{{categoryName}}`",
+ "success": "La Catégorie `{{categoryName}}` a été supprimée avec succès"
+ }
+ },
+ "categoryValue": {
+ "title": "Valeurs",
+ "add": {
+ "title": "Ajouter une nouvelle Valeur",
+ "form": {
+ "value": "Valeur"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "add": "Ajouter Valeur"
+ },
+ "check": {
+ "value": {
+ "required": "La valeur est requise"
+ }
+ },
+ "error": "Impossible d'ajouter la Valeur `{{valueName}}`",
+ "success": "Valeur `{{valueName}}` ajoutée avec succès"
+ },
+ "remove": {
+ "title": "Supprimer une Valeur",
+ "content": "Voulez-vous supprimer la Valeur `{{valueName}}` de la PDP `{{pdpName}}` ?",
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer la Valeur `{{valueName}}`",
+ "success": "La Valeur `{{valueName}}` a été supprimée avec succès"
+ }
+ },
+ "assignment": {
+ "title": "Affectation des Objets",
+ "action": {
+ "assign": "Affecter",
+ "unassign": "Désaffecter"
+ },
+ "list": {
+ "notFound": "Il n'existe aucune affectation"
+ },
+ "add": {
+ "error": "Impossible de réaliser l'affectation Objet `{{objectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}`",
+ "success": "Affectation de Objet `{{objectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}` réalisée avec succès"
+ },
+ "remove": {
+ "error": "Impossible de réaliser la désaffectation Objet `{{objectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}`",
+ "success": "Désaffectation de Objet `{{objectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}` réalisée avec succès"
+ }
+ }
+ }
+ },
+ "rule": {
+ "title": "Règles de la PDP `{{pdpName}}`",
+ "list": {
+ "table": {
+ "subject": "Sujets",
+ "object": "Objects",
+ "notFound": "Il n'existe aucune règle"
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Ajouter une règle",
+ "delete": "Supprimer une règle"
+ }
+ },
+ "add": {
+ "title": "Ajouter une nouvelle Règle",
+ "action": {
+ "create": "Créer la Règle",
+ "cancel": "Annuler"
+ },
+ "form": {
+ "subject": {
+ "subject": "Sujets",
+ "category": "Catégories",
+ "categoryValue": "Valeur",
+ "action": {
+ "add": "Ajouter",
+ "delete": "Supprimer"
+ }
+ },
+ "object": {
+ "object": "Objets",
+ "category": "Catégories",
+ "categoryValue": "Valeurs",
+ "action": {
+ "add": "Ajouter",
+ "delete": "Supprimer"
+ }
+ }
+ },
+ "success": "La règle a été créée avec succès",
+ "error": "Impossible de créer la règle"
+ },
+ "delete": {
+ "title": "Supprime une Règle",
+ "content": "Voulez-vous supprimer la Valeur règle `{{ruleJson}}` de la PDP `{{pdpName}}` ?",
+ "action": {
+ "delete": "Supprimer la Règle",
+ "cancel": "Annuler"
+ },
+ "error": "Impossible de supprimer la règle `{{ruleJson}}`",
+ "success": "La règle `{{ruleJson}}` a été supprimée avec succès"
+ },
+ "action": {
+ "back": "Liste des PDPs"
+ }
+ }
+ }
+ }
+}
diff --git a/old/moon_gui/delivery/assets/img/ajax-loader.gif b/old/moon_gui/delivery/assets/img/ajax-loader.gif
new file mode 100755
index 00000000..d0bce154
--- /dev/null
+++ b/old/moon_gui/delivery/assets/img/ajax-loader.gif
Binary files differ
diff --git a/old/moon_gui/delivery/assets/img/ajax-waiting.gif b/old/moon_gui/delivery/assets/img/ajax-waiting.gif
new file mode 100755
index 00000000..d84f6537
--- /dev/null
+++ b/old/moon_gui/delivery/assets/img/ajax-waiting.gif
Binary files differ
diff --git a/old/moon_gui/delivery/assets/img/arrow-link.gif b/old/moon_gui/delivery/assets/img/arrow-link.gif
new file mode 100755
index 00000000..ca17f44b
--- /dev/null
+++ b/old/moon_gui/delivery/assets/img/arrow-link.gif
Binary files differ
diff --git a/old/moon_gui/delivery/assets/img/et.jpg b/old/moon_gui/delivery/assets/img/et.jpg
new file mode 100644
index 00000000..67cc0a9d
--- /dev/null
+++ b/old/moon_gui/delivery/assets/img/et.jpg
Binary files differ
diff --git a/old/moon_gui/delivery/assets/img/favicon.ico b/old/moon_gui/delivery/assets/img/favicon.ico
new file mode 100755
index 00000000..a7910bf5
--- /dev/null
+++ b/old/moon_gui/delivery/assets/img/favicon.ico
Binary files differ
diff --git a/old/moon_gui/delivery/assets/img/logo-openstack.png b/old/moon_gui/delivery/assets/img/logo-openstack.png
new file mode 100755
index 00000000..60ab0e1e
--- /dev/null
+++ b/old/moon_gui/delivery/assets/img/logo-openstack.png
Binary files differ
diff --git a/old/moon_gui/delivery/assets/img/logo-orange.gif b/old/moon_gui/delivery/assets/img/logo-orange.gif
new file mode 100755
index 00000000..9c612291
--- /dev/null
+++ b/old/moon_gui/delivery/assets/img/logo-orange.gif
Binary files differ
diff --git a/old/moon_gui/delivery/html/authentication/authentication.tpl.html b/old/moon_gui/delivery/html/authentication/authentication.tpl.html
new file mode 100644
index 00000000..d942d8e8
--- /dev/null
+++ b/old/moon_gui/delivery/html/authentication/authentication.tpl.html
@@ -0,0 +1 @@
+<div class="col-md-6 col-md-offset-3"><h2 data-translate="moon.login.titlePage">Login</h2><form name="form" ng-submit="form.$valid && auth.login()" novalidate><div class="form-group" ng-class="{ 'has-error': form.$submitted && form.username.$invalid }"><label for="username" data-translate="moon.login.username">Username</label><input type="text" id="username" name="username" class="form-control" ng-model="auth.credentials.username" required><div ng-messages="form.$submitted && form.username.$error" class="help-block"><div ng-message="required" data-translate="moon.login.check.username.required">Username is required</div></div></div><div class="form-group" ng-class="{ 'has-error': form.$submitted && form.password.$invalid }"><label for="password" data-translate="moon.login.password">Password</label><input type="password" id="password" name="password" class="form-control" ng-model="auth.credentials.password" required><div ng-messages="form.$submitted && form.password.$error" class="help-block"><div ng-message="required" data-translate="moon.login.check.password.required">Password is required</div></div></div><div class="form-group"><button ng-disabled="auth.loading" class="btn btn-primary" data-translate="moon.login.login">Login</button> <img ng-if="auth.loading" src="assets/img/ajax-loader.gif"></div></form></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/common/404/404.tpl.html b/old/moon_gui/delivery/html/common/404/404.tpl.html
new file mode 100644
index 00000000..f03a2e98
--- /dev/null
+++ b/old/moon_gui/delivery/html/common/404/404.tpl.html
@@ -0,0 +1 @@
+<div data-translate="moon.global.404">Not found!</div><div>Go <a href="" ui-sref="moon.project.list">Projects ?</a></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/common/compatibility/compatibility.tpl.html b/old/moon_gui/delivery/html/common/compatibility/compatibility.tpl.html
new file mode 100644
index 00000000..26c0f09e
--- /dev/null
+++ b/old/moon_gui/delivery/html/common/compatibility/compatibility.tpl.html
@@ -0,0 +1 @@
+<div class="modal" tabindex="-1" data-role="modalCompatibility"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.compatibility.title"></h4></div><div class="modal-body"><span data-translate="moon.compatibility.content"></span></div><div class="modal-footer"><div class="btn-toolbar" style="float: right;"><button ng-click="$hide()" class="btn btn-default" data-translate="moon.compatibility.close">Close</button></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/common/footer/footer.tpl.html b/old/moon_gui/delivery/html/common/footer/footer.tpl.html
new file mode 100644
index 00000000..6c01bd92
--- /dev/null
+++ b/old/moon_gui/delivery/html/common/footer/footer.tpl.html
@@ -0,0 +1 @@
+<div class="container footer" ng-controller="FooterController as footer"><div class="row"><div class="pull-right"><span>v<span ng-bind="footer.version"></span></span> - <a href="" ng-click="footer.showBrowsersCompliance()" data-translate="moon.compatibility.label">browser compatibility</a></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/common/header/header.tpl.html b/old/moon_gui/delivery/html/common/header/header.tpl.html
new file mode 100644
index 00000000..92224309
--- /dev/null
+++ b/old/moon_gui/delivery/html/common/header/header.tpl.html
@@ -0,0 +1 @@
+<div class="container banner" ng-controller="HeaderController as header"><div class="row"><div class="col-md-3 sub-banner"><a ui-sref="moon.dashboard"><img src="assets/img/logo-orange.gif" alt="Orange"> </a><img src="assets/img/logo-openstack.png" alt="OpenStack"></div><div class="col-md-6 center-block"><h1 data-translate="moon.global.applicationName">Moon UI</h1></div><div class="col-md-3"><span class="pull-right"><a href="" ng-click="header.changeLocale('fr', $event)" ng-class="{'strong' : header.currentLanguage === 'fr'}"><img src="assets/img/arrow-link.gif" alt="fr_">fr</a> <a href="" ng-click="header.changeLocale('en', $event)" ng-class="{'strong' : header.currentLanguage === 'en'}"><img src="assets/img/arrow-link.gif" alt="en_">en</a> <a href="" ng-if="connected" ng-click="header.logout()" class="left30"><span class="glyphicon glyphicon-log-out"></span> <span data-translate="moon.logout.title">Logout</span>(<span ng-bind="header.getUser().token.user.name"></span>) </a><a href="" ng-if="!connected" class="left30"><span class="glyphicon glyphicon-log-in"></span> <span data-translate="moon.login.title">Login</span></a></span></div></div><div class="row"><toaster-container toaster-options="{'position-class': 'toast-top-right', 'close-button': true}"></toaster-container></div><div class="row" ng-if="connected"><ul class="nav nav-tabs"><li ng-class="{active: header.isModelTabActive()}"><a ui-sref="moon.model.list" data-translate="moon.menu.model">Models</a></li><li ng-class="{active: header.isPolicyTabActive()}"><a ui-sref="moon.policy.list" data-translate="moon.menu.policy">Policy</a></li><li ng-class="{active: header.isPDPTabActive()}"><a ui-sref="moon.pdp.list" data-translate="moon.menu.pdp">PDP</a></li><li ng-class="{active: header.isProjectTabActive()}"><a ui-sref="moon.project.list" data-translate="moon.menu.project">Projects</a></li><!--<li ng-class="{active: header.isLogsTabActive()}"><a ui-sref="moon.logs" data-translate="moon.menu.logs">Logs</a></li>--></ul></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/common/loader/loader.tpl.html b/old/moon_gui/delivery/html/common/loader/loader.tpl.html
new file mode 100644
index 00000000..dc52e911
--- /dev/null
+++ b/old/moon_gui/delivery/html/common/loader/loader.tpl.html
@@ -0,0 +1 @@
+<img src="assets/img/ajax-loader.gif"> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/common/waiting/waiting.tpl.html b/old/moon_gui/delivery/html/common/waiting/waiting.tpl.html
new file mode 100644
index 00000000..eca2ae9e
--- /dev/null
+++ b/old/moon_gui/delivery/html/common/waiting/waiting.tpl.html
@@ -0,0 +1 @@
+<div class="modal" tabindex="-1" data-role="modalWaiting"><div class="modal-dialog"><div class="modal-content"><div class="modal-body centered"><img src="assets/img/ajax-waiting.gif"></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/dashboard/dashboard.tpl.html b/old/moon_gui/delivery/html/dashboard/dashboard.tpl.html
new file mode 100644
index 00000000..caee0db0
--- /dev/null
+++ b/old/moon_gui/delivery/html/dashboard/dashboard.tpl.html
@@ -0,0 +1 @@
+<div class="container"><div class="row"><h1 data-translate="moon.dashboard.content">Moon:Software-Defined Security Framework</h1></div><div class="row"><img src="assets/img/et.jpg" alt="ET" class="img-responsive img-dashboard"></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/logs/logs.tpl.html b/old/moon_gui/delivery/html/logs/logs.tpl.html
new file mode 100644
index 00000000..bb6dd686
--- /dev/null
+++ b/old/moon_gui/delivery/html/logs/logs.tpl.html
@@ -0,0 +1 @@
+<div class="container">Logs</div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/model/action/model-add.tpl.html b/old/moon_gui/delivery/html/model/action/model-add.tpl.html
new file mode 100644
index 00000000..ed370f05
--- /dev/null
+++ b/old/moon_gui/delivery/html/model/action/model-add.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="ModelAddController as add" class="modal" tabindex="-1" data-role="modalAddModel"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.model.add.title"></h4></div><div class="modal-body"><form class="form-horizontal" role="form" name="add.form"><div class="form-group" ng-class="{'has-error': add.form.name.$invalid && add.form.name.$dirty}"><label for="name" class="col-sm-3 control-label" data-translate="moon.model.add.form.name">Name</label><div class="col-sm-6"><input name="name" id="name" class="form-control" type="text" data-ng-model="add.model.name" required><div class="help-block" ng-show="add.form.name.$dirty && add.form.name.$invalid"><small class="error" ng-show="add.form.name.$error.required" data-translate="moon.model.add.check.name.required">Name is required</small></div></div></div><div class="form-group"><label for="description" class="col-sm-3 control-label" data-translate="moon.model.add.form.description">Description</label><div class="col-sm-6"><textarea id="description" name="description" class="form-control" data-ng-model="add.model.description"></textarea></div></div></form></div><div class="modal-footer"><div class="btn-toolbar" style="float: right;"><a href="" ng-click="$hide()" class="btn btn-default"><span data-translate="moon.model.add.action.cancel">Cancel</span> </a><a href="" ng-disabled="add.loading" ng-click="add.create()" class="btn btn-warning"><span class="glyphicon glyphicon-save"></span> <span data-translate="moon.model.add.action.create">Create Model</span></a><moon-loader ng-if="add.loading"></moon-loader></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/model/action/model-delete.tpl.html b/old/moon_gui/delivery/html/model/action/model-delete.tpl.html
new file mode 100644
index 00000000..a3e51261
--- /dev/null
+++ b/old/moon_gui/delivery/html/model/action/model-delete.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="ModelDeleteController as del" class="modal" tabindex="-1" data-role="modalDeleteModel"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.model.remove.title"></h4></div><div class="modal-body"><p><span data-translate="moon.model.remove.content.query" data-translate-values="{ modelName: del.model.name }"></span></p></div><div class="modal-footer"><div class="btn-toolbar" style="float: right;"><a href="" ng-click="$hide()" class="btn btn-default"><span data-translate="moon.model.remove.action.cancel">Cancel</span> </a><a href="" ng-disabled="del.loading" ng-click="del.remove()" class="btn btn-warning"><span class="glyphicon glyphicon-trash"></span> <span data-translate="moon.model.remove.action.delete">Delete</span></a><moon-loader ng-if="del.loading"></moon-loader></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/model/action/model-view.tpl.html b/old/moon_gui/delivery/html/model/action/model-view.tpl.html
new file mode 100644
index 00000000..4e016c12
--- /dev/null
+++ b/old/moon_gui/delivery/html/model/action/model-view.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="ModelViewController as view" class="modal" tabindex="-1" data-role="modalViewProject"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.model.view.title" data-translate-values="{modelName: view.model.name}"></h4></div><div class="modal-body"><dl class="dl-horizontal"><dt data-translate="moon.model.view.id">Id</dt><dd ng-bind="view.model.id"></dd><dt data-translate="moon.model.view.name">Name</dt><dd ng-bind="view.model.name"></dd><dt data-translate="moon.model.view.description">Description</dt><dd ng-bind="view.model.description"></dd></dl><div ng-if="view.meta_rules_values"><moon-meta-rules-list mapped-model="view.model" edit-mode="false"></moon-meta-rules-list></div><div ng-if="!view.meta_rules_values"><moon-loader></moon-loader></div></div><div class="modal-footer top10"><div class="btn-toolbar" style="float: right;"><button ng-click="$hide()" class="btn btn-default" data-translate="moon.model.view.action.close">Close</button></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/model/edit/metadata/metadata-edit.tpl.html b/old/moon_gui/delivery/html/model/edit/metadata/metadata-edit.tpl.html
new file mode 100644
index 00000000..188c3678
--- /dev/null
+++ b/old/moon_gui/delivery/html/model/edit/metadata/metadata-edit.tpl.html
@@ -0,0 +1 @@
+<div><div class="col-md-4 col-sm-4 col-xs-4"><a class="btn btn-primary" type="button" style="white-space: normal;" ng-click="edit.fromList = !edit.fromList"><span ng-if="!edit.fromList" data-translate="moon.model.metadata.edit.action.list">Add from the list</span> <span ng-if="edit.fromList" data-translate="moon.model.metadata.edit.action.new">Add a new Category</span></a></div><div class="col-md-8 col-sm-8 col-xs-8"><form name="selectMetaData" ng-if="edit.fromList" class="form-horizontal" role="form"><div class="form-group"><ui-select ng-model="edit.selectedMetaData" name="object"><ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match><ui-select-choices repeat="ametaData in edit.list"><div ng-value="ametaData" ng-bind="ametaData.name"></div></ui-select-choices></ui-select></div><div class="form-group"><div class="pull-left col-md-4 col-sm-4 col-xs-4"><a href="" ng-disabled="edit.loading || !edit.selectedMetaData" ng-click="edit.deleteMetaData()" class="btn btn-warning"><span class="glyphicon glyphicon-trash"></span> <span data-translate="moon.model.metadata.edit.action.delete">Delete</span></a></div><div class="pull-right col-md-7 col-md-offset-1 col-sm-7 col-sm-offset-1 col-xs-7 col-xs-offset-1"><a href="" ng-disabled="edit.loading || !edit.selectedMetaData" ng-click="edit.addToMetaRule()" class="btn btn-warning" style="white-space: normal;"><span class="glyphicon glyphicon-link"></span> <span data-translate="moon.model.metadata.edit.action.add">Add the selected Category</span></a></div></div><moon-loader ng-if="edit.loading"></moon-loader></form><form ng-if="!edit.fromList" class="form-horizontal" role="form" name="edit.form"><div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}"><label for="name" class="col-sm-3 control-label" data-translate="moon.model.metadata.edit.name">Name</label><div class="col-sm-6"><input name="name" id="name" class="form-control" type="text" data-ng-model="edit.metaData.name" required><div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid"><small class="error" ng-show="edit.form.name.$error.required" data-translate="moon.model.metadata.edit.check.name.required">Name is required</small></div></div></div><div class="form-group"><label for="description" class="col-sm-3 control-label" data-translate="moon.model.metadata.edit.description">Description</label><div class="col-sm-6"><textarea id="description" name="description" class="form-control" data-ng-model="edit.metaData.description"></textarea></div></div><div class="form-group"><div class="pull-right"><a href="" ng-disabled="edit.loading" ng-click="edit.create()" class="btn btn-warning"><span class="glyphicon glyphicon-save"></span> <span data-translate="moon.model.metadata.edit.action.create">Create</span></a><moon-loader ng-if="edit.loading"></moon-loader></div></div></form></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/model/edit/metadata/metadata-list.tpl.html b/old/moon_gui/delivery/html/model/edit/metadata/metadata-list.tpl.html
new file mode 100644
index 00000000..050bfbce
--- /dev/null
+++ b/old/moon_gui/delivery/html/model/edit/metadata/metadata-list.tpl.html
@@ -0,0 +1,88 @@
+<div><!--
+ !shortDisplay allow to display more details than shortDisplay.
+ It will display panels row by row and each panels list have a table with more columns
+ --><div ng-if="!list.shortDisplay"><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.model.metadata.subject.title">List of associated Subject Categories</h4></div><div class="panel-body"><div class="table-responsive"><table class="table table-striped"><thead><tr><th data-translate="moon.model.metadata.table.id">Id</th><th data-translate="moon.model.metadata.table.name">Name</th><th data-translate="moon.model.metadata.table.description">Description</th><th ng-if="list.editMode" data-translate="moon.model.metadata.table.action.title"></th></tr></thead><moon-loader ng-if="list.loadingCatSub"></moon-loader><tbody ng-if="!list.loadingCatSub && list.getSubjectCategories().length > 0"><tr ng-repeat="(key, value) in list.catSub"><td ng-bind="value.id"></td><td ng-bind="value.name"></td><td ng-bind="value.description"></td><td ng-if="list.editMode"><a href="" ng-if="!value.loader" ng-click="list.unMapSub(value)"><span class="glyphicon glyphicon-transfer"></span> <span class="control-label" data-translate="moon.model.metadata.action.remove">Remove</span> </a><!--<div ng-if="!value.loader" class="dropdown">
+
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.model.metadata.table.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+
+ <ul class="dropdown-menu">
+
+ <li>
+ <a href="" ng-click="list.unMapSub(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metadata.action.remove">Remove</span>
+ </a>
+ </li>
+
+ <li class="divider"></li>
+
+ <li>
+ <a href="" ng-click="list.deleteSub(value)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.model.metadata.table.action.delete">Delete</span>
+ </a>
+ </li>
+
+ </ul>
+
+ </div>--><div ng-if="value.loader"><moon-loader></moon-loader></div></td></tr></tbody><tbody ng-if="!list.loadingCatSub && list.catSub.length === 0"><tr><td data-translate="moon.model.metadata.subject.notFound">There is no Subjects</td><td></td><td></td><td ng-if="list.editMode"></td></tr></tbody></table></div></div></div><div ng-if="list.editMode" class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.model.metadata.subject.add.title">Add a Subject Category</h4></div><div class="panel-body"><moon-meta-data-edit meta-rule="list.metaRule" meta-data-type="list.typeOfSubject"></moon-meta-data-edit></div></div><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.model.metadata.object.title">List associated of Object Categories</h4></div><div class="panel-body"><div class="table-responsive"><table class="table table-striped"><thead><tr><th data-translate="moon.model.metadata.table.id">Id</th><th data-translate="moon.model.metadata.table.name">Name</th><th data-translate="moon.model.metadata.table.description">Description</th><th ng-if="list.editMode" data-translate="moon.model.metadata.table.action.title"></th></tr></thead><moon-loader ng-if="list.loadingCatObj"></moon-loader><tbody ng-if="!list.loadingCatObj && list.catObj.length > 0"><tr ng-repeat="(key, value) in list.catObj"><td ng-bind="value.id"></td><td ng-bind="value.name"></td><td ng-bind="value.description"></td><td ng-if="list.editMode"><a href="" ng-if="!value.loader" ng-click="list.unMapObj(value)"><span class="glyphicon glyphicon-transfer"></span> <span class="control-label" data-translate="moon.model.metadata.action.remove">Remove</span> </a><!--<div ng-if="!value.loader" class="dropdown">
+
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.model.metadata.table.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+
+ <ul class="dropdown-menu">
+
+ <li>
+ <a href="" ng-click="list.unMapObj(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metadata.action.remove">Remove</span>
+ </a>
+ </li>
+
+ <li class="divider"></li>
+
+ <li>
+ <a href="" ng-click="list.deleteObj(value)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.model.metadata.table.action.delete">Delete</span>
+ </a>
+ </li>
+
+ </ul>
+
+ </div>--><div ng-if="value.loader"><moon-loader></moon-loader></div></td></tr></tbody><tbody ng-if="!list.loadingCatObj && list.catObj.length === 0"><tr><td data-translate="moon.model.metadata.object.notFound">There is no Objects</td><td></td><td></td><td ng-if="list.editMode"></td></tr></tbody></table></div></div></div><div ng-if="list.editMode" class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.model.metadata.object.add.title">Add an Object Category</h4></div><div class="panel-body"><moon-meta-data-edit meta-rule="list.metaRule" meta-data-type="list.typeOfObject"></moon-meta-data-edit></div></div><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.model.metadata.action.title">List associated of Action Categories</h4></div><div class="panel-body"><div class="table-responsive"><table class="table table-striped"><thead><tr><th data-translate="moon.model.metadata.table.id">Id</th><th data-translate="moon.model.metadata.table.name">Name</th><th data-translate="moon.model.metadata.table.description">Description</th><th ng-if="list.editMode" data-translate="moon.model.metadata.table.action.title"></th></tr></thead><moon-loader ng-if="list.loadingCatAct"></moon-loader><tbody ng-if="!list.loadingCatAct && list.catAct.length > 0"><tr ng-repeat="(key, value) in list.catAct"><td ng-bind="value.id"></td><td ng-bind="value.name"></td><td ng-bind="value.description"></td><td ng-if="list.editMode"><a href="" ng-if="!value.loader" ng-click="list.unMapAct(value)"><span class="glyphicon glyphicon-transfer"></span> <span class="control-label" data-translate="moon.model.metadata.action.remove">Remove</span> </a><!--<div ng-if="!value.loader" class="dropdown">
+
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.model.metadata.table.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+
+ <ul class="dropdown-menu">
+
+ <li>
+ <a href="" ng-click="list.unMapAct(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metadata.action.remove">Remove</span>
+ </a>
+ </li>
+
+ <li class="divider"></li>
+
+ <li>
+ <a href="" ng-click="list.deleteAct(value)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.model.metadata.table.action.delete">Delete</span>
+ </a>
+ </li>
+
+ </ul>
+
+ </div>--><div ng-if="value.loader"><moon-loader></moon-loader></div></td></tr></tbody><tbody ng-if="!list.loadingCatAct && list.catAct.length === 0"><tr><td data-translate="moon.model.metadata.action.notFound">There is no Actions</td><td></td><td></td><td ng-if="list.editMode"></td></tr></tbody></table></div></div></div><div ng-if="list.editMode" class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.model.metadata.action.add.title">Add an Action Category</h4></div><div class="panel-body">.<moon-meta-data-edit meta-rule="list.metaRule" meta-data-type="list.typeOfAction"></moon-meta-data-edit></div></div></div><!--
+ !shortDisplay allow to display less details than shortDisplay.
+ It will display 3 panels on the same row, each panels have a table with on columns (name)
+ --><div ng-if="list.shortDisplay"><div class="row"><div class="col-md-4"><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.model.metadata.subject.title">List of associated Subject Categories</h4></div><div class="panel-body"><div class="table-responsive"><table class="table table-striped"><thead><tr><th data-translate="moon.model.metadata.table.name">Name</th></tr></thead><moon-loader ng-if="list.loadingCatSub"></moon-loader><tbody ng-if="!list.loadingCatSub && list.getSubjectCategories().length > 0"><tr ng-repeat="(key, value) in list.catSub"><td ng-bind="value.name"></td></tr></tbody><tbody ng-if="!list.loadingCatSub && list.catSub.length === 0"><tr><td data-translate="moon.model.metadata.subject.notFound">There is no Subjects</td></tr></tbody></table></div></div></div></div><div class="col-md-4"><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.model.metadata.object.title">List associated of Object Categories</h4></div><div class="panel-body"><div class="table-responsive"><table class="table table-striped"><thead><tr><th data-translate="moon.model.metadata.table.name">Name</th></tr></thead><moon-loader ng-if="list.loadingCatObj"></moon-loader><tbody ng-if="!list.loadingCatObj && list.catObj.length > 0"><tr ng-repeat="(key, value) in list.catObj"><td ng-bind="value.name"></td></tr></tbody><tbody ng-if="!list.loadingCatObj && list.catObj.length === 0"><tr><td data-translate="moon.model.metadata.object.notFound">There is no Objects</td></tr></tbody></table></div></div></div></div><div class="col-md-4"><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.model.metadata.action.title">List associated of Action Categories</h4></div><div class="panel-body"><div class="table-responsive"><table class="table table-striped"><thead><tr><th data-translate="moon.model.metadata.table.name">Name</th></tr></thead><moon-loader ng-if="list.loadingCatAct"></moon-loader><tbody ng-if="!list.loadingCatAct && list.catAct.length > 0"><tr ng-repeat="(key, value) in list.catAct"><td ng-bind="value.name"></td></tr></tbody><tbody ng-if="!list.loadingCatAct && list.catAct.length === 0"><tr><td data-translate="moon.model.metadata.action.notFound">There is no Actions</td></tr></tbody></table></div></div></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/model/edit/metarules/action/mapping/metarules-add.tpl.html b/old/moon_gui/delivery/html/model/edit/metarules/action/mapping/metarules-add.tpl.html
new file mode 100644
index 00000000..8593236d
--- /dev/null
+++ b/old/moon_gui/delivery/html/model/edit/metarules/action/mapping/metarules-add.tpl.html
@@ -0,0 +1 @@
+<div class="row"><form class="form-horizontal" role="form" name="add.form"><div class="form-group" ng-class="{'has-error': add.form.name.$invalid && add.form.name.$dirty}"><label for="name" class="col-sm-3 control-label" data-translate="moon.model.metarules.add.form.name">Name</label><div class="col-sm-6"><input name="name" id="name" class="form-control" type="text" data-ng-model="add.metaRule.name" required><div class="help-block" ng-show="add.form.name.$dirty && add.form.name.$invalid"><small class="error" ng-show="add.form.name.$error.required" data-translate="moon.model.metarules.add.check.name.required">Name is required</small></div></div></div><div class="form-group"><label for="description" class="col-sm-3 control-label" data-translate="moon.model.metarules.add.form.description">Description</label><div class="col-sm-6"><textarea id="description" name="description" class="form-control" data-ng-model="add.metaRule.description"></textarea></div></div><div class="form-group"><div class="col-sm-8"><div class="pull-right"><a href="" ng-disabled="add.loading" ng-click="add.create()" class="btn btn-warning"><span class="glyphicon glyphicon-save"></span> <span data-translate="moon.model.metarules.add.action.create">Create</span></a><moon-loader ng-if="add.loading"></moon-loader></div></div></div></form></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/model/edit/metarules/action/mapping/metarules-map.tpl.html b/old/moon_gui/delivery/html/model/edit/metarules/action/mapping/metarules-map.tpl.html
new file mode 100644
index 00000000..9041f072
--- /dev/null
+++ b/old/moon_gui/delivery/html/model/edit/metarules/action/mapping/metarules-map.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="moonMetaRulesMapController as map" class="modal" tabindex="-1" data-role="MapMetaRules"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.model.metarules.map.title"></h4></div><div class="modal-body"><div class="row"><div class="col-sm-3"><button class="btn btn-primary" style="white-space: normal;" ng-click="map.addMetaRuleToList = !map.addMetaRuleToList"><span ng-if="!map.addMetaRuleToList" data-translate="moon.model.metarules.map.action.new">Add a new Meta Rule</span> <span ng-if="map.addMetaRuleToList" data-translate="moon.model.metarules.map.action.list">List of Meta Rules</span></button></div><div class="col-sm-9"><form class="form-horizontal" role="form" name="map.form"><div class="form-group" ng-if="!map.addMetaRuleToList"><label class="col-sm-3 control-label" data-translate="moon.model.metarules.map.form.list">List of Meta Rule</label><div class="col-sm-9"><ui-select ng-model="map.selectedMetaRule" name="object"><ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match><ui-select-choices repeat="ametaRule in map.metaRules"><div ng-value="ametaRule" ng-bind="ametaRule.name"></div></ui-select-choices></ui-select></div></div><div class="form-group" ng-if="!map.addMetaRuleToList"><moon-loader ng-if="map.metaRulesLoading || map.mappingLoading"></moon-loader><div class="col-sm-5"><a href="" ng-disabled="map.metaRulesLoading || map.mappingLoading || !map.selectedMetaRule" ng-click="map.deleteMetaRule()" class="btn btn-warning" style="white-space: normal;"><span class="glyphicon glyphicon-trash"></span> <span data-translate="moon.model.metarules.map.action.delete">Delete the selected Meta Rule</span></a></div><div class="col-sm-5 col-sm-offset-2"><a href="" ng-disabled="map.metaRulesLoading || map.mappingLoading || !map.selectedMetaRule" ng-click="map.mapToModel()" class="btn btn-warning" style="white-space: normal;"><span class="glyphicon glyphicon-link"></span> <span data-translate="moon.model.metarules.map.action.add">Add the selected Meta Rule</span></a></div></div><div class="form-group" ng-if="map.addMetaRuleToList"><moon-meta-rules-add></moon-meta-rules-add></div></form></div></div></div><div class="modal-footer"><div class="btn-toolbar" style="float: right;"><a href="" ng-click="$hide()" class="btn btn-default"><span data-translate="moon.model.metarules.add.action.cancel">Cancel</span></a></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/model/edit/metarules/action/mapping/metarules-unmap.tpl.html b/old/moon_gui/delivery/html/model/edit/metarules/action/mapping/metarules-unmap.tpl.html
new file mode 100644
index 00000000..37e21f11
--- /dev/null
+++ b/old/moon_gui/delivery/html/model/edit/metarules/action/mapping/metarules-unmap.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="MetaRulesUnMapController as unmap" class="modal" tabindex="-1" data-role="modalUnMapMetaRule"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.model.metarules.unmap.title"></h4></div><div class="modal-body"><span data-translate="moon.model.metarules.unmap.content" data-translate-values="{ modelName: unmap.model.name, metaRuleName: unmap.metaRule.name }"></span></div><div class="modal-footer"><div class="btn-toolbar" style="float: right;"><a href="" ng-click="$hide()" class="btn btn-default"><span data-translate="moon.model.metarules.unmap.action.cancel">Cancel</span> </a><a href="" ng-disabled="unmap.unMappingLoading" ng-click="unmap.unmap()" class="btn btn-warning"><span class="glyphicon glyphicon-transfer"></span> <span data-translate="moon.model.metarules.unmap.action.unmap">Unmap</span></a><moon-loader ng-if="unmap.unMappingLoading"></moon-loader></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/model/edit/metarules/action/metarules-edit-basic.tpl.html b/old/moon_gui/delivery/html/model/edit/metarules/action/metarules-edit-basic.tpl.html
new file mode 100644
index 00000000..3a171600
--- /dev/null
+++ b/old/moon_gui/delivery/html/model/edit/metarules/action/metarules-edit-basic.tpl.html
@@ -0,0 +1 @@
+<div class="row"><form class="form-horizontal" role="form" name="edit.form"><div class="form-group"><label for="id" class="col-sm-3 control-label" data-translate="moon.model.metarules.edit.basic.form.id">Id</label><div class="col-sm-6"><input name="id" id="id" disabled="disabled" class="form-control" type="text" data-ng-model="edit.metaRuleToEdit.id" required></div></div><div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}"><label for="name" class="col-sm-3 control-label" data-translate="moon.model.metarules.edit.basic.form.name">Name</label><div class="col-sm-6"><input name="name" id="name" class="form-control" type="text" data-ng-model="edit.metaRuleToEdit.name" required><div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid"><small class="error" ng-show="edit.form.name.$error.required" data-translate="moon.model.metarules.edit.basic.check.name.required">Name is required</small></div></div></div><div class="form-group"><label for="description" class="col-sm-3 control-label" data-translate="moon.model.metarules.edit.basic.form.description">Description</label><div class="col-sm-6"><textarea id="description" name="description" class="form-control" data-ng-model="edit.metaRuleToEdit.description"></textarea></div></div><div class="form-group"><div class="col-sm-2 col-sm-offset-3"><a href="" ng-disabled="edit.loading" ng-click="edit.init()" class="btn btn-default"><span data-translate="moon.model.metarules.edit.basic.action.init">Init</span></a></div><div class="col-sm-4 col-sm-offset-2"><a href="" ng-disabled="edit.loading" ng-click="edit.editMetaRule()" class="btn btn-warning"><span class="glyphicon glyphicon-save"></span> <span data-translate="moon.model.metarules.edit.basic.action.update">Update</span></a><moon-loader ng-if="edit.loading"></moon-loader></div></div></form></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/model/edit/metarules/action/metarules-edit.tpl.html b/old/moon_gui/delivery/html/model/edit/metarules/action/metarules-edit.tpl.html
new file mode 100644
index 00000000..5c454d3f
--- /dev/null
+++ b/old/moon_gui/delivery/html/model/edit/metarules/action/metarules-edit.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="MetaRulesEditController as edit" class="modal" tabindex="-1" data-role="modalViewProject"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.model.metarules.edit.title" data-translate-values="{metaRuleName: edit.metaRule.name}"></h4></div><div class="modal-body"><div class="panel panel-default"><div class="panel-heading"><h4><span data-translate="moon.model.edit.basic.title">Basic Information</span> <a href="" ng-click="edit.editBasic = !edit.editBasic"><span data-translate="moon.model.metarules.edit.update">Update</span> <span class="glyphicon glyphicon-cog"></span></a></h4></div><div class="panel-body"><div ng-if="edit.editBasic"><moon-meta-rules-edit-basic meta-rule="edit.metaRule"></moon-meta-rules-edit-basic></div><div ng-if="!edit.editBasic"><dl class="dl-horizontal"><dt>Id</dt><dd ng-bind="edit.metaRule.id"></dd><dt>Name</dt><dd ng-bind="edit.metaRule.name"></dd><dt>Description</dt><dd ng-bind="edit.metaRule.description"></dd></dl></div></div></div><moon-meta-data-list edit-mode="true" meta-rule="edit.metaRule"></moon-meta-data-list></div><div class="modal-footer top10"><div class="btn-toolbar" style="float: right;"><button ng-click="$hide()" class="btn btn-default" data-translate="moon.model.view.action.close">Close</button></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/model/edit/metarules/metarules-list.tpl.html b/old/moon_gui/delivery/html/model/edit/metarules/metarules-list.tpl.html
new file mode 100644
index 00000000..c6d6c92e
--- /dev/null
+++ b/old/moon_gui/delivery/html/model/edit/metarules/metarules-list.tpl.html
@@ -0,0 +1 @@
+<div><div><h4 data-translate="moon.model.metarules.title">List of Meta Rules</h4></div><div class="table-responsive" data-role="table"><table class="table table-striped table-hover" ng-table="list.table"><colgroup><col class="col-md-2"><col class="col-md-2"><col class="col-md-1"><col class="col-md-1"><col class="col-md-1"><col class="col-md-2"></colgroup><thead><tr><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('name', 'asc'), 'sort-desc': list.table.isSortBy('name', 'desc') }" ng-click="list.table.sorting('name', list.table.isSortBy('name', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.model.metarules.table.name">Name</div></th><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('description', 'asc'), 'sort-desc': list.table.isSortBy('description', 'desc') }" ng-click="list.table.sorting('description', list.table.isSortBy('description', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.model.metarules.table.description">Description</div></th><th class="customTables sortable"><div data-translate="moon.model.metarules.table.metadata.subject.number">Number of Subjects</div></th><th class="customTables sortable"><div data-translate="moon.model.metarules.table.metadata.object.number">Number of Subjects</div></th><th class="customTables sortable"><div data-translate="moon.model.metarules.table.metadata.action.number">Number of Actions</div></th><th class="customTables"><div data-translate="moon.model.metarules.action.title">Actions</div></th></tr></thead><tbody ng-if="!list.hasMetaRules()"><tr><td colspan="2"><span data-translate="moon.model.metarules.table.notFound">There is no Meta Rules</span></td></tr></tbody><tbody ng-if="list.hasMetaRules()"><tr ng-repeat="aMetaRules in $data | filter:list.search.find | orderBy:sort:reverse"><td ng-bind="aMetaRules.name"></td><td ng-bind="aMetaRules.description"></td><td ng-bind="aMetaRules.subject_categories.length"></td><td ng-bind="aMetaRules.object_categories.length"></td><td ng-bind="aMetaRules.action_categories.length"></td><td><div ng-if="list.editMode"><div ng-if="!value.loader" class="dropdown"><button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown"><span data-translate="moon.model.metadata.table.action.title">Actions</span> <span class="caret"></span></button><ul class="dropdown-menu"><li><a href="" ng-click="list.unmap.showModal(aMetaRules)"><span class="glyphicon glyphicon-transfer"></span> <span class="control-label" data-translate="moon.model.metarules.action.remove">Remove</span></a></li><li><a href="" ng-click="list.edit.showModal(aMetaRules)"><span class="glyphicon glyphicon-cog"></span> <span class="control-label" data-translate="moon.model.metarules.action.edit">Edit</span></a></li></ul></div></div><div ng-if="!list.editMode"><a href="" ng-click="list.showDetail(aMetaRules)"><span ng-if="aMetaRules.id !== list.getShowDetailValue().id"><span class="glyphicon glyphicon-eye-open"></span> <span class="control-label" data-translate="moon.model.metarules.action.detail.open">Consult</span> </span><span ng-if="aMetaRules.id === list.getShowDetailValue().id"><span class="glyphicon glyphicon-eye-close"></span> <span class="control-label" data-translate="moon.model.metarules.action.detail.close">Close</span></span></a></div></td></tr></tbody></table><div ng-if="list.showDetailValue"><moon-meta-data-list edit-mode="list.editMode" meta-rule="list.getShowDetailValue()"></moon-meta-data-list></div></div><div class="form-group" ng-if="list.editMode"><a href="" ng-click="list.map.showModal()" class="btn btn-default"><span class="glyphicon glyphicon-link"></span> <span data-translate="moon.model.metarules.action.settings">Settings</span></a></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/model/edit/model-edit-basic.tpl.html b/old/moon_gui/delivery/html/model/edit/model-edit-basic.tpl.html
new file mode 100644
index 00000000..a645b1ee
--- /dev/null
+++ b/old/moon_gui/delivery/html/model/edit/model-edit-basic.tpl.html
@@ -0,0 +1 @@
+<div class="row"><form class="form-horizontal" role="form" name="edit.form"><div class="form-group"><label for="id" class="col-sm-3 control-label" data-translate="moon.model.edit.basic.form.id">Id</label><div class="col-sm-6"><input name="id" id="id" disabled="disabled" class="form-control" type="text" data-ng-model="edit.modelToEdit.id" required></div></div><div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}"><label for="name" class="col-sm-3 control-label" data-translate="moon.model.edit.basic.form.name">Name</label><div class="col-sm-6"><input name="name" id="name" class="form-control" type="text" data-ng-model="edit.modelToEdit.name" required><div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid"><small class="error" ng-show="edit.form.name.$error.required" data-translate="moon.model.edit.basic.check.name.required">Name is required</small></div></div></div><div class="form-group"><label for="description" class="col-sm-3 control-label" data-translate="moon.model.edit.basic.form.description">Description</label><div class="col-sm-6"><textarea id="description" name="description" class="form-control" data-ng-model="edit.modelToEdit.description"></textarea></div></div><div class="form-group"><div class="col-sm-2 col-sm-offset-3"><a href="" ng-disabled="edit.loading" ng-click="edit.init()" class="btn btn-default"><span data-translate="moon.model.edit.basic.action.init">Init</span></a></div><div class="col-sm-4 col-sm-offset-2"><a href="" ng-disabled="edit.loading" ng-click="edit.editModel()" class="btn btn-warning"><span class="glyphicon glyphicon-save"></span> <span data-translate="moon.model.edit.basic.action.update">Update</span></a><moon-loader ng-if="edit.loading"></moon-loader></div></div></form></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/model/edit/model-edit.tpl.html b/old/moon_gui/delivery/html/model/edit/model-edit.tpl.html
new file mode 100644
index 00000000..10f4545b
--- /dev/null
+++ b/old/moon_gui/delivery/html/model/edit/model-edit.tpl.html
@@ -0,0 +1,4 @@
+<div class="container"><div class="row"><h3 class="pull-left" data-translate="moon.model.edit.title" data-translate-values="{ modelName: edit.model.name }">Edit</h3></div><div class="panel panel-default"><div class="panel-heading"><span data-translate="moon.model.edit.basic.title">Basic Information</span> <a href="" ng-click="edit.editBasic = !edit.editBasic"><span data-translate="moon.model.edit.update">Update</span> <span class="glyphicon glyphicon-cog"></span></a></div><div class="panel-body"><div ng-if="edit.editBasic"><moon-model-edit-basic model="edit.model"></moon-model-edit-basic></div><div ng-if="!edit.editBasic"><dl class="dl-horizontal"><dt data-translate="moon.model.edit.basic.form.id">Id</dt><dd ng-bind="edit.model.id"></dd><dt data-translate="moon.model.edit.basic.form.name">Name</dt><dd ng-bind="edit.model.name"></dd><dt data-translate="moon.model.edit.basic.form.description">Description</dt><dd ng-bind="edit.model.description"></dd></dl></div></div></div><div class="panel panel-default"><div class="panel-heading"><span data-translate="moon.model.edit.metarules.title">Meta Rule</span><!--<a href="" ng-click="edit.editMetaRules = !edit.editMetaRules">
+ <span data-translate="moon.model.edit.update">Update</span>
+ <span class="glyphicon glyphicon-cog"></span>
+ </a>--></div><div class="panel-body" ng-if="edit.model.meta_rules_values"><div class=""><moon-meta-rules-list mapped-model="edit.model" edit-mode="edit.editMetaRules"></moon-meta-rules-list></div></div><div class="panel-body" ng-if="!edit.model.meta_rules_values"><moon-loader></moon-loader></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/model/model-list.tpl.html b/old/moon_gui/delivery/html/model/model-list.tpl.html
new file mode 100644
index 00000000..138a66b7
--- /dev/null
+++ b/old/moon_gui/delivery/html/model/model-list.tpl.html
@@ -0,0 +1,6 @@
+<div class="container"><div><form class="form-inline pull-right"><div class="form-group"><div><input id="searchProject" data-ng-model="list.search.query" type="text" class="form-control" placeholder="{{'moon.model.list.search.placeholder' | translate}}"></div></div><div class="form-group"><div><button type="submit" class="btn btn-danger" data-ng-click="list.search.reset()" data-translate="moon.model.list.search.reset">Reset</button></div></div></form></div><div>&nbsp;</div><div>&nbsp;</div><div>&nbsp;</div><div class="row"><div class="table-responsive" data-role="table"><table class="table table-striped table-hover" ng-table="list.table"><thead><tr><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('name', 'asc'), 'sort-desc': list.table.isSortBy('name', 'desc') }" ng-click="list.table.sorting('name', list.table.isSortBy('name', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.model.list.table.name">Name</div></th><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('description', 'asc'), 'sort-desc': list.table.isSortBy('description', 'desc') }" ng-click="list.table.sorting('description', list.table.isSortBy('description', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.model.list.table.description">Description</div></th><th class="customTables sortable"><div data-translate="moon.model.list.table.metaRules.number">Number of Meta Rules</div></th><th class="customTables"><div data-translate="moon.model.list.action.title">Actions</div></th></tr></thead><tbody ng-if="!list.hasModels()"><tr><td colspan="2"><span data-translate="moon.model.list.table.notFound">There is no Models</span></td></tr></tbody><tbody ng-if="list.hasModels()"><tr ng-repeat="aModel in $data | filter:list.search.find | orderBy:sort:reverse"><td ng-bind="aModel.name"></td><td ng-bind="aModel.description"></td><td ng-bind="aModel.meta_rules.length"></td><td><div class="dropdown"><button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown"><span data-translate="moon.model.list.action.title">Actions</span> <span class="caret"></span></button><ul class="dropdown-menu"><!-- <li>
+ <a href="" ng-click="list.view.showModal(aModel)">
+ <span class="glyphicon glyphicon-eye-open"></span>
+ <span class="control-label" data-translate="moon.model.list.action.detail">Detail</span>
+ </a>
+ </li>--><li><a href="" ui-sref="moon.model.edit({id: aModel.id})"><span class="glyphicon glyphicon-cog"></span> <span class="control-label" data-translate="moon.model.list.action.edit">Edit</span></a></li><li class="divider"></li><li><a href="" ng-click="list.del.showModal(aModel)"><span class="glyphicon glyphicon-trash"></span> <span class="control-label" data-translate="moon.model.list.action.delete">Delete</span></a></li></ul></div></td></tr></tbody></table></div><div class="container"><div class="form-inline form-group"><a href="" ng-click="list.add.showModal()" class="btn btn-default"><span class="glyphicon glyphicon-plus-sign"></span> <span data-translate="moon.model.list.action.add">Add Model</span></a></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/pdp/action/pdp-add.tpl.html b/old/moon_gui/delivery/html/pdp/action/pdp-add.tpl.html
new file mode 100644
index 00000000..5d8b2b65
--- /dev/null
+++ b/old/moon_gui/delivery/html/pdp/action/pdp-add.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="PDPAddController as add" class="modal" tabindex="-1" data-role="modalAddPDP"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.pdp.add.title"></h4></div><div class="modal-body"><form class="form-horizontal" role="form" name="add.form"><div class="form-group" ng-class="{'has-error': add.form.name.$invalid && add.form.name.$dirty}"><label for="name" class="col-sm-3 control-label" data-translate="moon.pdp.add.form.name">Name</label><div class="col-sm-6"><input name="name" id="name" class="form-control" type="text" data-ng-model="add.pdp.name" required><div class="help-block" ng-show="add.form.name.$dirty && add.form.name.$invalid"><small class="error" ng-show="add.form.name.$error.required" data-translate="moon.pdp.add.check.name.required">Name is required</small></div></div></div><div class="form-group" ng-class="{'has-error': add.form.policy.$dirty && (add.form.policy.$invalid || !add.selectedPolicy)}"><label class="col-sm-3 control-label" data-translate="moon.pdp.add.form.policy">Policy</label><div class="col-sm-6" ng-if="!add.loadingPolicies"><ui-select ng-model="add.selectedPolicy" name="policy" required><ui-select-match placeholder="(None)">{{$select.selected.name}}</ui-select-match><ui-select-choices repeat="policy in add.policies"><div ng-value="policy">{{policy.name}}</div></ui-select-choices></ui-select><div class="help-block" ng-show="add.form.policy.$dirty && (add.form.policy.$invalid || !add.selectedPolicy)"><small class="error" ng-show="add.form.policy.$error.required" data-translate="moon.pdp.add.check.policy.required">Policy is required</small></div></div><div class="col-sm-6" ng-if="add.loadingPolicies"><moon-loader ng-if="add.loadingPolicies"></moon-loader></div></div><div class="form-group"><label for="description" class="col-sm-3 control-label" data-translate="moon.pdp.add.form.description">Description</label><div class="col-sm-6"><textarea name="description" id="description" class="form-control" ng-model="add.pdp.description"></textarea></div></div></form></div><div class="modal-footer"><div class="btn-toolbar" style="float: right;"><a href="" ng-click="$hide()" class="btn btn-default"><span data-translate="moon.pdp.add.action.cancel">Cancel</span> </a><a href="" ng-disabled="add.loading" ng-click="add.create(add.pdp)" class="btn btn-warning"><span class="glyphicon glyphicon-save"></span> <span data-translate="moon.pdp.add.action.create">Create</span></a><moon-loader ng-if="add.loading"></moon-loader></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/pdp/action/pdp-delete.tpl.html b/old/moon_gui/delivery/html/pdp/action/pdp-delete.tpl.html
new file mode 100644
index 00000000..f5f1d322
--- /dev/null
+++ b/old/moon_gui/delivery/html/pdp/action/pdp-delete.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="PDPDeleteController as del" class="modal" tabindex="-1" data-role="modalDeletePDP"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.pdp.remove.title"></h4></div><div class="modal-body"><span data-translate="moon.pdp.remove.content" data-translate-values="{ pdpName: del.pdp.name}"></span></div><div class="modal-footer"><div class="btn-toolbar" style="float: right;"><a href="" ng-click="$hide()" class="btn btn-default"><span data-translate="moon.pdp.remove.action.cancel">Cancel</span> </a><a href="" ng-disabled="del.loading" ng-click="del.remove()" class="btn btn-warning"><span class="glyphicon glyphicon-trash"></span> <span data-translate="moon.pdp.remove.action.delete">Delete</span></a><moon-loader ng-if="del.loading"></moon-loader></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/pdp/edit/pdp-edit-basic.tpl.html b/old/moon_gui/delivery/html/pdp/edit/pdp-edit-basic.tpl.html
new file mode 100644
index 00000000..e15e27e0
--- /dev/null
+++ b/old/moon_gui/delivery/html/pdp/edit/pdp-edit-basic.tpl.html
@@ -0,0 +1 @@
+<div class="row"><form class="form-horizontal" role="form" name="edit.form"><div class="form-group"><label for="id" class="col-sm-3 control-label" data-translate="moon.pdp.edit.basic.form.id">Id</label><div class="col-sm-6"><input name="id" id="id" disabled="disabled" class="form-control" type="text" data-ng-model="edit.pdpToEdit.id" required></div></div><div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}"><label for="name" class="col-sm-3 control-label" data-translate="moon.pdp.edit.basic.form.name">Name</label><div class="col-sm-6"><input name="name" id="name" class="form-control" type="text" data-ng-model="edit.pdpToEdit.name" required><div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid"><small class="error" ng-show="edit.form.name.$error.required" data-translate="moon.pdp.edit.basic.check.name.required">Name is required</small></div></div></div><div class="form-group"><label for="description" class="col-sm-3 control-label" data-translate="moon.pdp.edit.basic.form.description">Description</label><div class="col-sm-6"><textarea id="description" name="description" class="form-control" data-ng-model="edit.pdpToEdit.description"></textarea></div></div><div class="form-group"><div class="col-sm-2 col-sm-offset-3"><a href="" ng-disabled="edit.loading" ng-click="edit.init()" class="btn btn-default"><span data-translate="moon.pdp.edit.basic.action.init">Init</span></a></div><div class="col-sm-4 col-sm-offset-2"><a href="" ng-disabled="edit.loading" ng-click="edit.editPdp()" class="btn btn-warning"><span class="glyphicon glyphicon-save"></span> <span data-translate="moon.pdp.edit.basic.action.update">Update</span></a><moon-loader ng-if="edit.loading"></moon-loader></div></div></form></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/pdp/edit/pdp-edit.tpl.html b/old/moon_gui/delivery/html/pdp/edit/pdp-edit.tpl.html
new file mode 100644
index 00000000..96b3dd78
--- /dev/null
+++ b/old/moon_gui/delivery/html/pdp/edit/pdp-edit.tpl.html
@@ -0,0 +1 @@
+<div class="container"><div class="row"><h3 class="pull-left" data-translate="moon.pdp.edit.title" data-translate-values="{ pdpName: edit.pdp.name }">Edit</h3></div><div class="row"><div class="panel panel-default"><div class="panel-heading"><h4><span data-translate="moon.pdp.edit.basic.title">Basic Information</span> <a href="" ng-click="edit.editBasic = !edit.editBasic"><span data-translate="moon.pdp.edit.update">Update</span> <span class="glyphicon glyphicon-cog"></span></a></h4></div><div class="panel-body"><div ng-if="edit.editBasic"><moon-p-d-p-edit-basic pdp="edit.pdp"></moon-p-d-p-edit-basic></div><div ng-if="!edit.editBasic"><dl class="dl-horizontal"><dt>Id</dt><dd ng-bind="edit.pdp.id"></dd><dt>Name</dt><dd ng-bind="edit.pdp.name"></dd><dt>Description</dt><dd ng-bind="edit.pdp.description"></dd></dl></div></div></div><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.pdp.edit.policy.title">Policies</h4></div><div class="panel-body"><div class="row"><moon-policy-mapped-list pdp="edit.pdp"></moon-policy-mapped-list></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/pdp/pdp-list.tpl.html b/old/moon_gui/delivery/html/pdp/pdp-list.tpl.html
new file mode 100644
index 00000000..31d1aae0
--- /dev/null
+++ b/old/moon_gui/delivery/html/pdp/pdp-list.tpl.html
@@ -0,0 +1 @@
+<div class="container"><div><form class="form-inline pull-right"><div class="form-group"><div><input id="searchPDP" data-ng-model="list.search.query" type="text" class="form-control" placeholder="{{'moon.pdp.list.search.placeholder' | translate}}"></div></div><div class="form-group"><div><button type="submit" class="btn btn-danger" data-ng-click="list.search.reset()" data-translate="moon.pdp.list.search.reset">Reset</button></div></div></form></div><div>&nbsp;</div><div>&nbsp;</div><div>&nbsp;</div><div class="row"><div class="table-responsive" data-role="table"><table class="table table-striped table-hover" ng-table="list.table"><thead><tr><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('name', 'asc'), 'sort-desc': list.table.isSortBy('name', 'desc') }" ng-click="list.table.sorting('name', list.table.isSortBy('name', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.pdp.list.table.name">Name</div></th><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('security_pipeline', 'asc'), 'sort-desc': list.table.isSortBy('security_pipeline', 'desc') }" ng-click="list.table.sorting('security_pipeline', list.table.isSortBy('policy', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.pdp.list.table.security_pipeline.number">Number of Securities</div></th><th class="customTables" ng-class="{ 'sort-asc': list.table.isSortBy('project', 'asc'), 'sort-desc': list.table.isSortBy('project', 'desc') }" ng-click="list.table.sorting('project', list.table.isSortBy('project', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.pdp.list.table.project">Project</div></th><th class="customTables"><div data-translate="moon.pdp.list.action.title">Actions</div></th></tr></thead><tbody ng-if="!list.hasPDPs()"><tr><td colspan="12"><span data-translate="moon.pdp.list.table.notFound">There is no PDP</span></td></tr></tbody><tbody ng-if="list.hasPDPs()"><tr ng-repeat="pdp in $data | filter:list.search.find | orderBy:sort:reverse"><td ng-bind="list.getPDPName(pdp)"></td><td ng-bind="list.getSecPipelineFromPdp(pdp).length"></td><td><div ng-if="list.isMapped(pdp)"><div ng-if="!list.getProjectFromPDP(pdp)"><moon-loader ng-if="!list.getProjectFromPDP(pdp)"></moon-loader><em data-translate="moon.pdp.list.table.loading.project">Loading Project</em></div><div ng-if="list.getProjectFromPDP(pdp)"><span ng-bind="pdp.project.name"></span></div></div><div ng-if="!list.isMapped(pdp)"><span data-translate="moon.pdp.list.table.mapping.map">Is not mapped</span></div></td><td><div class="dropdown"><button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown"><span data-translate="moon.pdp.list.action.title">Actions</span> <span class="caret"></span></button><ul class="dropdown-menu"><li><a href="" ui-sref="moon.pdp.edit({id: pdp.id})"><span class="glyphicon glyphicon-cog"></span> <span class="control-label" data-translate="moon.pdp.list.action.edit">Edit</span></a></li><li class="divider"></li><li><a href="" ng-click="list.del.showModal(pdp)"><span class="glyphicon glyphicon-trash"></span> <span class="control-label" data-translate="moon.pdp.list.action.delete">Delete</span></a></li></ul></div></td></tr></tbody></table></div><div class="container"><div class="form-inline form-group"><a href="" ng-click="list.add.showModal()" class="btn btn-default"><span class="glyphicon glyphicon-plus-sign"></span> <span data-translate="moon.pdp.list.action.add">Add PDP</span></a></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/action/mapping/policy-map.tpl.html b/old/moon_gui/delivery/html/policy/action/mapping/policy-map.tpl.html
new file mode 100644
index 00000000..0d185618
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/action/mapping/policy-map.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="PolicyMapController as map" class="modal" tabindex="-1" data-role="modalMappingPolicy"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.policy.map.title" data-translate-values="{ pdpName: map.pdp.name}"></h4></div><div class="modal-body"><form class="form-horizontal" role="form" name="map.form"><div class="form-group" ng-class="{'has-error': map.form.policy.$dirty && (map.form.policy.$invalid || !map.selectedPolicy)}"><label class="col-sm-3 control-label" data-translate="moon.policy.map.form.list">List of Policies</label><div class="col-sm-6"><ui-select ng-model="map.selectedPolicy" name="policy" required><ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match><ui-select-choices repeat="policy in map.policies"><div ng-bind="policy.name" ng-value="policy"></div></ui-select-choices></ui-select><moon-loader ng-if="map.policiesLoading"></moon-loader><div class="help-block" ng-show="map.form.policy.$dirty && (map.form.policy.$invalid || !map.selectedPolicy)"><small class="error" ng-show="map.form.policy.$error.required" data-translate="moon.policy.map.check.policy.required">Policy is required</small></div></div></div></form></div><div class="modal-footer"><div class="btn-toolbar" style="float: right;"><a href="" ng-click="$hide()" class="btn btn-default"><span data-translate="moon.policy.map.action.cancel">Cancel</span> </a><a href="" ng-disabled="map.mappingLoading" ng-click="map.map()" class="btn btn-warning"><span class="glyphicon glyphicon-link"></span> <span data-translate="moon.policy.map.action.map">Map</span></a><moon-loader ng-if="map.mappingLoading"></moon-loader></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/action/mapping/policy-unmap.tpl.html b/old/moon_gui/delivery/html/policy/action/mapping/policy-unmap.tpl.html
new file mode 100644
index 00000000..844510e9
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/action/mapping/policy-unmap.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="PolicyUnMapController as unmap" class="modal" tabindex="-1" data-role="modalUnmapPolicy"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.policy.unmap.title"></h4></div><div class="modal-body"><span data-translate="moon.policy.unmap.content" data-translate-values="{ policyName: unmap.policy.name, pdpName: unmap.pdp.name }"></span></div><div class="modal-footer"><div class="btn-toolbar" style="float: right;"><a href="" ng-click="$hide()" class="btn btn-default"><span data-translate="moon.policy.unmap.action.cancel">Cancel</span> </a><a href="" ng-disabled="unmap.unMappingLoading" ng-click="unmap.unmap()" class="btn btn-warning"><span class="glyphicon glyphicon-transfer"></span> <span data-translate="moon.policy.unmap.action.unmap">Unmap</span></a><moon-loader ng-if="unmap.unMappingLoading"></moon-loader></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/action/policy-add.tpl.html b/old/moon_gui/delivery/html/policy/action/policy-add.tpl.html
new file mode 100644
index 00000000..17f714c8
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/action/policy-add.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="PolicyAddController as add" class="modal" tabindex="-1" data-role="modalAddPolicy"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.policy.add.title"></h4></div><div class="modal-body"><form class="form-horizontal" role="form" name="add.form"><div class="form-group" ng-class="{'has-error': add.form.name.$invalid && add.form.name.$dirty}"><label for="name" class="col-sm-3 control-label" data-translate="moon.policy.add.form.name">Name</label><div class="col-sm-6"><input name="name" id="name" class="form-control" type="text" data-ng-model="add.policy.name" required><div class="help-block" ng-show="add.form.name.$dirty && add.form.name.$invalid"><small class="error" ng-show="add.form.name.$error.required" data-translate="moon.policy.add.check.name.required">Name is required</small></div></div></div><div class="form-group" ng-class="{'has-error': add.form.genre.$dirty && (add.form.genre.$invalid || !add.selectedGenre)}"><label class="col-sm-3 control-label" data-translate="moon.policy.add.form.genre">Genre</label><div class="col-sm-6"><ui-select ng-model="add.selectedGenre" name="genre" required><ui-select-match placeholder="(None)">{{$select.selected}}</ui-select-match><ui-select-choices repeat="genre in add.genres"><div ng-value="genre">{{genre}}</div></ui-select-choices></ui-select><div class="help-block" ng-show="add.form.genre.$dirty && (add.form.genre.$invalid || !add.selectedPolicy)"><small class="error" ng-show="add.form.genre.$error.required" data-translate="moon.policy.add.check.genre.required">Genre is required</small></div></div></div><div class="form-group" ng-class="{'has-error': add.form.model.$dirty && (add.form.model.$invalid || !add.selectedModel)}"><label class="col-sm-3 control-label" data-translate="moon.policy.add.form.model">Models</label><div class="col-sm-6"><ui-select ng-model="add.selectedModel" name="model" required><ui-select-match placeholder="(None)">{{$select.selected.name}}</ui-select-match><ui-select-choices repeat="model in add.models"><div ng-value="model">{{model.name}}</div></ui-select-choices></ui-select><moon-loader ng-if="add.modelsLoading"></moon-loader><div class="help-block" ng-show="add.form.model.$dirty && (add.form.model.$invalid || !add.selectedModel)"><small class="error" ng-show="add.form.model.$error.required" data-translate="moon.policy.add.check.model.required">Model is required</small></div></div></div><div class="form-group"><label for="description" class="col-sm-3 control-label" data-translate="moon.policy.add.form.description">Description</label><div class="col-sm-6"><textarea id="description" name="description" class="form-control" data-ng-model="add.policy.description"></textarea></div></div></form></div><div class="modal-footer"><div class="btn-toolbar" style="float: right;"><a href="" ng-click="$hide()" class="btn btn-default"><span data-translate="moon.policy.add.action.cancel">Cancel</span> </a><a href="" ng-disabled="add.loading" ng-click="add.create()" class="btn btn-warning"><span class="glyphicon glyphicon-save"></span> <span data-translate="moon.policy.add.action.create">Create Policy</span></a><moon-loader ng-if="add.loading"></moon-loader></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/action/policy-delete.tpl.html b/old/moon_gui/delivery/html/policy/action/policy-delete.tpl.html
new file mode 100644
index 00000000..2e042fc0
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/action/policy-delete.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="PolicyDeleteController as del" class="modal" tabindex="-1" data-role="modalDeletePolicy"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.policy.remove.title"></h4></div><div class="modal-body"><p><span data-translate="moon.policy.remove.content.query" data-translate-values="{ policyName: del.policy.name }"></span></p></div><div class="modal-footer"><div class="btn-toolbar" style="float: right;"><a href="" ng-click="$hide()" class="btn btn-default"><span data-translate="moon.policy.remove.action.cancel">Cancel</span> </a><a href="" ng-disabled="del.loading" ng-click="del.remove()" class="btn btn-warning"><span class="glyphicon glyphicon-trash"></span> <span data-translate="moon.policy.remove.action.delete">Delete</span></a><moon-loader ng-if="del.loading"></moon-loader></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/edit/parameter/assignments/assignments-edit.tpl.html b/old/moon_gui/delivery/html/policy/edit/parameter/assignments/assignments-edit.tpl.html
new file mode 100644
index 00000000..4d9e8a85
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/edit/parameter/assignments/assignments-edit.tpl.html
@@ -0,0 +1 @@
+<div><div class="col-md-12 col-sm-12 col-xs-12"><form ng-if="!edit.fromList" class="form-horizontal" role="form" name="edit.form"><!-- Select Policy --><div class="form-group" ng-class="{'has-error': edit.form.policyList.$invalid && edit.form.policyList.$dirty}"><label for="policyList" class="col-sm-3 control-label" data-translate="moon.policy.assignments.edit.policies">Policy List</label><div class="col-sm-6" ng-if="edit.loadingPolicies"><moon-loader></moon-loader></div><div class="col-sm-6" ng-if="!edit.loadingPolicies"><ui-select ng-model="edit.selectedPolicy" name="policyList" id="policyList" required><ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match><ui-select-choices repeat="aPolicy in edit.policyList"><div ng-value="aPolicy" ng-bind="aPolicy.name"></div></ui-select-choices></ui-select><div class="help-block" ng-show="edit.form.policyList.$dirty && edit.form.policyList.$invalid"><small class="error" ng-show="edit.form.policyList.$error.required" data-translate="moon.policy.assignments.edit.check.policy.required">Policy is required</small></div></div></div><!-- Select Perimeter --><div class="form-group" ng-class="{'has-error': edit.form.perimeterList.$invalid && edit.form.perimeterList.$dirty}"><label for="perimeterList" class="col-sm-3 control-label" data-translate="moon.policy.assignments.edit.perimeters">Perimeter List</label><div class="col-sm-6" ng-if="edit.loadingPerimeters"><moon-loader></moon-loader></div><div class="col-sm-6" ng-if="!edit.loadingPerimeters"><ui-select ng-model="edit.selectedPerimeter" name="perimeterList" id="perimeterList" required><ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match><ui-select-choices repeat="aPerimeter in edit.perimeterList"><div ng-value="aPerimeter" ng-bind="aPerimeter.name"></div></ui-select-choices></ui-select><div class="help-block" ng-show="edit.form.perimeterList.$dirty && edit.form.perimeterList.$invalid"><small class="error" ng-show="edit.form.perimeterList.$error.required" data-translate="moon.policy.assignments.edit.check.perimeter.required">Perimeter is required</small></div></div></div><!-- Select Category --><div class="form-group" ng-class="{'has-error': edit.form.categoryList.$invalid && edit.form.categoryList.$dirty}"><label for="categoryList" class="col-sm-3 control-label" data-translate="moon.policy.assignments.edit.categories">Category List</label><div class="col-sm-6" ng-if="edit.loadingCategories"><moon-loader></moon-loader></div><div class="col-sm-6" ng-if="!edit.loadingCategories"><ui-select ng-model="edit.selectedCategory" name="categoryList" id="categoryList" required><ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match><ui-select-choices repeat="aCategory in edit.categoryList"><div ng-value="aCategory" ng-bind="aCategory.name"></div></ui-select-choices></ui-select><div class="help-block" ng-show="edit.form.categoryList.$dirty && edit.form.categoryList.$invalid"><small class="error" ng-show="edit.form.categoryList.$error.required" data-translate="moon.policy.assignments.edit.check.category.required">Category is required</small></div></div></div><!-- Select Data --><div class="form-group" ng-if="edit.selectedCategory" ng-class="{'has-error': edit.form.dataList.$invalid && edit.form.dataList.$dirty}"><label for="dataList" class="col-sm-3 control-label" data-translate="moon.policy.assignments.edit.data">Data List</label><div class="col-sm-6" ng-if="edit.loadingData"><moon-loader></moon-loader></div><div class="col-sm-4" ng-if="!edit.loadingData"><ui-select ng-model="edit.selectedData" name="dataList" id="dataList"><ui-select-match placeholder="(None)" ng-bind="edit.getName($select.selected)"></ui-select-match><ui-select-choices repeat="aData in edit.dataToBeSelected"><div ng-value="aData" ng-bind="edit.getName(aData)"></div></ui-select-choices></ui-select><div class="help-block" ng-show="edit.form.dataList.$dirty && edit.form.dataList.$invalid || !edit.assignementsAttributeValid"><small class="error" ng-show="edit.form.dataList.$error.required || !edit.assignementsAttributeValid" data-translate="moon.policy.assignments.edit.check.data.required">Data is required</small></div></div><div class="col-sm-2 text-center"><a href="" ng-if="edit.selectedData" ng-click="edit.addSelectedData()"><span style="font-size:1.5em; line-height: 1.5em;" class="glyphicon glyphicon-plus-sign"></span></a></div></div><!-- Selected DataList --><div class="form-group" ng-if="!edit.loadingData"><label class="col-sm-3 control-label" data-translate="moon.policy.assignments.edit.selectedData">Selected Data)</label><div class="col-sm-6"><ul><li ng-repeat="(key, value) in edit.selectedDataList"><span ng-bind="edit.getName(value)"></span> <a href="" ng-click="edit.removeSelectedData(value)"><span style="font-size:1.5em; line-height: 1.5em" class="glyphicon glyphicon-remove"></span></a></li></ul></div></div><div class="form-group"><div class="pull-right"><a href="" ng-disabled="edit.loading" ng-click="edit.create()" class="btn btn-warning"><span class="glyphicon glyphicon-save"></span> <span data-translate="moon.policy.assignments.edit.action.create">Create</span></a><moon-loader ng-if="edit.loading"></moon-loader></div></div></form></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/edit/parameter/assignments/assignments-list.tpl.html b/old/moon_gui/delivery/html/policy/edit/parameter/assignments/assignments-list.tpl.html
new file mode 100644
index 00000000..6cae38d8
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/edit/parameter/assignments/assignments-list.tpl.html
@@ -0,0 +1 @@
+<div><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.assignments.subject.title">List of associated Subjects</h4></div><div class="panel-body"><div class="table-responsive"><table class="table table-striped"><thead><tr><th data-translate="moon.policy.assignments.table.perimeter.name">Perimeter name</th><th data-translate="moon.policy.assignments.table.category.name">Category name</th><th data-translate="moon.policy.assignments.table.data.name">Data name</th></tr></thead><moon-loader ng-if="list.loadingSub"></moon-loader><tbody ng-if="!list.loadingSub && list.getSubjects().length > 0"><tr ng-repeat="(key, value) in list.subjects"><td><div ng-if="!list.getPerimeterFromAssignment(value, list.typeOfSubject)"><moon-loader ng-if="!list.getPerimeterFromAssignment(value)"></moon-loader><em data-translate="moon.policy.assignments.table.loading.perimeter">Loading</em></div><div ng-if="list.getPerimeterFromAssignment(value)"><span ng-bind="value.perimeter.name"></span></div></td><td><div ng-if="!list.getCategoryFromAssignment(value, list.typeOfSubject)"><moon-loader ng-if="!list.getCategoryFromAssignment(value)"></moon-loader><em data-translate="moon.policy.assignments.table.loading.category">Loading</em></div><div ng-if="list.getCategoryFromAssignment(value)"><span ng-bind="value.category.name"></span></div></td><td><span ng-repeat="(index, id) in value.assignments"><span ng-if="!list.getDataFromAssignmentsIndex(index, value, list.typeOfSubject)"><moon-loader ng-if="!list.getDataFromAssignmentsIndex(index, value, list.typeOfSubject)"></moon-loader></span><span ng-if="list.getDataFromAssignmentsIndex(index, value, list.typeOfSubject)"><span ng-bind="value.assignments_value[index].data.name"></span> <a href="" ng-if="!value.loader" ng-click="list.deleteSub(value, value.assignments_value[index].data.id)"><span>(</span><span class="glyphicon glyphicon-transfer"></span><span>)</span> </a><span ng-if="index < value.assignments.length-1">,&nbsp;</span></span></span></td><td><div ng-if="value.loader"><moon-loader></moon-loader></div></td></tr></tbody><tbody ng-if="!list.loadingSub && list.getSubjects().length === 0"><tr><td data-translate="moon.policy.assignments.subject.notFound">There is no Subjects</td><td></td><td></td></tr></tbody></table></div></div></div><div ng-if="list.editMode" class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.assignments.subject.add.title">Add a Subject Category</h4></div><div class="panel-body"><moon-assignments-edit policy="list.policy" assignments-type="list.typeOfSubject"></moon-assignments-edit></div></div><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.assignments.object.title">List associated of Objects</h4></div><div class="panel-body"><div class="table-responsive"><table class="table table-striped"><thead><tr><th data-translate="moon.policy.assignments.table.perimeter.name">Perimeter name</th><th data-translate="moon.policy.assignments.table.category.name">Category name</th><th data-translate="moon.policy.assignments.table.data.name">Data name</th></tr></thead><moon-loader ng-if="list.loadingObj"></moon-loader><tbody ng-if="!list.loadingObj && list.getObjects().length > 0"><tr ng-repeat="(key, value) in list.objects"><td><div ng-if="!list.getPerimeterFromAssignment(value, list.typeOfObject)"><moon-loader ng-if="!list.getPerimeterFromAssignment(value)"></moon-loader><em data-translate="moon.policy.assignments.table.loading.perimeter">Loading</em></div><div ng-if="list.getPerimeterFromAssignment(value)"><span ng-bind="value.perimeter.name"></span></div></td><td><div ng-if="!list.getCategoryFromAssignment(value, list.typeOfObject)"><moon-loader ng-if="!list.getCategoryFromAssignment(value)"></moon-loader><em data-translate="moon.policy.assignments.table.loading.category">Loading</em></div><div ng-if="list.getCategoryFromAssignment(value)"><span ng-bind="value.category.name"></span></div></td><td><span ng-repeat="(index, id) in value.assignments"><span ng-if="!list.getDataFromAssignmentsIndex(index, value, list.typeOfObject)"><moon-loader ng-if="!list.getDataFromAssignmentsIndex(index, value, list.typeOfObject)"></moon-loader></span><span ng-if="list.getDataFromAssignmentsIndex(index, value, list.typeOfObject)"><span ng-if="value.assignments_value[index].data.name" ng-bind="value.assignments_value[index].data.name"></span> <span ng-if="value.assignments_value[index].data.value.name" ng-bind="value.assignments_value[index].data.value.name"></span> <a href="" ng-if="!value.loader" ng-click="list.deleteObj(value, value.assignments_value[index].data.id)"><span>(</span><span class="glyphicon glyphicon-transfer"></span><span>)</span> </a><span ng-if="index < value.assignments.length-1">,&nbsp;</span></span></span></td></tr></tbody><tbody ng-if="!list.loadingObj && list.getObjects().length === 0"><tr><td data-translate="moon.policy.assignments.object.notFound">There is no Objects</td><td></td><td></td></tr></tbody></table></div></div></div><div ng-if="list.editMode" class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.assignments.object.add.title">Add an Object Category</h4></div><div class="panel-body"><moon-assignments-edit policy="list.policy" assignments-type="list.typeOfObject"></moon-assignments-edit></div></div><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.assignments.action.title">List associated of Actions</h4></div><div class="panel-body"><div class="table-responsive"><table class="table table-striped"><thead><tr><th data-translate="moon.policy.assignments.table.perimeter.name">Perimeter name</th><th data-translate="moon.policy.assignments.table.category.name">Category name</th><th data-translate="moon.policy.assignments.table.data.name">Data name</th></tr></thead><moon-loader ng-if="list.loadingAct"></moon-loader><tbody ng-if="!list.loadingAct && list.getActions().length > 0"><tr ng-repeat="(key, value) in list.actions"><td><div ng-if="!list.getPerimeterFromAssignment(value, list.typeOfAction)"><moon-loader ng-if="!list.getPerimeterFromAssignment(value)"></moon-loader><em data-translate="moon.policy.assignments.table.loading.perimeter">Loading</em></div><div ng-if="list.getPerimeterFromAssignment(value)"><span ng-bind="value.perimeter.name"></span></div></td><td><div ng-if="!list.getCategoryFromAssignment(value, list.typeOfAction)"><moon-loader ng-if="!list.getCategoryFromAssignment(value)"></moon-loader><em data-translate="moon.policy.assignments.table.loading.category">Loading</em></div><div ng-if="list.getCategoryFromAssignment(value)"><span ng-bind="value.category.name"></span></div></td><td><span ng-repeat="(index, id) in value.assignments"><span ng-if="!list.getDataFromAssignmentsIndex(index, value, list.typeOfAction)"><moon-loader ng-if="!list.getDataFromAssignmentsIndex(index, value, list.typeOfAction)"></moon-loader></span><span ng-if="list.getDataFromAssignmentsIndex(index, value, list.typeOfAction)"><span ng-if="value.assignments_value[index].data.name" ng-bind="value.assignments_value[index].data.name"></span> <span ng-if="value.assignments_value[index].data.value.name" ng-bind="value.assignments_value[index].data.value.name"></span> <a href="" ng-if="!value.loader" ng-click="list.deleteAct(value, value.assignments_value[index].data.id)"><span>(</span><span class="glyphicon glyphicon-transfer"></span><span>)</span> </a><span ng-if="index < value.assignments.length-1">,&nbsp;</span></span></span></td></tr></tbody><tbody ng-if="!list.loadingAct && list.getActions().length === 0"><tr><td data-translate="moon.policy.assignments.action.notFound">There is no Actions</td><td></td><td></td></tr></tbody></table></div></div></div><div ng-if="list.editMode" class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.assignments.action.add.title">Add an Action Category</h4></div><div class="panel-body">.<moon-assignments-edit policy="list.policy" assignments-type="list.typeOfAction"></moon-assignments-edit></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/edit/parameter/data/data-edit.tpl.html b/old/moon_gui/delivery/html/policy/edit/parameter/data/data-edit.tpl.html
new file mode 100644
index 00000000..d63f6683
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/edit/parameter/data/data-edit.tpl.html
@@ -0,0 +1 @@
+<div><div class="col-md-12 col-sm-12 col-xs-12"><form ng-if="!edit.fromList" class="form-horizontal" role="form" name="edit.form"><div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}"><label for="name" class="col-sm-3 control-label" data-translate="moon.policy.data.edit.name">Name</label><div class="col-sm-6"><input name="name" id="name" class="form-control" type="text" data-ng-model="edit.data.name" required><div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid"><small class="error" ng-show="edit.form.name.$error.required" data-translate="moon.policy.data.edit.check.name.required">Name is required</small></div></div></div><div class="form-group"><label for="description" class="col-sm-3 control-label" data-translate="moon.policy.data.edit.description">Description</label><div class="col-sm-6"><textarea id="description" name="description" class="form-control" data-ng-model="edit.data.description"></textarea></div></div><div class="form-group" ng-class="{'has-error': edit.form.categoryList.$invalid && edit.form.categoryList.$dirty}"><label for="categoryList" class="col-sm-3 control-label" data-translate="moon.policy.data.edit.categories">Category List</label><div class="col-sm-6"><ui-select ng-model="edit.selectedCategory" name="categoryList" id="categoryList" required><ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match><ui-select-choices repeat="aCategory in edit.categoriesToBeSelected"><div ng-value="aCategory" ng-bind="aCategory.name"></div></ui-select-choices></ui-select><div class="help-block" ng-show="edit.form.categoryList.$dirty && edit.form.categoryList.$invalid"><small class="error" ng-show="edit.form.categoryList.$error.required" data-translate="moon.policy.data.edit.check.category.required">Category is required</small></div></div></div><div class="form-group"><div class="pull-right"><a href="" ng-disabled="edit.loading" ng-click="edit.create()" class="btn btn-warning"><span class="glyphicon glyphicon-save"></span> <span data-translate="moon.policy.data.edit.action.create">Create</span></a><moon-loader ng-if="edit.loading"></moon-loader></div></div></form></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/edit/parameter/data/data-list.tpl.html b/old/moon_gui/delivery/html/policy/edit/parameter/data/data-list.tpl.html
new file mode 100644
index 00000000..ef9b2ba7
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/edit/parameter/data/data-list.tpl.html
@@ -0,0 +1,113 @@
+<div><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.data.subject.title">List of associated Subjects</h4></div><div class="panel-body"><div class="table-responsive"><table class="table table-striped"><thead><tr><th data-translate="moon.policy.data.table.name">Name</th><th data-translate="moon.policy.data.table.description">Description</th><th data-translate="moon.policy.data.table.category.name">Category</th><th data-translate="moon.policy.data.table.action.title"></th></tr></thead><moon-loader ng-if="list.loadingSub"></moon-loader><tbody ng-if="!list.loadingSub && list.getSubjects().length > 0"><tr ng-repeat="(key, value) in list.subjects"><td ng-bind="value.name"></td><td ng-bind="value.description"></td><td><div ng-if="!list.getCategoryFromData(value, list.typeOfSubject)"><moon-loader ng-if="!list.getCategoryFromData(value)"></moon-loader><em data-translate="moon.policy.list.table.loading.category">Loading</em></div><div ng-if="list.getCategoryFromData(value)"><span ng-bind="value.category.name"></span></div></td><td><a href="" ng-if="!value.loader" ng-click="list.deleteSub(value)"><span class="glyphicon glyphicon-transfer"></span> <span class="control-label" data-translate="moon.policy.data.table.action.delete">Delete</span></a><div ng-if="value.loader"><moon-loader></moon-loader></div></td><!--<td>
+
+ <div class="dropdown">
+
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.policy.data.table.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+
+ <ul class="dropdown-menu">
+
+ <li>
+ <a href="" ng-click="list.unMapSub(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metarules.action.unmap">Unmap</span>
+ </a>
+ </li>
+
+ <li class="divider"></li>
+
+ <li>
+ <a href="" ng-click="list.deleteSub(value)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.policy.data.table.action.delete">Delete</span>
+ </a>
+ </li>
+
+ </ul>
+
+ </div>
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>--></tr></tbody><tbody ng-if="!list.loadingSub && list.getSubjects().length === 0"><tr><td colspan="4" data-translate="moon.policy.data.subject.notFound">There is no Subjects</td></tr></tbody></table></div></div></div><div ng-if="list.editMode" class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.data.subject.add.title">Add a Subject Category</h4></div><div class="panel-body"><moon-data-edit policy="list.policy" mn-data-type="list.typeOfSubject"></moon-data-edit></div></div><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.data.object.title">List associated of Objects</h4></div><div class="panel-body"><div class="table-responsive"><table class="table table-striped"><thead><tr><th data-translate="moon.policy.data.table.name">Name</th><th data-translate="moon.policy.data.table.description">Description</th><th data-translate="moon.policy.data.table.category.name">Category</th><th data-translate="moon.policy.data.table.action.title">Actions</th></tr></thead><moon-loader ng-if="list.loadingObj"></moon-loader><tbody ng-if="!list.loadingObj && list.getObjects().length > 0"><tr ng-repeat="(key, value) in list.objects"><td ng-bind="value.value.name"></td><td ng-bind="value.value.description"></td><td><div ng-if="!list.getCategoryFromData(value, list.typeOfObject)"><moon-loader ng-if="!list.getCategoryFromData(value)"></moon-loader><em data-translate="moon.policy.list.table.loading.category">Loading</em></div><div ng-if="list.getCategoryFromData(value)"><span ng-bind="value.category.name"></span></div></td><td><a href="" ng-if="!value.loader" ng-click="list.deleteObj(value)"><span class="glyphicon glyphicon-transfer"></span> <span class="control-label" data-translate="moon.policy.data.table.action.delete">Delete</span></a><div ng-if="value.loader"><moon-loader></moon-loader></div></td><!--<td>
+
+ <div class="dropdown">
+
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.policy.data.table.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+
+ <ul class="dropdown-menu">
+
+ <li>
+ <a href="" ng-click="list.unMapObj(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metarules.action.unmap">Unmap</span>
+ </a>
+ </li>
+
+ <li class="divider"></li>
+
+ <li>
+ <a href="" ng-click="list.deleteObj(value)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.policy.data.table.action.delete">Delete</span>
+ </a>
+ </li>
+
+ </ul>
+
+ </div>
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>
+ </tr>--></tr></tbody><tbody ng-if="!list.loadingObj && list.getObjects().length === 0"><tr><td colspan="4" data-translate="moon.policy.data.object.notFound">There is no Objects</td></tr></tbody></table></div></div></div><div ng-if="list.editMode" class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.data.object.add.title">Add an Object Category</h4></div><div class="panel-body"><moon-data-edit policy="list.policy" mn-data-type="list.typeOfObject"></moon-data-edit></div></div><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.data.action.title">List associated of Actions</h4></div><div class="panel-body"><div class="table-responsive"><table class="table table-striped"><thead><tr><th data-translate="moon.policy.data.table.name">Name</th><th data-translate="moon.policy.data.table.description">Description</th><th data-translate="moon.policy.data.table.category.name">Category</th><th data-translate="moon.policy.data.table.action.title">Actions</th></tr></thead><moon-loader ng-if="list.loadingAct"></moon-loader><tbody ng-if="!list.loadingAct && list.getActions().length > 0"><tr ng-repeat="(key, value) in list.actions"><td ng-bind="value.value.name"></td><td ng-bind="value.value.description"></td><td><div ng-if="!list.getCategoryFromData(value, list.typeOfAction)"><moon-loader ng-if="!list.getCategoryFromData(value)"></moon-loader><em data-translate="moon.policy.list.table.loading.category">Loading</em></div><div ng-if="list.getCategoryFromData(value)"><span ng-bind="value.category.name"></span></div></td><td><a href="" ng-if="!value.loader" ng-click="list.deleteSub(value)"><span class="glyphicon glyphicon-transfer"></span> <span class="control-label" data-translate="moon.policy.data.table.action.delete">Delete</span></a><div ng-if="value.loader"><moon-loader></moon-loader></div></td><!--<td>
+
+ <div class="dropdown">
+
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.policy.data.table.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+
+ <ul class="dropdown-menu">
+
+ <li>
+ <a href="" ng-click="list.unMapAct(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metarules.action.unmap">Unmap</span>
+ </a>
+ </li>
+
+ <li class="divider"></li>
+
+ <li>
+ <a href="" ng-click="list.deleteAct(value)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.policy.data.table.action.delete">Delete</span>
+ </a>
+ </li>
+
+ </ul>
+
+ </div>
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>--></tr></tbody><tbody ng-if="!list.loadingAct && list.getActions().length === 0"><tr><td colspan="4" data-translate="moon.policy.data.action.notFound">There is no Actions</td></tr></tbody></table></div></div></div><div ng-if="list.editMode" class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.data.action.add.title">Add an Action Category</h4></div><div class="panel-body">.<moon-data-edit policy="list.policy" mn-data-type="list.typeOfAction"></moon-data-edit></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/edit/parameter/perimeter/perimeter-edit.tpl.html b/old/moon_gui/delivery/html/policy/edit/parameter/perimeter/perimeter-edit.tpl.html
new file mode 100644
index 00000000..23b29cb5
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/edit/parameter/perimeter/perimeter-edit.tpl.html
@@ -0,0 +1,11 @@
+<div><div class="col-md-4 col-sm-4 col-xs-4"><a class="btn btn-primary" type="button" style="white-space: normal;" ng-click="edit.fromList = !edit.fromList"><span ng-if="!edit.fromList" data-translate="moon.policy.perimeter.edit.action.list">Add from the list</span> <span ng-if="edit.fromList" data-translate="moon.policy.perimeter.edit.action.new">Add a new Perimeter</span></a></div><div class="col-md-8 col-sm-8 col-xs-8"><form name="selectMetaData" ng-if="edit.fromList" class="form-horizontal" role="form"><div class="form-group"><ui-select ng-model="edit.selectedPerimeter" name="object"><ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match><ui-select-choices repeat="aPerimeter in edit.list"><div ng-value="aPerimeter" ng-bind="aPerimeter.name"></div></ui-select-choices></ui-select></div><div class="form-group"><div class="pull-left col-md-4 col-sm-4 col-xs-4"><a href="" ng-disabled="edit.loading || !edit.selectedPerimeter" ng-click="edit.deletePerimeter()" class="btn btn-warning"><span class="glyphicon glyphicon-trash"></span> <span data-translate="moon.policy.perimeter.edit.action.delete">Delete</span></a></div><div class="pull-right col-md-7 col-md-offset-1 col-sm-7 col-sm-offset-1 col-xs-7 col-xs-offset-1"><a href="" ng-disabled="edit.loading || !edit.selectedPerimeter" ng-click="edit.addToPolicy()" class="btn btn-warning" style="white-space: normal;"><span class="glyphicon glyphicon-link"></span> <span data-translate="moon.policy.perimeter.edit.action.add">Add the selected Perimeter</span></a></div></div><moon-loader ng-if="edit.loading"></moon-loader></form><form ng-if="!edit.fromList" class="form-horizontal" role="form" name="edit.form"><div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}"><label for="name" class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.name">Name</label><div class="col-sm-6"><input name="name" id="name" class="form-control" type="text" data-ng-model="edit.perimeter.name" required><div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid"><small class="error" ng-show="edit.form.name.$error.required" data-translate="moon.policy.perimeter.edit.check.name.required">Name is required</small></div></div></div><div class="form-group"><label for="description" class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.description">Description</label><div class="col-sm-6"><textarea id="description" name="description" class="form-control" data-ng-model="edit.perimeter.description"></textarea></div></div><!--
+ <div class="form-group">
+
+ <label for="partnerId" class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.partnerId">Partner Id</label>
+
+ <div class="col-sm-6">
+ <input name="partnerId" id="partnerId" class="form-control" type="text" data-ng-model="edit.perimeter.partnerId" />
+ </div>
+
+ </div>
+ --><div class="form-group" ng-if="edit.perimeterType === edit.subjectType" ng-class="{'has-error': edit.form.email.$invalid && edit.form.email.$dirty}"><label for="email" class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.email">Email</label><div class="col-sm-6"><input name="email" id="email" class="form-control" type="email" data-ng-model="edit.perimeter.email"></div></div><div class="form-group"><label for="policyList" class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.policies">Policy List</label><div class="col-sm-5"><ui-select ng-model="edit.selectedPolicy" id="policyList"><ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match><ui-select-choices repeat="aPolicy in edit.policiesToBeSelected"><div ng-value="aPolicy" ng-bind="aPolicy.name"></div></ui-select-choices></ui-select></div><div class="col-sm-1 text-center"><a href="" ng-click="edit.addPolicyToPerimeter()"><span style="font-size:1.5em; line-height: 1.5em;" class="glyphicon glyphicon-plus-sign"></span></a></div></div><div class="form-group"><label class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.selectedPolicies">Selected Policies</label><div class="col-sm-6"><ul><li ng-repeat="(key, value) in edit.selectedPolicyList"><span ng-bind="value.name"></span> <a href="" ng-click="edit.removeSelectedPolicy(value)"><span style="font-size:1.5em; line-height: 1.5em" class="glyphicon glyphicon-remove"></span></a></li></ul></div></div><div class="form-group"><div class="pull-right"><a href="" ng-disabled="edit.loading" ng-click="edit.create()" class="btn btn-warning"><span class="glyphicon glyphicon-save"></span> <span data-translate="moon.policy.perimeter.edit.action.create">Create</span></a><moon-loader ng-if="edit.loading"></moon-loader></div></div></form></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/edit/parameter/perimeter/perimeter-list.tpl.html b/old/moon_gui/delivery/html/policy/edit/parameter/perimeter/perimeter-list.tpl.html
new file mode 100644
index 00000000..5331e640
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/edit/parameter/perimeter/perimeter-list.tpl.html
@@ -0,0 +1 @@
+<div><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.perimeter.subject.title">List of associated Subjects</h4></div><div class="panel-body"><div class="table-responsive"><table class="table table-striped"><thead><tr><th data-translate="moon.policy.perimeter.table.name">Name</th><th data-translate="moon.policy.perimeter.table.description">Description</th><th data-translate="moon.policy.perimeter.table.email">Email</th><th data-translate="moon.policy.perimeter.table.action.title"></th></tr></thead><moon-loader ng-if="list.loadingSub"></moon-loader><tbody ng-if="!list.loadingSub && list.getSubjects().length > 0"><tr ng-repeat="(key, value) in list.subjects"><td ng-bind="value.name"></td><td ng-bind="value.description"></td><td ng-bind="value.email"></td><td><a href="" ng-if="!value.loader" ng-click="list.unMapSub(value)"><span class="glyphicon glyphicon-transfer"></span> <span class="control-label" data-translate="moon.policy.perimeter.table.action.unmap">Unmap</span></a><div ng-if="value.loader"><moon-loader></moon-loader></div></td></tr></tbody><tbody ng-if="!list.loadingSub && list.getSubjects().length === 0"><tr><td data-translate="moon.policy.perimeter.subject.notFound">There is no Subjects</td><td></td><td></td><td></td></tr></tbody></table></div></div></div><div ng-if="list.editMode" class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.perimeter.subject.add.title">Add a Subject Category</h4></div><div class="panel-body"><moon-perimeter-edit policy="list.policy" perimeter-type="list.typeOfSubject"></moon-perimeter-edit></div></div><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.perimeter.object.title">List associated of Objects</h4></div><div class="panel-body"><div class="table-responsive"><table class="table table-striped"><thead><tr><th data-translate="moon.policy.perimeter.table.name">Name</th><th data-translate="moon.policy.perimeter.table.description">Description</th><th data-translate="moon.policy.perimeter.table.action.title"></th></tr></thead><moon-loader ng-if="list.loadingObj"></moon-loader><tbody ng-if="!list.loadingObj && list.getObjects().length > 0"><tr ng-repeat="(key, value) in list.objects"><td ng-bind="value.name"></td><td ng-bind="value.description"></td><td><a href="" ng-if="!value.loader" ng-click="list.unMapObj(value)"><span class="glyphicon glyphicon-transfer"></span> <span class="control-label" data-translate="moon.policy.perimeter.table.action.unmap">Unmap</span></a><div ng-if="value.loader"><moon-loader></moon-loader></div></td></tr></tbody><tbody ng-if="!list.loadingObj && list.getObjects().length === 0"><tr><td data-translate="moon.policy.perimeter.object.notFound">There is no Objects</td><td></td><td></td></tr></tbody></table></div></div></div><div ng-if="list.editMode" class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.perimeter.object.add.title">Add an Object Category</h4></div><div class="panel-body"><moon-perimeter-edit policy="list.policy" perimeter-type="list.typeOfObject"></moon-perimeter-edit></div></div><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.perimeter.action.title">List associated of Actions</h4></div><div class="panel-body"><div class="table-responsive"><table class="table table-striped"><thead><tr><th data-translate="moon.policy.perimeter.table.name">Name</th><th data-translate="moon.policy.perimeter.table.description">Description</th><th data-translate="moon.policy.perimeter.table.action.title"></th></tr></thead><moon-loader ng-if="list.loadingAct"></moon-loader><tbody ng-if="!list.loadingAct && list.getActions().length > 0"><tr ng-repeat="(key, value) in list.actions"><td ng-bind="value.name"></td><td ng-bind="value.description"></td><td><a href="" ng-if="!value.loader" ng-click="list.unMapAct(value)"><span class="glyphicon glyphicon-transfer"></span> <span class="control-label" data-translate="moon.policy.perimeter.table.action.unmap">Unmap</span></a><div ng-if="value.loader"><moon-loader></moon-loader></div></td></tr></tbody><tbody ng-if="!list.loadingAct && list.getActions().length === 0"><tr><td data-translate="moon.policy.perimeter.action.notFound">There is no Actions</td><td></td><td></td></tr></tbody></table></div></div></div><div ng-if="list.editMode" class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.perimeter.action.add.title">Add an Action Category</h4></div><div class="panel-body">.<moon-perimeter-edit policy="list.policy" perimeter-type="list.typeOfAction"></moon-perimeter-edit></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/edit/parameter/rules/rules-edit.tpl.html b/old/moon_gui/delivery/html/policy/edit/parameter/rules/rules-edit.tpl.html
new file mode 100644
index 00000000..46716d0d
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/edit/parameter/rules/rules-edit.tpl.html
@@ -0,0 +1 @@
+<div><div class="col-md-12 col-sm-12 col-xs-12"><form ng-if="!edit.fromList" class="form-horizontal" role="form" name="edit.form"><!-- Select Policy --><div class="form-group" ng-class="{'has-error': edit.form.policyList.$invalid && edit.form.policyList.$dirty}"><label for="policyList" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.policies">Policy List</label><div class="col-sm-6"><ui-select ng-model="edit.selectedPolicy" name="policyList" id="policyList" required><ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match><ui-select-choices repeat="aPolicy in edit.policyList"><div ng-value="aPolicy" ng-bind="aPolicy.name"></div></ui-select-choices></ui-select><div class="help-block" ng-show="edit.form.policyList.$dirty && edit.form.policyList.$invalid"><small class="error" ng-show="edit.form.policyList.$error.required" data-translate="moon.policy.rules.edit.action.add.check.policy.required">Policy is required</small></div></div></div><div ng-if="!edit.selectedPolicy.meta_rules_values"><div class="col-sm-6 col-sm-offset-3"><moon-loader></moon-loader></div></div><div ng-if="edit.selectedPolicy.meta_rules_values"><!-- Select Meta Rules --><div class="form-group" ng-class="{'has-error': edit.form.metaRulesList.$invalid && edit.form.metaRulesList.$dirty}"><label for="metaRulesList" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.metarules">MetaRules List</label><div class="col-sm-6"><ui-select ng-model="edit.selectedMetaRules" name="metaRulesList" id="metaRulesList" required><ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match><ui-select-choices repeat="aMetaRules in edit.selectedPolicy.meta_rules_values"><div ng-value="aMetaRules" ng-bind="aMetaRules.name"></div></ui-select-choices></ui-select><div class="help-block" ng-show="edit.form.metaRulesList.$dirty && edit.form.metaRulesList.$invalid"><small class="error" ng-show="edit.form.metaRulesList.$error.required" data-translate="moon.policy.rules.edit.action.add.check.metarules.required">A MetaRules is required</small></div></div><div><a href="" ng-if="edit.selectedMetaRules" ng-click="edit.showDetailselectedMetaRules = !edit.showDetailselectedMetaRules"><span ng-if="!edit.showDetailselectedMetaRules"><span data-translate="moon.policy.rules.edit.action.add.details.show">Show</span> <span class="glyphicon glyphicon-eye-open"></span> </span><span ng-if="edit.showDetailselectedMetaRules"><span data-translate="moon.policy.rules.edit.action.add.details.close">Close</span> <span class="glyphicon glyphicon-eye-close"></span></span></a></div></div><div class="form-group" ng-if="edit.showDetailselectedMetaRules && edit.selectedMetaRules"><moon-meta-data-list edit-mode="edit.editMode" meta-rule="edit.selectedMetaRules" short-display="true"></moon-meta-data-list></div><!-- Select Data --><div class="form-group" ng-if="edit.selectedMetaRules"><div class="col-md-4"><div ng-if="edit.selectedMetaRules.subject_categories.length > 0"><div class="row"><div ng-if="!edit.data.loadingSubjects"><label for="subjectsList" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.categories.subject" data-translate-values="{ number: edit.selectedMetaRules.subject_categories.length }">Select Subject(s)</label><div class="col-sm-7"><ui-select ng-model="edit.selectedSubject" name="subjectsList" id="subjectsList" required><ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match><ui-select-choices repeat="aSubject in edit.data.subjectsToBeSelected"><div ng-value="aSubject" ng-bind="aSubject.name"></div></ui-select-choices></ui-select><div class="help-block" ng-show="edit.form.subjectsList.$dirty && edit.form.subjectsList.$invalid || !edit.numberOfSelectedSubjectValid"><small class="error" ng-show="edit.form.subjectsList.$error.required || !edit.numberOfSelectedSubjectValid" data-translate="moon.policy.rules.edit.action.add.check.subject.required" data-translate-values="{ number: edit.selectedMetaRules.subject_categories.length }">Some subject are required</small></div></div><div class="col-sm-2 text-center"><a href="" ng-if="edit.selectedSubject && !edit.isNumberSelectedDataAtMaximum(edit.data.subjectCST)" ng-click="edit.addDataToRules(edit.data.subjectCST)"><span style="font-size:1.5em; line-height: 1.5em;" class="glyphicon glyphicon-plus-sign"></span></a></div></div><div ng-if="edit.data.loadingSubjects"><moon-loader></moon-loader></div></div><div class="row" ng-if="!edit.data.loadingSubjects"><div class="form-group"><label class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.selectedSubjects">Selected Subjcet(s)</label><div class="col-sm-6"><ul><li ng-repeat="(key, value) in edit.data.selectedSubjectsList"><span ng-bind="value.name"></span> <a href="" ng-click="edit.removeSelectedDataFromRules(value, edit.data.subjectCST)"><span style="font-size:1.5em; line-height: 1.5em" class="glyphicon glyphicon-remove"></span></a></li></ul></div></div></div></div><div ng-if="edit.selectedMetaRules.subject_categories.length === 0"></div></div><div class="col-md-4"><div ng-if="edit.selectedMetaRules.object_categories.length > 0"><div class="row"><div ng-if="!edit.data.loadingObjects"><label for="objectsList" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.categories.object" data-translate-values="{ number: edit.selectedMetaRules.object_categories.length }">Select Object(s)</label><div class="col-sm-7"><ui-select ng-model="edit.selectedObject" name="objectsList" id="objectsList" required><ui-select-match placeholder="(None)" ng-bind="$select.selected.value.name"></ui-select-match><ui-select-choices repeat="aObject in edit.data.objectsToBeSelected"><div ng-value="aObject" ng-bind="aObject.value.name"></div></ui-select-choices></ui-select><div class="help-block" ng-show="edit.form.objectsList.$dirty && edit.form.objectsList.$invalid || !edit.numberOfSelectedObjecttValid"><small class="error" ng-show="edit.form.objectsList.$error.required || !edit.numberOfSelectedObjecttValid" data-translate="moon.policy.rules.edit.action.add.check.object.required" data-translate-values="{ number: edit.selectedMetaRules.object_categories.length }">Some objects are required</small></div></div><div class="col-sm-2 text-center"><a href="" ng-if="edit.selectedObject && !edit.isNumberSelectedDataAtMaximum(edit.data.objectCST)" ng-click="edit.addDataToRules(edit.data.objectCST)"><span style="font-size:1.5em; line-height: 1.5em;" class="glyphicon glyphicon-plus-sign"></span></a></div></div><div ng-if="edit.data.loadingObjects"><moon-loader></moon-loader></div></div><div class="row" ng-if="!edit.data.loadingObjects"><div class="form-group"><label class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.selectedObjects">Selected Objcet(s)</label><div class="col-sm-6"><ul><li ng-repeat="(key, value) in edit.data.selectedObjectsList"><span ng-bind="value.value.name"></span> <a href="" ng-click="edit.removeSelectedDataFromRules(value, edit.data.objectCST)"><span style="font-size:1.5em; line-height: 1.5em" class="glyphicon glyphicon-remove"></span></a></li></ul></div></div></div></div><div ng-if="edit.selectedMetaRules.object_categories.length === 0"></div></div><div class="col-md-4"><div ng-if="edit.selectedMetaRules.action_categories.length > 0"><div class="row"><div ng-if="!edit.data.loadingActions"><label for="actionsList" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.categories.action" data-translate-values="{ number: edit.selectedMetaRules.action_categories.length }">Select Action(s)</label><div class="col-sm-7"><ui-select ng-model="edit.selectedAction" name="actionsList" id="actionsList" required><ui-select-match placeholder="(None)" ng-bind="$select.selected.value.name"></ui-select-match><ui-select-choices repeat="aAction in edit.data.actionsToBeSelected"><div ng-value="aAction" ng-bind="aAction.value.name"></div></ui-select-choices></ui-select><div class="help-block" ng-show="edit.form.actionsList.$dirty && edit.form.actionsList.$invalid || !edit.numberOfSelectedActionsValid"><small class="error" ng-show="edit.form.actionsList.$error.required || !edit.numberOfSelectedActionsValid" data-translate="moon.policy.rules.edit.action.add.check.action.required" data-translate-values="{ number: edit.selectedMetaRules.action_categories.length }">Some action are required</small></div></div><div class="col-sm-2 text-center"><a href="" ng-if="edit.selectedAction && !edit.isNumberSelectedDataAtMaximum(edit.data.actionCST)" ng-click="edit.addDataToRules(edit.data.actionCST)"><span style="font-size:1.5em; line-height: 1.5em;" class="glyphicon glyphicon-plus-sign"></span></a></div></div><div ng-if="edit.data.loadingActions"><moon-loader></moon-loader></div></div><div class="row" ng-if="!edit.data.loadingActions"><div class="form-group"><label class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.selectedActions">Selected Action(s)</label><div class="col-sm-6"><ul><li ng-repeat="(key, value) in edit.data.selectedActionsList"><span ng-bind="value.value.name"></span> <a href="" ng-click="edit.removeSelectedDataFromRules(value, edit.data.actionCST)"><span style="font-size:1.5em; line-height: 1.5em" class="glyphicon glyphicon-remove"></span></a></li></ul></div></div></div></div><div ng-if="edit.selectedMetaRules.action_categories.length === 0"></div></div></div><div class="form-group" ng-class="{'has-error': edit.form.instructions.$invalid && edit.form.instructions.$dirty || !edit.instructionsValid}"><label for="instructions" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.instructions">Instruction</label><div class="col-sm-6"><textarea id="instructions" name="instructions" class="form-control" ng-model="edit.rules.instructions" rows="6" required></textarea><div class="help-block" ng-show="edit.form.instructions.$dirty && edit.form.instructions.$invalid || !edit.instructionsValid "><small class="error" data-translate="moon.policy.rules.edit.action.add.check.instructions.required">An instructions is required</small></div></div></div><div class="form-group"><div class="pull-right"><a href="" ng-disabled="edit.loading" ng-click="edit.create()" class="btn btn-warning"><span class="glyphicon glyphicon-save"></span> <span data-translate="moon.policy.rules.edit.action.create">Create</span></a><moon-loader ng-if="edit.loading"></moon-loader></div></div></div></form></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/edit/parameter/rules/rules-list.tpl.html b/old/moon_gui/delivery/html/policy/edit/parameter/rules/rules-list.tpl.html
new file mode 100644
index 00000000..25cfe6f1
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/edit/parameter/rules/rules-list.tpl.html
@@ -0,0 +1 @@
+<div><div class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.rules.edit.title">List of associated Subjects</h4></div><div class="panel-body"><div class="table-responsive" data-role="table"><table class="table table-striped table-hover" ng-table="list.table"><thead><tr><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('description', 'asc'), 'sort-desc': list.table.isSortBy('description', 'desc') }" ng-click="list.table.sorting('description', list.table.isSortBy('description', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.policy.rules.list.table.metaRule">Meta Rule</div></th><th class="customTables sortable"><div data-translate="moon.policy.rules.list.table.rule">Rule</div></th><th class="customTables sortable"><div data-translate="moon.policy.rules.list.table.instructions">Instruction</div></th><th class="customTables sortable"><div data-translate="moon.policy.rules.list.table.action.title">Actions</div></th></tr></thead><moon-loader ng-if="list.loadingRules"></moon-loader><tbody ng-if="!list.loadingRules && !list.hasRules()"><tr><td colspan="4"><span data-translate="moon.policy.rules.list.table.notFound">There is no Rules</span></td></tr></tbody><tbody ng-if="!list.loadingRules && list.hasRules()"><tr ng-repeat="aRule in $data | filter:list.search.find | orderBy:sort:reverse"><td><span ng-if="!list.getMetaRuleFromRule(aRule)"><moon-loader ng-if="!list.getMetaRuleFromRule(aRule)"></moon-loader><em data-translate="moon.policy.rules.list.table.loading.metaRule">Loading </em></span><span ng-if="list.getMetaRuleFromRule(aRule)"><span ng-bind="aRule.meta_rule.name"></span></span></td><td><span ng-if="!list.getMetaRuleFromRule(aRule)"><moon-loader ng-if="!list.getMetaRuleFromRule(aRule)"></moon-loader><em data-translate="moon.policy.rules.list.table.loading.metaRule">Loading </em></span><span ng-if="list.getMetaRuleFromRule(aRule)" ng-repeat="(key, value) in aRule.rule"><span ng-if="!list.getCategoryFromRuleIndex(key, aRule)"><moon-loader ng-if="!list.getCategoryFromRuleIndex(key, aRule)"></moon-loader></span><span ng-if="list.getCategoryFromRuleIndex(key, aRule)"><span ng-if="aRule.rule_value[key].category.name" ng-bind="aRule.rule_value[key].category.name"></span> <span ng-if="aRule.rule_value[key].category.value.name" ng-bind="aRule.rule_value[key].category.value.name"></span> <span ng-if="key < aRule.rule.length-1">,</span></span></span></td><td><pre ng-bind="aRule.instructions | json "></pre></td><td><a href="" ng-if="!aRule.loader" ng-click="list.deleteRules(aRule)"><span class="glyphicon glyphicon-transfer"></span> <span class="control-label" data-translate="moon.policy.rules.list.table.action.delete">Delete</span></a><div ng-if="aRule.loader"><moon-loader></moon-loader></div></td></tr></tbody></table></div></div></div><div ng-if="list.editMode" class="panel panel-default"><div class="panel-heading"><h4 data-translate="moon.policy.rules.edit.action.add.title">Add a Rule</h4></div><div class="panel-body">.<moon-rules-edit policy="list.policy"></moon-rules-edit></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/edit/policy-edit-basic.tpl.html b/old/moon_gui/delivery/html/policy/edit/policy-edit-basic.tpl.html
new file mode 100644
index 00000000..23f760d4
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/edit/policy-edit-basic.tpl.html
@@ -0,0 +1 @@
+<div class="row"><form class="form-horizontal" role="form" name="edit.form"><div class="form-group"><label for="id" class="col-sm-3 control-label" data-translate="moon.policy.edit.basic.form.id">Id</label><div class="col-sm-6"><input name="id" id="id" disabled="disabled" class="form-control" type="text" data-ng-model="edit.policyToEdit.id" required></div></div><div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}"><label for="name" class="col-sm-3 control-label" data-translate="moon.policy.edit.basic.form.name">Name</label><div class="col-sm-6"><input name="name" id="name" class="form-control" type="text" data-ng-model="edit.policyToEdit.name" required><div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid"><small class="error" ng-show="edit.form.name.$error.required" data-translate="moon.policy.edit.basic.check.name.required">Name is required</small></div></div></div><div class="form-group" ng-class="{'has-error': edit.form.model.$dirty && (edit.form.model.$invalid || !edit.selectedModel)}"><label class="col-sm-3 control-label" data-translate="moon.policy.edit.basic.form.model">Models</label><div class="col-sm-6"><ui-select ng-model="edit.selectedModel" name="model" required><ui-select-match placeholder="(None)">{{$select.selected.name}}</ui-select-match><ui-select-choices repeat="model in edit.models"><div ng-value="model">{{model.name}}</div></ui-select-choices></ui-select><moon-loader ng-if="edit.modelsLoading"></moon-loader><div class="help-block" ng-show="edit.form.model.$dirty && (edit.form.model.$invalid || !edit.selectedModel)"><small class="error" ng-show="edit.form.model.$error.required" data-translate="moon.policy.edit.basic.check.model.required">Model is required</small></div></div></div><div class="form-group"><label for="description" class="col-sm-3 control-label" data-translate="moon.policy.edit.basic.form.description">Description</label><div class="col-sm-6"><textarea id="description" name="description" class="form-control" data-ng-model="edit.policyToEdit.description"></textarea></div></div><div class="form-group"><div class="col-sm-2 col-sm-offset-3"><a href="" ng-disabled="edit.loading" ng-click="edit.init()" class="btn btn-default"><span data-translate="moon.policy.edit.basic.action.init">Init</span></a></div><div class="col-sm-4 col-sm-offset-2"><a href="" ng-disabled="edit.loading" ng-click="edit.editPolicy()" class="btn btn-warning"><span class="glyphicon glyphicon-save"></span> <span data-translate="moon.policy.edit.basic.action.update">Update</span></a><moon-loader ng-if="edit.loading"></moon-loader></div></div></form></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/edit/policy-edit.tpl.html b/old/moon_gui/delivery/html/policy/edit/policy-edit.tpl.html
new file mode 100644
index 00000000..f32497a2
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/edit/policy-edit.tpl.html
@@ -0,0 +1,13 @@
+<div class="container"><div class="row"><h3 class="pull-left" data-translate="moon.policy.edit.title" data-translate-values="{ policyName: edit.policy.name }">Edit</h3></div><div class="panel panel-default"><div class="panel-heading"><span data-translate="moon.policy.edit.basic.title">Basic Information</span> <a href="" ng-click="edit.editBasic = !edit.editBasic"><span data-translate="moon.policy.edit.update">Update</span> <span class="glyphicon glyphicon-cog"></span></a></div><div class="panel-body"><div ng-if="edit.editBasic"><moon-policy-edit-basic policy="edit.policy"></moon-policy-edit-basic></div><div ng-if="!edit.editBasic"><dl class="dl-horizontal"><dt data-translate="moon.policy.edit.basic.form.id">Id</dt><dd ng-bind="edit.policy.id"></dd><dt data-translate="moon.policy.edit.basic.form.name">Name</dt><dd ng-bind="edit.policy.name"></dd><dt data-translate="moon.policy.edit.basic.form.genre">Genre</dt><dd ng-bind="edit.policy.genre"></dd><dt data-translate="moon.policy.edit.basic.form.model">Model</dt><dd><span ng-if="edit.loadingModel"><moon-loader ng-if="edit.loadingModel"></moon-loader></span><span ng-if="!edit.loadingModel"><span ng-bind="edit.policy.model.name"></span></span></dd><dt data-translate="moon.policy.edit.basic.form.description">Description</dt><dd ng-bind="edit.policy.description"></dd></dl></div></div></div><div class="panel panel-default"><div class="panel-heading"><span data-translate="moon.policy.edit.perimeter.title">Perimeters</span> <a href="" ng-click="edit.showPart('showPerimeters')"><span ng-if="!edit.showPerimeters"><span data-translate="moon.policy.edit.show.open">Show</span> <span class="glyphicon glyphicon-eye-open"></span> </span><span ng-if="edit.showPerimeters"><span data-translate="moon.policy.edit.show.close">Show</span> <span class="glyphicon glyphicon-eye-close"></span> </span></a><!--<a href="" ng-if="edit.showPerimeters">
+ <span data-translate="moon.policy.edit.update">Update</span>
+ <span class="glyphicon glyphicon-cog"></span>
+ </a>--></div><div class="panel-body" ng-if="edit.showPerimeters"><moon-perimeter-list edit-mode="true" policy="edit.policy"></moon-perimeter-list></div></div><div class="panel panel-default"><div class="panel-heading"><span data-translate="moon.policy.edit.data.title">Data</span> <a href="" ng-click="edit.showPart('showData')"><span ng-if="!edit.showData"><span data-translate="moon.policy.edit.show.open">Show</span> <span class="glyphicon glyphicon-eye-open"></span> </span><span ng-if="edit.showData"><span data-translate="moon.policy.edit.show.close">Show</span> <span class="glyphicon glyphicon-eye-close"></span> </span></a><!--<a href="" ng-if="edit.showData">
+ <span data-translate="moon.policy.edit.update">Update</span>
+ <span class="glyphicon glyphicon-cog"></span>
+ </a>--></div><div class="panel-body" ng-if="edit.showData"><!-- --><moon-data-list edit-mode="true" policy="edit.policy"></moon-data-list></div></div><div class="panel panel-default"><div class="panel-heading"><span data-translate="moon.policy.edit.rules.title">Rules</span> <a href="" ng-click="edit.showPart('showRules')"><span ng-if="!edit.showRules"><span data-translate="moon.policy.edit.show.open">Show</span> <span class="glyphicon glyphicon-eye-open"></span> </span><span ng-if="edit.showRules"><span data-showrules="moon.policy.edit.show.close">Close</span> <span class="glyphicon glyphicon-eye-close"></span> </span></a><!--<a href="" ng-if="edit.showRules">
+ <span data-translate="moon.policy.edit.update">Update</span>
+ <span class="glyphicon glyphicon-cog"></span>
+ </a>--></div><div class="panel-body" ng-if="edit.showRules"><moon-rules-list edit-mode="true" policy="edit.policy"></moon-rules-list></div></div><div class="panel panel-default"><div class="panel-heading"><span data-translate="moon.policy.edit.assignments.title">Assignments</span> <a href="" ng-click="edit.showPart('showAssignments')"><span ng-if="!edit.showAssignments"><span data-translate="moon.policy.edit.show.open">Show</span> <span class="glyphicon glyphicon-eye-open"></span> </span><span ng-if="edit.showAssignments"><span data-showrules="moon.policy.edit.show.close">Close</span> <span class="glyphicon glyphicon-eye-close"></span> </span></a><!--<a href="" ng-if="edit.showRules">
+ <span data-translate="moon.policy.edit.update">Update</span>
+ <span class="glyphicon glyphicon-cog"></span>
+ </a>--></div><div class="panel-body" ng-if="edit.showAssignments"><moon-assignments-list edit-mode="true" policy="edit.policy"></moon-assignments-list></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/policy-list.tpl.html b/old/moon_gui/delivery/html/policy/policy-list.tpl.html
new file mode 100644
index 00000000..2e8a981c
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/policy-list.tpl.html
@@ -0,0 +1 @@
+<div class="container"><div><form class="form-inline pull-right"><div class="form-group"><div><input id="searcPolicy" data-ng-model="list.search.query" type="text" class="form-control" placeholder="{{'moon.policy.list.search.placeholder' | translate}}"></div></div><div class="form-group"><div><button type="submit" class="btn btn-danger" data-ng-click="list.search.reset()" data-translate="moon.policy.list.search.reset">Reset</button></div></div></form></div><div>&nbsp;</div><div>&nbsp;</div><div>&nbsp;</div><div class="row"><div class="table-responsive" data-role="table"><table class="table table-striped table-hover" ng-table="list.table"><colgroup><col class="col-md-4"><col class="col-md-2"><col class="col-md-2"><col class="col-md-1"></colgroup><thead><tr><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('name', 'asc'), 'sort-desc': list.table.isSortBy('name', 'desc') }" ng-click="list.table.sorting('name', list.table.isSortBy('name', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.policy.list.table.name">Name</div></th><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('genre', 'asc'), 'sort-desc': list.table.isSortBy('genre', 'desc') }" ng-click="list.table.sorting('genre', list.table.isSortBy('genre', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.policy.list.table.genre">Genre</div></th><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('description', 'asc'), 'sort-desc': list.table.isSortBy('description', 'desc') }" ng-click="list.table.sorting('description', list.table.isSortBy('description', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.policy.list.table.description">Description</div></th><th class="customTables sortable"><div data-translate="moon.policy.list.action.title">Actions</div></th></tr></thead><tbody ng-if="!list.hasPolicies()"><tr><td colspan="12"><span data-translate="moon.policy.list.table.notFound">There is no policy</span></td></tr></tbody><tbody ng-if="list.hasPolicies()"><tr ng-repeat="policy in $data | filter:list.search.find | orderBy:sort:reverse"><td ng-bind="policy.name"></td><td ng-bind="policy.genre"></td><td ng-bind="policy.description"></td><td><div class="dropdown"><button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown"><span data-translate="moon.policy.list.action.title">Actions</span> <span class="caret"></span></button><ul class="dropdown-menu"><li><a href="" ui-sref="moon.policy.edit({id: policy.id})"><span class="glyphicon glyphicon-cog"></span> <span class="control-label" data-translate="moon.policy.list.action.edit">Edit</span></a></li><li class="divider"></li><li><a href="" ng-click="list.del.showModal(policy)"><span class="glyphicon glyphicon-trash"></span> <span class="control-label" data-translate="moon.policy.list.action.delete">Delete</span></a></li></ul></div></td></tr></tbody></table></div><div class="container"><div class="form-inline form-group"><a href="" ng-click="list.add.showModal()" class="btn btn-default"><span class="glyphicon glyphicon-plus-sign"></span> <span data-translate="moon.policy.list.action.add">Add Model</span></a></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/policy/policy-mapped-list.tpl.html b/old/moon_gui/delivery/html/policy/policy-mapped-list.tpl.html
new file mode 100644
index 00000000..2e18a1b5
--- /dev/null
+++ b/old/moon_gui/delivery/html/policy/policy-mapped-list.tpl.html
@@ -0,0 +1 @@
+<div class="container"><div class="row" ng-if="list.loadingPolicies"><moon-loader ng-if="list.loadingPolicies"></moon-loader></div><div class="row" ng-if="!list.loadingPolicies"><div class="table-responsive" data-role="table"><table class="table table-striped table-hover" ng-table="list.table"><colgroup><col class="col-md-4"><col class="col-md-2"><col class="col-md-2"><col class="col-md-1"></colgroup><thead><tr><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('name', 'asc'), 'sort-desc': list.table.isSortBy('name', 'desc') }" ng-click="list.table.sorting('name', list.table.isSortBy('name', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.policy.list.table.name">Name</div></th><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('genre', 'asc'), 'sort-desc': list.table.isSortBy('genre', 'desc') }" ng-click="list.table.sorting('genre', list.table.isSortBy('genre', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.policy.list.table.genre">Genre</div></th><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('description', 'asc'), 'sort-desc': list.table.isSortBy('description', 'desc') }" ng-click="list.table.sorting('description', list.table.isSortBy('description', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.policy.list.table.description">Description</div></th><th class="customTables sortable"><div data-translate="moon.policy.list.action.title">Actions</div></th></tr></thead><tbody ng-if="!list.hasPolicies()"><tr><td colspan="12"><span data-translate="moon.policy.list.table.notFound">There is no policy</span></td></tr></tbody><tbody ng-if="list.hasPolicies()"><tr ng-repeat="policy in $data | filter:list.search.find | orderBy:sort:reverse"><td ng-bind="policy.name"></td><td ng-bind="policy.genre"></td><td ng-bind="policy.description"></td><td><a href="" ng-click="list.unmap.showModal(policy)"><span class="glyphicon glyphicon-transfer"></span> <em data-translate="moon.policy.list.action.unmap">Unmap</em></a></td></tr></tbody></table></div><div class="container"><div class="form-inline form-group"><a href="" ng-click="list.map.showModal()" class="btn btn-default"><span class="glyphicon glyphicon-link"></span> <em data-translate="moon.policy.list.action.map">Map a Policy to PDP</em></a></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/project/action/mapping/project-map.tpl.html b/old/moon_gui/delivery/html/project/action/mapping/project-map.tpl.html
new file mode 100644
index 00000000..13cef98b
--- /dev/null
+++ b/old/moon_gui/delivery/html/project/action/mapping/project-map.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="ProjectMapController as map" class="modal" tabindex="-1" data-role="modalMappingProject"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.project.map.title" data-translate-values="{projectName: map.project.name}"></h4></div><div class="modal-body"><form class="form-horizontal" role="form" name="map.form"><div class="form-group" ng-class="{'has-error': map.form.pdp.$dirty && (map.form.pdp.$invalid || !map.selectedPDP)}"><label class="col-sm-3 control-label" data-translate="moon.project.map.form.pdp">PDP</label><div class="col-sm-6"><ui-select ng-model="map.selectedPDP" name="pdp" required><ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match><ui-select-choices repeat="pdp in map.pdps"><div ng-bind="pdp.name" ng-value="pdp"></div></ui-select-choices></ui-select><img ng-if="map.pdpsLoading" src="assets/img/ajax-loader.gif"><div class="help-block" ng-show="map.form.pdp.$dirty && (map.form.pdp.$invalid || !map.selectedPDP)"><small class="error" ng-show="map.form.pdp.$error.required" data-translate="moon.project.map.check.pdp.required">PDP is required</small></div></div></div></form></div><div class="modal-footer"><div class="btn-toolbar" style="float: right;"><a href="" ng-click="$hide()" class="btn btn-default"><span data-translate="moon.project.map.action.cancel">Cancel</span> </a><a href="" ng-disabled="map.mappingLoading" ng-click="map.map()" class="btn btn-warning"><span class="glyphicon glyphicon-link"></span> <span data-translate="moon.project.map.action.map">Map</span> </a><img ng-if="map.mappingLoading" src="assets/img/ajax-loader.gif"></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/project/action/mapping/project-unmap.tpl.html b/old/moon_gui/delivery/html/project/action/mapping/project-unmap.tpl.html
new file mode 100644
index 00000000..735011a9
--- /dev/null
+++ b/old/moon_gui/delivery/html/project/action/mapping/project-unmap.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="ProjectUnMapController as unmap" class="modal" tabindex="-1" data-role="modalUnmapProject"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.project.unmap.title"></h4></div><div class="modal-body"><span data-translate="moon.project.unmap.content" data-translate-values="{ projectName: unmap.project.name, pdpName: unmap.project.mapping.authz.pdp.name }"></span></div><div class="modal-footer"><div class="btn-toolbar" style="float: right;"><a href="" ng-click="$hide()" class="btn btn-default"><span data-translate="moon.project.unmap.action.cancel">Cancel</span> </a><a href="" ng-disabled="unmap.unMappingLoading" ng-click="unmap.unmap()" class="btn btn-warning"><span class="glyphicon glyphicon-transfer"></span> <span data-translate="moon.project.unmap.action.unmap">Unmap</span> </a><img ng-if="unmap.unMappingLoading" src="assets/img/ajax-loader.gif"></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/project/action/project-add.tpl.html b/old/moon_gui/delivery/html/project/action/project-add.tpl.html
new file mode 100644
index 00000000..4db03982
--- /dev/null
+++ b/old/moon_gui/delivery/html/project/action/project-add.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="ProjectAddController as add" class="modal" tabindex="-1" data-role="modalAddProject"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.project.add.title"></h4></div><div class="modal-body"><form class="form-horizontal" role="form" name="add.form"><div class="form-group" ng-class="{'has-error': add.form.name.$invalid && add.form.name.$dirty}"><label for="name" class="col-sm-3 control-label" data-translate="moon.project.add.form.name">Name</label><div class="col-sm-6"><input name="name" id="name" class="form-control" type="text" data-ng-model="add.project.project.name" required><div class="help-block" ng-show="add.form.name.$dirty && add.form.name.$invalid"><small class="error" ng-show="add.form.name.$error.required" data-translate="moon.project.add.check.name.required">Name is required</small></div></div></div><div class="form-group"><label for="description" class="col-sm-3 control-label" data-translate="moon.project.add.form.description">Description</label><div class="col-sm-6"><textarea id="description" name="description" class="form-control" data-ng-model="add.project.project.description"></textarea></div></div><div class="form-group"><label for="enabled" class="col-sm-3 control-label" data-translate="moon.project.add.form.enabled">Enabled</label><div class="col-sm-6"><div class="radio"><input type="checkbox" id="enabled" name="enabled" class="js-switch" data-ng-model="add.project.project.enabled" ui-switch></div></div></div><div class="form-group" ng-class="{'has-error': add.form.domain.$invalid && add.form.domain.$dirty}"><label for="domain" class="col-sm-3 control-label" data-translate="moon.project.add.form.domain">Domain</label><div class="col-sm-6"><input name="domain" id="domain" type="text" class="form-control" data-ng-model="add.project.project.domain" required><div class="help-block" ng-show="add.form.domain.$dirty && add.form.domain.$invalid"><small class="error" ng-show="add.form.domain.$error.required" data-translate="moon.project.add.check.domain.required">Domain is required</small></div></div></div></form></div><div class="modal-footer"><div class="btn-toolbar" style="float: right;"><a href="" ng-click="$hide()" class="btn btn-default"><span data-translate="moon.project.add.action.cancel">Cancel</span> </a><a href="" ng-disabled="add.loading" ng-click="add.create()" class="btn btn-warning"><span class="glyphicon glyphicon-save"></span> <span data-translate="moon.project.add.action.create">Create</span> </a><img ng-if="add.loading" src="assets/img/ajax-loader.gif"></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/project/action/project-delete.tpl.html b/old/moon_gui/delivery/html/project/action/project-delete.tpl.html
new file mode 100644
index 00000000..867a6674
--- /dev/null
+++ b/old/moon_gui/delivery/html/project/action/project-delete.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="ProjectDeleteController as del" class="modal" tabindex="-1" data-role="modalDeleteProject"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.project.remove.title"></h4></div><div class="modal-body"><p><span data-translate="moon.project.remove.content.query" data-translate-values="{ projectName: del.project.name }"></span></p><p ng-if="del.loadingPDP"><img src="assets/img/ajax-loader.gif"></p><div ng-if="!del.loadingPDP"><p ng-if="!del.isProjectMapped()"><span data-translate="moon.project.remove.content.isNotMapped">This Project is not map with any PDP</span></p><p ng-if="del.isProjectMapped()"><span data-translate="moon.project.remove.content.isMapped" data-translate-values="{ pdpName: del.project.pdp.name }"></span></p></div></div><div class="modal-footer"><div class="btn-toolbar" style="float: right;"><a href="" ng-click="$hide()" class="btn btn-default"><span data-translate="moon.project.remove.action.cancel">Cancel</span> </a><a href="" ng-disabled="del.loading || del.loadingPDP" ng-click="del.remove()" class="btn btn-warning"><span class="glyphicon glyphicon-trash"></span> <span data-translate="moon.project.remove.action.delete">Delete</span> </a><img ng-if="del.loading" src="assets/img/ajax-loader.gif"></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/project/action/project-view.tpl.html b/old/moon_gui/delivery/html/project/action/project-view.tpl.html
new file mode 100644
index 00000000..157eec80
--- /dev/null
+++ b/old/moon_gui/delivery/html/project/action/project-view.tpl.html
@@ -0,0 +1 @@
+<div ng-controller="ProjectViewController as view" class="modal" tabindex="-1" data-role="modalViewProject"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="modal-title" data-translate="moon.project.view.title" data-translate-values="{projectName: view.project.name}"></h4></div><div class="modal-body"><dl class="dl-horizontal"><dt>Id</dt><dd ng-bind="view.project.id"></dd><dt>Name</dt><dd ng-bind="view.project.name"></dd><dt>Is_domain</dt><dd ng-bind="view.project.is_domain"></dd><dt>Link</dt><dd ng-bind="view.project.links.self"></dd><dt>enabled</dt><dd ng-bind="view.project.enabled"></dd><dt>Parent id</dt><dd ng-bind="view.project.parent_id"></dd><dt>Domain id</dt><dd ng-bind="view.project.domain_id"></dd><dt>Description</dt><dd ng-bind="view.project.description"></dd></dl></div><!--<div class="modal-body">--><!----><!--&lt;!&ndash; objects &ndash;&gt;--><!----><!--<div class="row">--><!--<div class="col-md-12">--><!--<h1 class="pull-left" data-translate="moon.project.view.object.title">Objects</h1>--><!--</div>--><!--</div>--><!----><!--<div class="row top05">--><!--<div class="col-md-3"><label data-translate="moon.project.view.object.name">Name</label></div>--><!--<div class="col-md-7"><label data-translate="moon.project.view.object.description">Description</label></div>--><!--<div class="col-md-2"><label data-translate="moon.project.view.object.enabled">Enabled</label></div>--><!--</div>--><!----><!--<div class="row" ng-if="view.objectsLoading">--><!--<div class="col-md-12"><img src="assets/img/ajax-loader.gif" /> <em data-translate="moon.project.view.object.loading">Loading Objects</em></div>--><!--</div>--><!----><!--<div class="row" ng-if="!view.objectsLoading && !view.hasObjects()">--><!--<div class="col-md-12" data-translate="moon.project.view.object.notFound">Objects not found</div>--><!--</div>--><!----><!--<div class="row" ng-if="!view.objectsLoading && view.hasObjects()" ng-repeat="object in view.objects">--><!--<div class="col-md-3">{{object.name}}</div> --><!--<div class="col-md-7">{{object.description}}</div>--><!--<div class="col-md-2">--><!--<span ng-if="object.enabled" class="glyphicon glyphicon-ok"></span>--><!--</div>--><!--</div>--><!----><!--&lt;!&ndash; subjects &ndash;&gt;--><!----><!--<div class="row top10">--><!--<div class="col-md-12">--><!--<h1 class="pull-left" data-translate="moon.project.view.subject.title">Subjects</h1>--><!--</div>--><!--</div>--><!----><!--<div class="row top05">--><!--<div class="col-md-3"><label data-translate="moon.project.view.subject.name">Name</label></div>--><!--<div class="col-md-3"><label data-translate="moon.project.view.subject.domain">Domain</label></div>--><!--<div class="col-md-4"><label data-translate="moon.project.view.subject.mail">Mail</label></div>--><!--<div class="col-md-2"><label data-translate="moon.project.view.subject.enabled">Enabled</label></div>--><!--</div>--><!----><!--<div class="row">--><!--<div class="col-md-3">--><!--<ui-select ng-model="view.selectedSubject" on-select="view.resolveRoles($item); view.resolveGroups($item)">--><!--<ui-select-match placeholder="(None)">{{$select.selected.name}}</ui-select-match>--><!--<ui-select-choices repeat="subject in view.subjects">--><!--<div ng-value="subject">{{subject.name}}</div>--><!--</ui-select-choices>--><!--</ui-select>--><!--<img ng-if="view.subjectsLoading" src="assets/img/ajax-loader.gif" />--><!--</div> --><!--<div class="col-md-3">{{view.selectedSubject.domain}}</div>--><!--<div class="col-md-4">{{view.selectedSubject.mail}}</div>--><!--<div class="col-md-2">--><!--<div ng-if="view.selectedSubject != null">--><!--<span ng-if="view.selectedSubject.enabled" class="glyphicon glyphicon-ok"></span>--><!--</div>--><!--</div>--><!--</div>--><!----><!--&lt;!&ndash; roles &ndash;&gt;--><!----><!--<div ng-if="view.hasSelectedSubject()">--><!----><!--<div class="row top10">--><!--<div class="col-md-12">--><!--<h1 class="pull-left" data-translate="moon.project.view.role.title">Roles</h1>--><!--</div>--><!--</div>--><!----><!--<div class="row top05">--><!----><!--<div class="col-md-3"><label data-translate="moon.project.view.role.value">Value</label></div>--><!--<div class="col-md-5"><label data-translate="moon.project.view.role.description">Description</label></div>--><!--<div class="col-md-2"><label data-translate="moon.project.view.role.assigned">Assigned</label></div>--><!--<div class="col-md-2"><label data-translate="moon.project.view.role.enabled">Enabled</label></div>--><!----><!--</div>--><!----><!--<div class="row" ng-if="view.rolesLoading">--><!--<div class="col-md-12"><img src="assets/img/ajax-loader.gif" /> <em data-translate="moon.project.view.role.loading">Loading Roles</em></div>--><!--</div>--><!----><!--<div class="row" ng-if="!view.rolesLoading && !view.hasRoles()">--><!--<div class="col-md-12" data-translate="moon.project.view.role.notFound">Roles not found</div>--><!--</div>--><!----><!--<div class="row" ng-if="!view.rolesLoading && view.hasRoles()" ng-repeat="role in view.roles">--><!----><!--<div class="col-md-3" ng-bind="role.value"></div>--><!--<div class="col-md-5" ng-bind="role.description"></div>--><!--<div class="col-md-2">--><!--<span ng-if="view.isRoleAssigned(role)" class="glyphicon glyphicon-ok"></span>--><!--</div>--><!--<div class="col-md-2">--><!--<span ng-if="role.enabled" class="glyphicon glyphicon-ok"></span>--><!--</div>--><!----><!--</div>--><!----><!--</div>--><!----><!--&lt;!&ndash; groups &ndash;&gt;--><!----><!--<div ng-if="view.hasSelectedSubject()">--><!----><!--<div class="row top10">--><!--<div class="col-md-12">--><!--<h1 class="pull-left" data-translate="moon.project.view.group.title">Groups</h1>--><!--</div>--><!--</div>--><!----><!--<div class="row top05">--><!----><!--<div class="col-md-3"><label data-translate="moon.project.view.group.value">Value</label></div>--><!--<div class="col-md-5"><label data-translate="moon.project.view.group.description">Description</label></div>--><!--<div class="col-md-2"><label data-translate="moon.project.view.group.assigned">Assigned</label></div>--><!--<div class="col-md-2"><label data-translate="moon.project.view.group.enabled">Enabled</label></div>--><!----><!--</div>--><!----><!--<div class="row" ng-if="view.groupsLoading">--><!--<div class="col-md-12"><img src="assets/img/ajax-loader.gif" /> <em data-translate="moon.project.view.group.loading">Loading Groups</em></div>--><!--</div>--><!----><!--<div class="row" ng-if="!view.groupsLoading && !view.hasGroups()">--><!--<div class="col-md-12" data-translate="moon.project.view.group.notFound">Groups not found</div>--><!--</div>--><!----><!--<div class="row" ng-if="!view.groupsLoading && view.hasGroups()" ng-repeat="group in view.groups">--><!----><!--<div class="col-md-3">{{group.value}}</div>--><!--<div class="col-md-5">{{group.description}}</div>--><!--<div class="col-md-2">--><!--<span ng-if="view.isGroupAssigned(group)" class="glyphicon glyphicon-ok"></span>--><!--</div>--><!--<div class="col-md-2">--><!--<span ng-if="group.enabled" class="glyphicon glyphicon-ok"></span>--><!--</div>--><!----><!--</div>--><!----><!--</div>--><!----><!--</div>--><!----><div class="modal-footer top10"><div class="btn-toolbar" style="float: right;"><button ng-click="$hide()" class="btn btn-default" data-translate="moon.project.view.action.close">Close</button></div></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/html/project/project-list.tpl.html b/old/moon_gui/delivery/html/project/project-list.tpl.html
new file mode 100644
index 00000000..d0ab8886
--- /dev/null
+++ b/old/moon_gui/delivery/html/project/project-list.tpl.html
@@ -0,0 +1 @@
+<div class="container"><div><form class="form-inline pull-right"><div class="form-group"><div><input id="searchProject" data-ng-model="list.search.query" type="text" class="form-control" placeholder="{{'moon.project.list.search.placeholder' | translate}}"></div></div><div class="form-group"><div><button type="submit" class="btn btn-danger" data-ng-click="list.search.reset()" data-translate="moon.project.list.search.reset">Reset</button></div></div></form></div><div>&nbsp;</div><div>&nbsp;</div><div>&nbsp;</div><div class="row"><div class="table-responsive" data-role="table"><table class="table table-striped table-hover" ng-table="list.table"><colgroup><col class="col-md-2"><col class="col-md-2"><col class="col-md-1"><col class="col-md-1"><col class="col-md-2"><col class="col-md-1"></colgroup><thead><tr><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('name', 'asc'), 'sort-desc': list.table.isSortBy('name', 'desc') }" ng-click="list.table.sorting('name', list.table.isSortBy('name', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.project.list.table.name">Name</div></th><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('domain', 'asc'), 'sort-desc': list.table.isSortBy('domain', 'desc') }" ng-click="list.table.sorting('domain', list.table.isSortBy('domain', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.project.list.table.domain">Domain</div></th><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('enabled', 'asc'), 'sort-desc': list.table.isSortBy('enabled', 'desc') }" ng-click="list.table.sorting('enabled', list.table.isSortBy('enabled', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.project.list.table.enabled">Enabled</div></th><th class="customTables sortable" ng-class="{ 'sort-asc': list.table.isSortBy('description', 'asc'), 'sort-desc': list.table.isSortBy('description', 'desc') }" ng-click="list.table.sorting('description', list.table.isSortBy('description', 'asc') ? 'desc' : 'asc')"><div data-translate="moon.project.list.table.description">Description</div></th><th class="customTables"><div data-translate="moon.project.list.table.mapping">Mapping</div></th><th class="customTables"><div data-translate="moon.project.list.action.title">Actions</div></th></tr></thead><tbody ng-if="!list.hasProjects()"><tr><td colspan="2"><span data-translate="moon.project.list.table.notFound">There is no Projects</span></td></tr></tbody><tbody ng-if="list.hasProjects()"><tr ng-repeat="aProject in $data | filter:list.search.find | orderBy:sort:reverse"><td ng-bind="aProject.name"></td><td ng-bind="aProject.domain_id"></td><td><span ng-if="aProject.enabled" class="glyphicon glyphicon-ok"></span></td><td ng-bind="aProject.description"></td><td><div ng-if="list.loadingPDPs"><img src="assets/img/ajax-loader.gif"> <em data-translate="moon.project.list.table.loading.pdp">Loading PDP</em></div><div ng-if="!list.loadingPDPs"><a href="" ng-if="!list.isProjectMapped(aProject)" ng-click="list.map.showModal(aProject)"><span class="glyphicon glyphicon-link"></span> <em data-translate="moon.project.list.action.map">Map to a PDP</em></a><div ng-if="list.isProjectMapped(aProject)"><span ng-bind="list.getMappedPDPName(aProject)"></span> (<a href="" ng-click="list.unmap.showModal(aProject)"> <span class="glyphicon glyphicon-transfer"></span> <em data-translate="moon.project.list.action.unmap">Unmap to a PDP</em> </a>)</div></div></td><td><div class="dropdown"><button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown"><span data-translate="moon.project.list.action.title">Actions</span> <span class="caret"></span></button><ul class="dropdown-menu"><li><a href="" ng-click="list.view.showModal(aProject)"><span class="glyphicon glyphicon-eye-open"></span> <span class="control-label" data-translate="moon.project.list.action.detail">Detail</span></a></li><li><a href="" ng-click="list.del.showModal(aProject)"><span class="glyphicon glyphicon-trash"></span> <span class="control-label" data-translate="moon.project.list.action.delete">Delete</span></a></li></ul></div></td></tr></tbody></table></div><div class="container"><div class="form-inline form-group"><a href="" ng-click="list.add.showModal()" class="btn btn-default"><span class="glyphicon glyphicon-plus-sign"></span> <span data-translate="moon.project.list.action.add">Add Project</span></a></div></div></div></div> \ No newline at end of file
diff --git a/old/moon_gui/delivery/index.html b/old/moon_gui/delivery/index.html
new file mode 100644
index 00000000..0631ab7a
--- /dev/null
+++ b/old/moon_gui/delivery/index.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="moon">
+<head>
+ <meta charset="UTF-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <title>Moon</title>
+ <link href="assets/img/favicon.ico" rel="shortcut icon"/>
+
+ <!-- inject:css -->
+ <link rel="stylesheet" href="assets/css/main.css">
+ <!-- endinject -->
+</head>
+<body>
+
+<div class="container">
+ <div ng-controller="HeaderController" ng-include="'html/common/header/header.tpl.html'"></div>
+</div>
+
+<div class="container">
+ <div ui-view></div>
+</div>
+
+<div class="container">
+ <div ng-controller="FooterController" ng-include="'html/common/footer/footer.tpl.html'"></div>
+</div>
+
+<!-- inject:js -->
+<script src="js/modules.js"></script>
+<script src="js/app.js"></script>
+<!-- endinject -->
+
+</body>
+</html> \ No newline at end of file
diff --git a/old/moon_gui/delivery/js/app.js b/old/moon_gui/delivery/js/app.js
new file mode 100644
index 00000000..96bb1f6a
--- /dev/null
+++ b/old/moon_gui/delivery/js/app.js
@@ -0,0 +1,4 @@
+!function(){"use strict";function e(e,s,d,u){s.useStaticFilesLoader({prefix:"assets/i18n/",suffix:".json"}).preferredLanguage("en").useCookieStorage(),u.theme="selectize",e.when("","/model"),e.when("/","/model"),e.otherwise("/404"),t(d),o(d),n(d),c(d),i(d),r(d),a(d),l(d)}function t(e){return e.state("moon",{abstract:!0,template:"<div ui-view></div>"}).state("moon.404",{url:"/404",templateUrl:"html/common/404/404.tpl.html"}),e}function o(e){return e.state("moon.dashboard",{url:"/dashboard",templateUrl:"html/dashboard/dashboard.tpl.html"}),e}function n(e){return e.state("moon.auth",{abstract:!0,template:"<div ui-view></div>"}).state("moon.auth.login",{url:"/login",templateUrl:"html/authentication/authentication.tpl.html",controller:"AuthenticationController",controllerAs:"auth"}),e}function i(e){return e.state("moon.model",{abstract:!0,template:"<div ui-view></div>"}).state("moon.model.list",{url:"/model",templateUrl:"html/model/model-list.tpl.html",controller:"ModelListController",controllerAs:"list",resolve:{models:["modelService",function(e){return e.findAll()}]}}).state("moon.model.edit",{url:"/model/:id",templateUrl:"html/model/edit/model-edit.tpl.html",controller:"ModelEditController",controllerAs:"edit",resolve:{model:["$stateParams","modelService",function(e,t){return t.findOneWithMetaRules(e.id)}]}}),e}function c(e){return e.state("moon.project",{abstract:!0,template:"<div ui-view></div>"}).state("moon.project.list",{url:"/project",templateUrl:"html/project/project-list.tpl.html",controller:"ProjectListController",controllerAs:"list",resolve:{projects:["projectService",function(e){return e.findAll()}]}}),e}function r(e){return e.state("moon.pdp",{abstract:!0,template:"<div ui-view></div>"}).state("moon.pdp.list",{url:"/pdp",templateUrl:"html/pdp/pdp-list.tpl.html",controller:"PDPListController",controllerAs:"list",resolve:{pdps:["pdpService",function(e){return e.findAll()}]}}).state("moon.pdp.edit",{url:"/pdp/:id",templateUrl:"html/pdp/edit/pdp-edit.tpl.html",controller:"PDPEditController",controllerAs:"edit",resolve:{pdp:["$stateParams","pdpService",function(e,t){return t.findOne(e.id)}]}}),e}function a(e){return e.state("moon.policy",{abstract:!0,template:"<div ui-view></div>"}).state("moon.policy.list",{url:"/policy",templateUrl:"html/policy/policy-list.tpl.html",controller:"PolicyListController",controllerAs:"list",resolve:{policies:["policyService",function(e){return e.findAll()}]}}).state("moon.policy.edit",{url:"/policy/:id",templateUrl:"html/policy/edit/policy-edit.tpl.html",controller:"PolicyEditController",controllerAs:"edit",resolve:{policy:["$stateParams","policyService",function(e,t){return t.findOne(e.id)}]}}),e}function l(e){return e.state("moon.logs",{url:"/logs",templateUrl:"html/logs/logs.tpl.html",controller:"LogsController",controllerAs:"logs"}),e}function s(e,t,o,n,i,c,r){function a(e,t,o){-1===["/login"].indexOf(r.path())&&!c.currentUser&&r.path("/login")}function l(){e.connected=i.IsConnected(),e.transitionModal.$promise.then(e.transitionModal.show)}function s(){e.transitionModal.hide()}function d(t,i,c,r,a,l){var s=u(t,i,c,r,a,l);o("moon.global.error",{stacktrace:s}).then(function(e){n.alertError(e)}),e.transitionModal.hide()}function u(e,t,o,n,i,c){var r={};return r.status=c.status,r.message=c.statusText,r.state=t,r.params=o,r}e.connected=i.IsConnected(),e.transitionModal=t({scope:e,template:"html/common/waiting/waiting.tpl.html",backdrop:"static",show:!1}),e.$on("$stateChangeStart",l),e.$on("$stateChangeSuccess",s),e.$on("$stateChangeError",d),e.$on("$locationChangeStart",a),i.IsConnected()&&i.SetTokenHeader(i.GetTokenHeader())}angular.module("moon",["ngResource","ngRoute","ui.router","ngMessages","ui.bootstrap","ngTable","ngCookies","ngStorage","pascalprecht.translate","ngAnimate","mgcrea.ngStrap","NgSwitchery","ui.select","toaster"]).config(e).run(s);e.$inject=["$urlRouterProvider","$translateProvider","$stateProvider","uiSelectConfig"],s.$inject=["$rootScope","$modal","$translate","alertService","authenticationService","$sessionStorage","$location"]}(),function(){"use strict";angular.module("moon").constant("DEFAULT_CST",{DOMAIN:{DEFAULT:"Default"}}).constant("SECURITY_PIPELINE_CST",{TYPE:{POLICY:"policy"}}).constant("META_DATA_CST",{TYPE:{SUBJECT:"SUBJECT",OBJECT:"OBJECT",ACTION:"ACTION"}}).constant("PERIMETER_CST",{TYPE:{SUBJECT:"SUBJECT",OBJECT:"OBJECT",ACTION:"ACTION"}}).constant("DATA_CST",{TYPE:{SUBJECT:"SUBJECT",OBJECT:"OBJECT",ACTION:"ACTION"}}).constant("ASSIGNMENTS_CST",{TYPE:{SUBJECT:"SUBJECT",OBJECT:"OBJECT",ACTION:"ACTION"}}).constant("REST_URI",{PDP:"http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/pdp/",MODELS:"http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/models/",METARULES:"http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/meta_rules/",RULES:"http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/rules/",POLICIES:"http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/policies/",METADATA:{subject:"http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/subject_categories/",object:"http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/object_categories/",action:"http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/action_categories/"},PERIMETERS:{subject:"http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/subjects/",object:"http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/objects/",action:"http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/actions/"},KEYSTONE:"http://{{KEYSTONE_HOST}}:{{KEYSTONE_PORT}}/v3/"})}(),function(){"use strict";function e(e,t,o,n,i){function c(){l.loading=!0,e.Login(l.credentials,r,a)}function r(){t("moon.login.success").then(function(e){o.alertSuccess(e),n.go("moon.dashboard"),l.loading=!1})}function a(e){t("moon.login.error",{errorCode:e.status}).then(function(e){o.alertError(e),l.loading=!1})}var l=this;l.login=c,l.loading=!1,l.credentials={username:"",password:""},function(){i.connected&&n.go("moon.dashboard")}()}angular.module("moon").controller("AuthenticationController",e),e.$inject=["authenticationService","$translate","alertService","$state","$rootScope"]}(),function(){"use strict";function e(){}angular.module("moon").controller("LogsController",e)}(),function(){"use strict";function e(e,t,o,n,i,c){function r(){return S.table=new n({page:1,count:10,sorting:{name:"asc"}},{total:function(){return S.getModels().length},getData:function(e,t){var o=t.sorting()?i("orderBy")(S.getModels(),t.orderBy()):S.getModels();e.resolve(o.slice((t.page()-1)*t.count(),t.page()*t.count()))},$scope:{$data:{}}}),S.table}function a(){return S.models?S.models:[]}function l(){return S.getModels().length>0}function s(){S.search.query=""}function d(e){return-1!==e.name.indexOf(S.search.query)||-1!==e.description.indexOf(S.search.query)}function u(){S.add.modal.$promise.then(S.add.modal.show)}function m(e){S.models.push(e)}function p(){S.table.total(S.models.length),S.table.reload()}function f(e,t){m(t),p(),S.add.modal.hide()}function h(e){S.add.modal.hide()}function g(e){S.view.modal.$scope.model=e,S.view.modal.$promise.then(S.view.modal.show)}function y(e){S.del.modal.$scope.model=e,S.del.modal.$promise.then(S.del.modal.show)}function v(e){S.models=_.chain(S.models).reject({id:e.id}).value()}function b(e,t){S.deleteModel(t),S.refreshModels(),S.del.modal.hide()}function j(e,t){S.del.modal.hide()}var S=this;S.models=o,S.table={},S.search={query:"",find:d,reset:s},S.getModels=a,S.hasModels=l,S.deleteModel=v,S.refreshModels=p,S.add={modal:c({template:"html/model/action/model-add.tpl.html",show:!1}),showModal:u},S.view={modal:c({template:"html/model/action/model-view.tpl.html",show:!1}),showModal:g},S.del={modal:c({template:"html/model/action/model-delete.tpl.html",show:!1}),showModal:y},function(){r()}();var T={"event:modelCreatedSuccess":t.$on("event:modelCreatedSuccess",f),"event:modelCreatedError":t.$on("event:modelCreatedError",h),"event:modelDeletedSuccess":t.$on("event:modelDeletedSuccess",b),"event:modelDeletedError":t.$on("event:modelDeletedError",j)};for(var E in T)e.$on("$destroy",T[E])}angular.module("moon").controller("ModelListController",e),e.$inject=["$scope","$rootScope","models","NgTableParams","$filter","$modal"]}(),function(){"use strict";function e(e,t,o,n,i,c,r){function a(){return A.pdps?A.pdps:[]}function l(){return A.getPDPs().length>0}function s(e){A.pdps.push(e)}function d(e){A.pdps=_.chain(A.pdps).reject({id:e.id}).value()}function u(){A.table.total(A.pdps.length),A.table.reload()}function m(e){return _(_.values(A.getPDPs())).each(function(t){t.id===e.id&&(t=_.clone(e))}),A.pdps}function p(e){return e.id}function f(e){return e.tenant.name}function h(e){return e?e.name:""}function g(e){return!_.isNull(e.keystone_project_id)}function y(e){return _.has(e,"project")?e.project:(_.has(e,"callPdpInProgress")||(e.callPdpInProgress=!0,r.findOne(e.keystone_project_id,function(t){return e.callPdpInProgress=!1,e.project=t,e.project})),!1)}function v(){return A.table=new i({page:1,count:10},{total:function(){return A.getPDPs().length},getData:function(e,t){var n=t.sorting()?o("orderBy")(A.getPDPs(),t.orderBy()):A.getPDPs();e.resolve(n.slice((t.page()-1)*t.count(),t.page()*t.count()))},$scope:{$data:{}}}),A.table}function b(e){return-1!==A.getPDPName(e).indexOf(A.search.query)||-1!==A.getSecPipelineFromPdp(e).indexOf(A.search.query)}function j(e){return e.security_pipeline?e.security_pipeline:[]}function S(){A.search.query=""}function T(){A.add.modal.$promise.then(A.add.modal.show)}function E(e,t){A.addPDP(t),A.refreshPDPs(),A.add.modal.hide()}function P(e,t){A.add.modal.hide()}function $(e){A.del.modal.$scope.pdp=e,A.del.modal.$promise.then(A.del.modal.show)}function C(e,t){A.deletePDP(t),A.refreshPDPs(),A.del.modal.hide()}function O(){A.del.modal.hide()}var A=this;A.pdps=c,A.mappings=[],A.getPDPs=a,A.hasPDPs=l,A.getPDPName=h,A.isMapped=g,A.getProjectFromPDP=y,A.getidFromPDP=p,A.table={},A.addPDP=s,A.deletePDP=d,A.refreshPDPs=u,A.updatePDPs=m,A.getMappedProjectName=f,A.getSecPipelineFromPdp=j,A.search={query:"",find:b,reset:S},A.add={modal:n({template:"html/pdp/action/pdp-add.tpl.html",show:!1}),showModal:T},A.del={modal:n({template:"html/pdp/action/pdp-delete.tpl.html",show:!1}),showModal:$},function(){v()}();var R={"event:pdpCreatedSuccess":e.$on("event:pdpCreatedSuccess",E),"event:pdpCreatedError":e.$on("event:pdpCreatedError",P),"event:pdpDeletedSuccess":e.$on("event:pdpDeletedSuccess",C),"event:pdpDeletedError":e.$on("event:pdpDeletedError",O)};_.each(R,function(e){t.$on("$destroy",R[e])})}angular.module("moon").controller("PDPListController",e),e.$inject=["$rootScope","$scope","$filter","$modal","NgTableParams","pdps","projectService"]}(),function(){"use strict";function e(e,t,o,n,i,c){function r(){return j.policies?j.policies:[]}function a(){return j.getPolicies().length>0}function l(){return j.table=new o({page:1,count:10,sorting:{name:"asc",genre:"asc"}},{total:function(){return j.getPolicies().length},getData:function(e,t){var o=t.sorting()?n("orderBy")(j.getPolicies(),t.orderBy()):j.getPolicies();e.resolve(o.slice((t.page()-1)*t.count(),t.page()*t.count()))},$scope:{$data:{}}}),j.table}function s(e){return-1!==e.name.indexOf(j.search.query)||-1!==e.genre.indexOf(j.search.query)||-1!==e.description.indexOf(j.search.query)}function d(){j.search.query=""}function u(){j.add.modal.$promise.then(j.add.modal.show)}function m(e,t){j.addPolicy(t),j.refreshPolicies(),j.add.modal.hide()}function p(e,t){j.add.modal.hide()}function f(e){j.policies.push(e)}function h(){j.table.total(j.policies.length),j.table.reload()}function g(e){j.del.modal.$scope.policy=e,j.del.modal.$promise.then(j.del.modal.show)}function y(e){j.policies=_.chain(j.policies).reject({id:e.id}).value()}function v(e,t){j.deletePolicy(t),j.refreshPolicies(),j.del.modal.hide()}function b(e,t){j.del.modal.hide()}var j=this;j.policies=t,j.getPolicies=r,j.hasPolicies=a,j.addPolicy=f,j.refreshPolicies=h,j.deletePolicy=y,j.table={},j.search={query:"",find:s,reset:d},j.add={modal:i({template:"html/policy/action/policy-add.tpl.html",show:!1}),showModal:u},j.del={modal:i({template:"html/policy/action/policy-delete.tpl.html",show:!1}),showModal:g},function(){l()}();var S={"event:policyCreatedSuccess":c.$on("event:policyCreatedSuccess",m),"event:policyCreatedError":c.$on("event:policyCreatedError",p),"event:policyDeletedSuccess":c.$on("event:policyDeletedSuccess",v),"event:policyDeletedError":c.$on("event:policyDeletedError",b)};for(var T in S)e.$on("$destroy",S[T])}angular.module("moon").controller("PolicyListController",e),e.$inject=["$scope","policies","NgTableParams","$filter","$modal","$rootScope"]}(),function(){"use strict";function e(){return{templateUrl:"html/policy/policy-mapped-list.tpl.html",bindToController:!0,controller:t,controllerAs:"list",scope:{pdp:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c){function r(e){_.isUndefined(y.pdp.security_pipeline)||(y.policiesId=y.pdp.security_pipeline,c.findSomeWithCallback(y.policiesId,function(t){y.policies=t,y.loadingPolicies=!1,e?d():a()}))}function a(){return y.table=new o({page:1,count:10},{total:function(){return y.getPolicies().length},getData:function(e,t){var o=t.sorting()?i("orderBy")(y.getPolicies(),t.orderBy()):y.getPolicies();e.resolve(o.slice((t.page()-1)*t.count(),t.page()*t.count()))},$scope:{$data:{}}}),y.table}function l(){return y.policies?y.policies:[]}function s(){return y.getPolicies().length>0}function d(){y.table.total(y.getPolicies().length),y.table.reload()}function u(){y.map.modal.$scope.pdp=y.pdp,y.map.modal.$promise.then(y.map.modal.show)}function m(e){y.unmap.modal.$scope.pdp=y.pdp,y.unmap.modal.$scope.policy=e,y.unmap.modal.$promise.then(y.unmap.modal.show)}function p(e,t){y.pdp=t,r(!0),y.map.modal.hide()}function f(e){y.map.modal.hide()}function h(e,t){y.pdp=t,r(!0),y.unmap.modal.hide()}function g(e){y.unmap.modal.hide()}var y=this;y.table={},y.pdp=e.list.pdp,y.getPolicies=l,y.hasPolicies=s,y.refreshPolicies=d,y.loadingPolicies=!0,y.policies=[],function(){r(!1)}(),y.map={modal:n({template:"html/policy/action/mapping/policy-map.tpl.html",show:!1}),showModal:u},y.unmap={modal:n({template:"html/policy/action/mapping/policy-unmap.tpl.html",show:!1}),showModal:m};var v={"event:policyMapToPdpSuccess":t.$on("event:policyMapToPdpSuccess",p),"event:policyMapToPdpError":t.$on("event:policyMapToPdpError",f),"event:policyUnMappedToPdpSuccess":t.$on("event:policyUnMappedToPdpSuccess",h),"event:policyUnMappedToPdpError":t.$on("event:policyUnMappedToPdpError",g)};for(var b in v)e.$on("$destroy",v[b])}angular.module("moon").directive("moonPolicyMappedList",e),e.$inject=[],angular.module("moon").controller("moonPolicyMappedListController",t),t.$inject=["$scope","$rootScope","NgTableParams","$modal","$filter","policyService"]}(),function(){"use strict";function e(e,t,o,n,i,c,r){function a(){k.loadingPDPs=!0,h(),c.findAllWithCallBack(function(e){k.pdps=e,c.mapPdpsToProjects(k.projects,k.pdps),k.loadingPDPs=!1})}function l(){return k.projects?k.projects:[]}function s(){return k.getProjects().length>0}function d(e){return _.has(e,"pdp")}function u(e){return e.pdp}function m(e){k.projects.push(e)}function p(e){k.projects=_.chain(k.projects).reject({id:e.id}).value()}function f(){k.table.total(k.projects.length),k.table.reload()}function h(){return k.table=new i({page:1,count:10,sorting:{name:"asc"}},{total:function(){return k.getProjects().length},getData:function(e,t){var n=t.sorting()?o("orderBy")(k.getProjects(),t.orderBy()):k.getProjects();e.resolve(n.slice((t.page()-1)*t.count(),t.page()*t.count()))},$scope:{$data:{}}}),k.table}function g(e){return _.has(e,"pdp")?e.pdp.name:"error"}function y(e){return-1!==e.name.indexOf(k.search.query)||-1!==e.description.indexOf(k.search.query)}function v(){k.search.query=""}function b(){k.add.modal.$promise.then(k.add.modal.show)}function j(e,t){k.addProject(t),k.refreshProjects(),k.add.modal.hide()}function S(e,t){k.add.modal.hide()}function T(e){k.del.modal.$scope.project=e,k.del.modal.$promise.then(k.del.modal.show)}function E(e,t){k.deleteProject(t),k.refreshProjects(),k.del.modal.hide()}function P(e,t){k.del.modal.hide()}function $(e){k.map.modal.$scope.project=e,k.map.modal.$promise.then(k.map.modal.show)}function C(e,t){a(),k.map.modal.hide()}function O(e,t){k.map.modal.hide()}function A(e){k.unmap.modal.$scope.project=e,k.unmap.modal.$promise.then(k.unmap.modal.show)}function R(e,t){var o=_.findIndex(k.projects,function(e){return t.id===e.id});if(-1===o)return k.unmap.modal.hide(),!1;k.projects[o]=t,k.refreshProjects(),k.unmap.modal.hide()}function M(e,t){k.unmap.modal.hide()}function D(e){k.view.modal.$scope.project=e,k.view.modal.$promise.then(k.view.modal.show)}var k=this;k.projects=r,k.pdps=[],k.getProjects=l,k.hasProjects=s,k.isProjectMapped=d,k.table={},k.addProject=m,k.deleteProject=p,k.refreshProjects=f,k.getMappedPDPName=g,k.getPdpFromProject=u,k.search={query:"",find:y,reset:v},k.add={modal:n({template:"html/project/action/project-add.tpl.html",show:!1}),showModal:b},k.del={modal:n({template:"html/project/action/project-delete.tpl.html",show:!1}),showModal:T},k.map={modal:n({template:"html/project/action/mapping/project-map.tpl.html",show:!1}),showModal:$},k.unmap={modal:n({template:"html/project/action/mapping/project-unmap.tpl.html",show:!1}),showModal:A},k.view={modal:n({template:"html/project/action/project-view.tpl.html",show:!1}),showModal:D},a();var L={"event:projectCreatedSuccess":e.$on("event:projectCreatedSuccess",j),"event:projectCreatedError":e.$on("event:projectCreatedError",S),"event:projectDeletedSuccess":e.$on("event:projectDeletedSuccess",E),"event:projectDeletedError":e.$on("event:projectDeletedError",P),"event:projectMappedSuccess":e.$on("event:projectMappedSuccess",C),"event:projectMappedError":e.$on("event:projectMappedError",O),"event:projectUnmappedSuccess":e.$on("event:projectUnmappedSuccess",R),"event:projectUnmappedError":e.$on("event:projectUnmappedError",M)};for(var N in L)t.$on("$destroy",L[N])}angular.module("moon").controller("ProjectListController",e),e.$inject=["$rootScope","$scope","$filter","$modal","ngTableParams","pdpService","projects"]}(),function(){"use strict";function e(e,t){function o(){n.browsersModal.$promise.then(n.browsersModal.show)}var n=this;n.version=null,n.browsersModal=null,n.showBrowsersCompliance=o,function(){n.browsersModal=e({template:"html/common/compatibility/compatibility.tpl.html",show:!1}),n.browsersModal}(),function(){var e=n;t.version.get().$promise.then(function(t){return e.version=t.version?t.version:"SNAPSHOT",e.version})}()}angular.module("moon").controller("FooterController",e),e.$inject=["$modal","versionService"]}(),function(){"use strict";function e(e,t,o,n){function i(t,o){o.preventDefault(),e.use(t),e.preferredLanguage(t),r.currentLanguage=t}function c(){o.Logout(),e("moon.logout.success").then(function(e){n.alertSuccess(e)})}var r=this;r.isProjectTabActive=t.isProjectTabActive,r.isPDPTabActive=t.isPDPTabActive,r.isLogsTabActive=t.isLogsTabActive,r.isPolicyTabActive=t.isPolicyTabActive,r.isModelTabActive=t.isModelTabActive,r.changeLocale=i,r.logout=c,r.currentLanguage=e.use(),r.getUser=o.GetUser}angular.module("moon").controller("HeaderController",e),e.$inject=["$translate","menuService","authenticationService","alertService"]}(),function(){"use strict";function e(){return{templateUrl:"html/common/loader/loader.tpl.html",restrict:"E"}}angular.module("moon").directive("moonLoader",e),e.$inject=[]}(),function(){"use strict";function e(e,t,o,n,i,c){function r(){function r(t){var i=c.transformOne(t,"models");n("moon.model.add.success",{modelName:i.name}).then(function(e){o.alertSuccess(e)}),a.loading=!1,e.$emit("event:modelCreatedSuccess",i)}function l(t){n("moon.model.add.error",{modelName:a.model.name}).then(function(e){o.alertError(e)}),a.loading=!1,e.$emit("event:modelCreatedError",a.project)}i.isInvalid(a.form)?i.checkFieldsValidity(a.form):(a.loading=!0,t.data.create({},a.model,r,l))}var a=this;a.form={},a.loading=!1,a.model={name:null,description:null,meta_rules:[]},a.create=r}angular.module("moon").controller("ModelAddController",e),e.$inject=["$scope","modelService","alertService","$translate","formService","utilService"]}(),function(){"use strict";function e(e,t,o,n){function i(){function i(n){t("moon.model.remove.success",{modelName:c.model.name}).then(function(e){o.alertSuccess(e)}),c.loading=!1,e.$emit("event:modelDeletedSuccess",c.model)}function r(n){t("moon.model.remove.error",{modelName:c.model.name,errorCode:n.data.error.code,message:n.data.error.message}).then(function(e){o.alertError(e)}),c.loading=!1,e.$emit("event:modelDeletedError",c.model)}c.loading=!0,n.delete(c.model,i,r)}var c=this;c.model=e.model,c.loading=!1,c.remove=i}angular.module("moon").controller("ModelDeleteController",e),e.$inject=["$scope","$translate","alertService","modelService"]}(),function(){"use strict";function e(e,t){function o(){t.findSomeWithMetaData(n.model.meta_rules).then(function(e){n.meta_rules_values=e,n.model.meta_rules_values=e})}var n=this;n.model=e.model,n.meta_rules_values=!1,function(){n.model.meta_rules.length>0?o():n.meta_rules_values=[]}()}angular.module("moon").controller("ModelViewController",e),e.$inject=["$scope","metaRuleService"]}(),function(){"use strict";function e(e,t,o,n){function i(e,t){c.model=t,n.findSomeWithCallback(t.meta_rules,function(e){c.model.meta_rules_values=e})}var c=this;c.model=o,c.editBasic=!1,c.editMetaRules=!0;var r={"event:modelUpdatedSuccess":t.$on("event:modelUpdatedSuccess",i),"event:updateModelFromMetaRuleAddSuccess":t.$on("event:updateModelFromMetaRuleAddSuccess",i)};for(var a in r)e.$on("$destroy",r[a])}angular.module("moon").controller("ModelEditController",e),e.$inject=["$scope","$rootScope","model","metaRuleService"]}(),function(){"use strict";function e(){return{templateUrl:"html/model/edit/model-edit-basic.tpl.html",bindToController:!0,controller:t,controllerAs:"edit",scope:{model:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c){function r(){function r(t){var o=c.transformOne(t,"models");i("moon.model.edit.basic.success",{modelName:o.name}).then(function(e){n.alertSuccess(e)}),l.loading=!1,e.$emit("event:modelUpdatedSuccess",o)}function a(e){i("moon.model.edit.basic.error",{modelName:l.model.name}).then(function(e){n.alertError(e)}),l.loading=!1}o.isInvalid(l.form)?o.checkFieldsValidity(l.form):(l.loading=!0,t.update(l.modelToEdit,r,a))}function a(){l.modelToEdit=angular.copy(l.model)}var l=this;l.editModel=r,l.init=a,l.form={},function(){l.model=e.edit.model,l.modelToEdit=angular.copy(l.model)}()}angular.module("moon").directive("moonModelEditBasic",e),e.$inject=[],angular.module("moon").controller("moonModelEditBasicController",t),t.$inject=["$scope","modelService","formService","alertService","$translate","utilService"]}(),function(){"use strict";function e(e,t,o,n,i,c,r){function a(c){function a(n){t("moon.pdp.add.success",{pdpName:c.name}).then(function(e){o.alertSuccess(e)});var i=r.transformOne(n,"pdps");l.loading=!1,e.$emit("event:pdpCreatedSuccess",i)}function s(n){t("moon.pdp.add.error",{pdpName:c.name}).then(function(e){o.alertError(e)}),l.loading=!1,e.$emit("event:pdpCreatedError")}n.isInvalid(l.form)?n.checkFieldsValidity(l.form):(l.loading=!0,i.data.pdp.create({},{name:l.pdp.name,description:l.pdp.description,security_pipeline:[l.selectedPolicy.id],keystone_project_id:null},a,s))}var l=this;l.form={},l.pdp={},l.policies=[],l.selectedPolicy=null,l.loading=!1,l.loadingPolicies=!0,l.create=a,function(){c.findAllWithCallback(function(e){l.policies=e,l.loadingPolicies=!1})}()}angular.module("moon").controller("PDPAddController",e),e.$inject=["$scope","$translate","alertService","formService","pdpService","policyService","utilService"]}(),function(){"use strict";function e(e,t,o,n){function i(){function i(n){t("moon.pdp.remove.success",{pdpName:c.pdp.name}).then(function(e){o.alertSuccess(e)}),c.loading=!1,e.$emit("event:pdpDeletedSuccess",c.pdp)}function r(n){t("moon.pdp.remove.error",{pdpName:c.pdp.name}).then(function(e){o.alertError(e)}),c.loading=!1,e.$emit("event:pdpDeletedError",c.pdp)}c.loading=!0,n.data.pdp.remove({pdp_id:c.pdp.id},i,r)}var c=this;c.pdp=e.pdp,c.loading=!1,c.remove=i}angular.module("moon").controller("PDPDeleteController",e),e.$inject=["$scope","$translate","alertService","pdpService"]}(),function(){"use strict";function e(e,t,o,n){function i(e,t){c.pdp=t}var c=this;c.pdp=o,c.editBasic=!1;var r={"event:pdpUpdatedSuccess":t.$on("event:pdpUpdatedSuccess",i)};for(var a in r)e.$on("$destroy",r[a])}angular.module("moon").controller("PDPEditController",e),e.$inject=["$scope","$rootScope","pdp","$stateParams"]}(),function(){"use strict";function e(){return{templateUrl:"html/pdp/edit/pdp-edit-basic.tpl.html",bindToController:!0,controller:t,controllerAs:"edit",scope:{pdp:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c){function r(){function r(t){var o=c.transformOne(t,"pdps");i("moon.pdp.edit.basic.success",{pdpName:o.name}).then(function(e){n.alertSuccess(e)}),l.loading=!1,e.$emit("event:pdpUpdatedSuccess",o)}function a(e){i("moon.pdp.edit.basic.error",{pdpName:l.pdp.name}).then(function(e){n.alertError(e)}),l.loading=!1}o.isInvalid(l.form)?o.checkFieldsValidity(l.form):(l.loading=!0,t.update(l.pdpToEdit,r,a))}function a(){l.pdpToEdit=angular.copy(l.pdp)}var l=this;l.editPdp=r,l.init=a,l.form={},function(){l.pdp=e.edit.pdp,l.pdpToEdit=angular.copy(l.pdp)}()}angular.module("moon").directive("moonPDPEditBasic",e),e.$inject=[],angular.module("moon").controller("moonPDPEditBasicController",t),t.$inject=["$scope","pdpService","formService","alertService","$translate","utilService"]}(),function(){"use strict";function e(e,t,o,n,i,c,r){function a(){r.findAllWithCallBack(l)}function l(e){d.models=e,d.modelsLoading=!1}function s(){function r(n){var i=c.transformOne(n,"policies");t("moon.policy.add.success",{policyName:i.name}).then(function(e){o.alertSuccess(e)}),d.loading=!1,e.$emit("event:policyCreatedSuccess",i)}function a(n){t("moon.policy.add.error",{policyName:d.model.name}).then(function(e){o.alertError(e)}),d.loading=!1,e.$emit("event:policyCreatedError",d.project)}n.isInvalid(d.form)?n.checkFieldsValidity(d.form):(d.loading=!0,i.data.policy.create({},{name:d.policy.name,description:d.policy.description,genre:[d.selectedGenre],model_id:d.selectedModel.id},r,a))}var d=this;d.loading=!1,d.form={},d.policy={name:null,genre:null,description:null,model_id:null},d.genres=["admin","authz"],d.models=[],d.modelsLoading=!0,d.create=s,function(){a()}()}angular.module("moon").controller("PolicyAddController",e),e.$inject=["$scope","$translate","alertService","formService","policyService","utilService","modelService"]}(),function(){"use strict";function e(e,t,o,n){function i(){function i(n){t("moon.policy.remove.success",{policyName:c.policy.name}).then(function(e){o.alertSuccess(e)}),c.loading=!1,e.$emit("event:policyDeletedSuccess",c.policy)}function r(n){t("moon.policy.remove.error",{policyName:c.policy.name,errorCode:n.data.error.code,message:n.data.error.message}).then(function(e){o.alertError(e)}),c.loading=!1,e.$emit("event:policyDeletedError",c.policy)}c.loading=!0,n.delete(c.policy,i,r)}var c=this;c.policy=e.policy,c.loading=!1,c.remove=i}angular.module("moon").controller("PolicyDeleteController",e),e.$inject=["$scope","$translate","alertService","policyService"]}(),function(){"use strict";function e(e,t,o,n){function i(e){var t=a[e];a.showPerimeters=!1,a.showData=!1,a.showRules=!1,a.showAssignments=!1,a[e]=!t}function c(){a.loadingModel=!0,n.findOneWithCallback(a.policy.model_id,function(e){a.loadingModel=!1,a.policy.model=e})}function r(e,t){a.policy=t,c()}var a=this;a.policy=o,a.editBasic=!1,a.showPerimeters=!1,a.showData=!1,a.showRules=!1,a.showAssignments=!1,a.showPart=i,function(){c()}();var l={"event:policyUpdatedSuccess":t.$on("event:policyUpdatedSuccess",r)};for(var s in l)e.$on("$destroy",l[s])}angular.module("moon").controller("PolicyEditController",e),e.$inject=["$scope","$rootScope","policy","modelService"]}(),function(){"use strict";function e(){return{templateUrl:"html/policy/edit/policy-edit-basic.tpl.html",bindToController:!0,controller:t,controllerAs:"edit",scope:{policy:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c,r){function a(){r.findAllWithCallBack(l)}function l(e){u.models=e,_.each(e,function(e){e.id===u.policy.model_id&&(u.selectedModel=e)}),u.modelsLoading=!1}function s(){function r(t){var o=c.transformOne(t,"policies");i("moon.policy.edit.basic.success",{policyName:o.name}).then(function(e){n.alertSuccess(e)}),u.loading=!1,e.$emit("event:policyUpdatedSuccess",o)}function a(e){i("moon.policy.edit.basic.error",{policyName:u.policy.name}).then(function(e){n.alertError(e)}),u.loading=!1}o.isInvalid(u.form)?o.checkFieldsValidity(u.form):(u.loading=!0,delete u.policyToEdit.model,u.policyToEdit.model_id=u.selectedModel.id,t.update(u.policyToEdit,r,a))}function d(){u.policyToEdit=angular.copy(u.policy)}var u=this;u.editPolicy=s,u.init=d,u.form={},u.modelsLoading=!0,function(){u.policy=e.edit.policy,u.policyToEdit=angular.copy(u.policy),console.log(u.policyToEdit),a()}()}angular.module("moon").directive("moonPolicyEditBasic",e),e.$inject=[],angular.module("moon").controller("moonPolicyEditBasicController",t),t.$inject=["$scope","policyService","formService","alertService","$translate","utilService","modelService"]}(),function(){"use strict";function e(e,t,o,n,i,c){function r(){function c(n){var i=n.project;t("moon.project.add.success",{projectName:i.name}).then(function(e){o.alertSuccess(e)}),a.loading=!1,e.$emit("event:projectCreatedSuccess",i)}function r(n){t("moon.project.add.error",{projectName:a.project.project.name}).then(function(e){o.alertError(e)}),a.loading=!1,e.$emit("event:projectCreatedError",a.project)}n.isInvalid(a.form)?n.checkFieldsValidity(a.form):(a.loading=!0,i.data.projects.create({},a.project,c,r))}var a=this;a.form={},a.loading=!1,a.project={project:{name:null,description:null,enabled:!0,domain:c.DOMAIN.DEFAULT}},a.create=r}angular.module("moon").controller("ProjectAddController",e),e.$inject=["$scope","$translate","alertService","formService","projectService","DEFAULT_CST"]}(),function(){"use strict";function e(e,t,o,n,i){function c(){i.findAllWithCallBack(function(e){d.pdps=e,i.mapPdpsToProject(d.project,d.pdps),d.loadingPDP=!1})}function r(){return _.has(d.project,"pdp")}function a(){d.loading=!0,r()?l(s):s()}function l(n){function c(n){t("moon.project.remove.mapping.remove.error",{pdpName:r}).then(function(e){o.alertError(e)}),d.loading=!1,e.$emit("event:projectDeletedError",d.project)}var r=unmap.project.pdp.name;i.unMap(unmap.project,n,c)}function s(){function i(n){t("moon.project.remove.success",{projectName:d.project.name}).then(function(e){o.alertSuccess(e)}),d.loading=!1,e.$emit("event:projectDeletedSuccess",d.project)}function c(n){t("moon.project.remove.error",{projectName:d.project.name,errorCode:n.data.error.code,message:n.data.error.message}).then(function(e){o.alertError(e)}),d.loading=!1,e.$emit("event:projectDeletedError",d.project)}n.data.projects.remove({project_id:d.project.id},i,c)}var d=this;d.project=e.project,d.loading=!1,d.loadingPDP=!0,d.remove=a,d.isProjectMapped=r,d.pdps=[],function(){c()}()}angular.module("moon").controller("ProjectDeleteController",e),e.$inject=["$scope","$translate","alertService","projectService","pdpService"]}(),function(){"use strict";function e(e,t,o,n,i){this.project=t.project}angular.module("moon").controller("ProjectViewController",e),e.$inject=["$q","$scope","$translate","alertService","projectService"]}(),function(){"use strict";function e(e){function t(t){e.pop("error",null,t,5e3)}function o(t){e.pop("success",null,t,5e3)}function n(t){e.pop("note",null,t,5e3)}var i={};return i.alertError=t,i.alertSuccess=o,i.alertInfo=n,i}angular.module("moon").factory("alertService",e),e.$inject=["toaster"]}(),function(){"use strict";function e(){function e(){var e,t=navigator.userAgent,o=t.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i)||[];return/trident/i.test(o[1])?(e=/\brv[ :]+(\d+)/g.exec(t)||[],
+"IE "+(e[1]||"")):"Chrome"===o[1]&&null!=(e=t.match(/\bOPR\/(\d+)/))?"Opera "+e[1]:(o=o[2]?[o[1],o[2]]:[navigator.appName,navigator.appVersion,"-?"],null!=(e=t.match(/version\/(\d+)/i))&&o.splice(1,1,e[1]),o.join(" "))}var t={};return t.sayWho=e,t}angular.module("moon").factory("browserService",e)}(),function(){"use strict";function e(){function e(e){return e.$invalid}function t(e){var t=_.keys(e.$error);_(t).each(function(t){var o=_.values(e.$error[t]);_(o).each(function(e){e.$dirty=!0,e.$setValidity(t,!1)})})}var o={};return o.isInvalid=e,o.checkFieldsValidity=t,o}angular.module("moon").factory("formService",e)}(),function(){"use strict";function e(e){function t(){return e.includes("moon.project")}function o(){return e.includes("moon.pdp")}function n(){return e.includes("moon.policy")}function i(){return e.includes("moon.logs")}function c(){return e.includes("moon.model")}var r={};return r.isProjectTabActive=t,r.isPDPTabActive=o,r.isPolicyTabActive=n,r.isLogsTabActive=i,r.isModelTabActive=c,r}angular.module("moon").factory("menuService",e),e.$inject=["$state"]}(),function(){"use strict";function e(e,t){function o(o){switch(o){case e.TYPE.POLICY:default:return t.findAll()}}var n={};return n.findAll=o,n}angular.module("moon").factory("securityPipelineService",e),e.$inject=["SECURITY_PIPELINE_CST","policyService"]}(),function(){"use strict";function e(){return{transform:function(e,t){var o=[];return _.each(e[t],function(e,t){e.id=t,o.push(e)}),o},transformOne:function(e,t){var o=[];return _.each(e[t],function(e,t){e.id=t,o.push(e)}),o[0]}}}angular.module("moon").factory("utilService",e),e.$inject=[]}(),function(){"use strict";function e(e){return{version:e("version.json",{},{get:{method:"GET",isArray:!1}})}}angular.module("moon").factory("versionService",e),e.$inject=["$resource"]}(),function(){"use strict";function e(e,t,o,n){function i(e,t){_.each(e,function(e){return c(e,t)})}function c(e,t){if(_.isNull(e.keystone_project_id))return!1;var o=_.findIndex(t,function(t){return e.id===t.keystone_project_id});return-1!==o&&(e.pdp=t[o],!0)}return{data:{pdp:t(o.PDP+":pdp_id",{},{query:{method:"GET",isArray:!1},get:{method:"GET",isArray:!1},create:{method:"POST"},update:{method:"PATCH"},remove:{method:"DELETE"}})},findAll:function(){return this.data.pdp.query().$promise.then(function(e){return n.transform(e,"pdps")})},findAllWithCallBack:function(e){return this.data.pdp.query().$promise.then(function(t){e(n.transform(t,"pdps"))})},findOne:function(e){return this.data.pdp.get({pdp_id:e}).$promise.then(function(e){return n.transformOne(e,"pdps")})},unMap:function(e,t,o){e.keystone_project_id=null,_.has(e,"project")&&delete e.project,this.data.pdp.update({pdp_id:e.id},e,t,o)},map:function(e,t,o,n){e.keystone_project_id=t,this.data.pdp.update({pdp_id:e.id},e,o,n)},update:function(e,t,o){this.data.pdp.update({pdp_id:e.id},e,t,o)},mapPdpsToProjects:i,mapPdpsToProject:c}}angular.module("moon").factory("pdpService",e),e.$inject=["$q","$resource","REST_URI","utilService"]}(),function(){"use strict";function e(e,t,o,n,i){function c(){return _.has(o,"currentUser")}function r(){delete o.currentUser,n.defaults.headers.common["X-Auth-Token"]="",i.path("/")}function a(){return o.currentUser}function l(){return o.currentUser.connectionToken}function s(e){n.defaults.headers.common["X-Auth-Token"]=e}return{data:e(t.KEYSTONE+"auth/tokens",{},{login:{method:"POST",transformResponse:function(e,t){var o={};return o.data=angular.fromJson(e),o.headers=t(),o}},logout:{method:"DELETE"}}),Login:function(e,t,n){var i={auth:{identity:{methods:["password"],password:{user:{name:e.username,domain:{name:"Default"},password:e.password}}},scope:{project:{name:"admin",domain:{name:"Default"}}}}};this.data.login({},i,function(e){o.currentUser=e.data,o.currentUser.connectionToken=e.headers["x-subject-token"],s(e.headers["x-subject-token"]),t()},n)},IsConnected:c,SetTokenHeader:s,GetTokenHeader:l,GetUser:a,Logout:r}}angular.module("moon").factory("authenticationService",e),e.$inject=["$resource","REST_URI","$sessionStorage","$http","$location"]}(),function(){"use strict";function e(e){return{data:{image:e("./pip/nova/images",{},{query:{method:"GET",isArray:!1}}),flavor:e("./pip/nova/flavors",{},{query:{method:"GET",isArray:!1}})}}}angular.module("moon").factory("novaService",e),e.$inject=["$resource"]}(),function(){"use strict";function e(e,t){return{data:{projects:e(t.KEYSTONE+"projects/:project_id",{},{query:{method:"GET",isArray:!1},get:{method:"GET",isArray:!1},create:{method:"POST"},remove:{method:"DELETE"}})},findOne:function(e,t){return this.data.projects.get({project_id:e}).$promise.then(function(e){t(e.project)})},findAll:function(){return this.data.projects.query().$promise.then(function(e){var t=[];return _.each(e.projects,function(e){t.push(e)}),t})}}}angular.module("moon").factory("projectService",e),e.$inject=["$resource","REST_URI"]}(),function(){"use strict";function e(){return{templateUrl:"html/model/edit/metadata/metadata-edit.tpl.html",bindToController:!0,controller:t,controllerAs:"edit",scope:{metaDataType:"=",metaRule:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c,r,a){function l(){function e(e){g.list=e}switch(g.metaDataType){case o.TYPE.SUBJECT:t.subject.findAllWithCallback(e);break;case o.TYPE.OBJECT:t.object.findAllWithCallback(e);break;case o.TYPE.ACTION:t.action.findAllWithCallback(e);break;default:g.list=[]}}function s(){function t(t){i("moon.model.metarules.update.success",{metaRuleName:l.name}).then(function(e){n.alertSuccess(e)}),l=a.transformOne(t,"meta_rules"),angular.copy(l,g.metaRule),e.$emit("event:updateMetaRuleFromMetaDataAddSuccess",g.metaRule),f()}function c(e){i("moon.model.metarules.update.error",{metaRuleName:l.name,reason:e.message}).then(function(e){n.alertError(e)}),f()}if(g.selectedMetaData){var l=angular.copy(g.metaRule);switch(g.metaDataType){case o.TYPE.SUBJECT:l.subject_categories.push(g.selectedMetaData.id);break;case o.TYPE.OBJECT:l.object_categories.push(g.selectedMetaData.id);break;case o.TYPE.ACTION:l.action_categories.push(g.selectedMetaData.id)}r.update(l,t,c)}}function d(){function e(e){var t={};switch(g.metaDataType){case o.TYPE.SUBJECT:t=a.transformOne(e,"subject_categories");break;case o.TYPE.OBJECT:t=a.transformOne(e,"object_categories");break;case o.TYPE.ACTION:t=a.transformOne(e,"action_categories")}i("moon.model.metadata.edit.create.success",{name:t.name}).then(function(e){n.alertSuccess(e)}),f(),g.list.push(t),h()}function r(e){i("moon.model.metadata.edit.create.error",{name:l.name}).then(function(e){n.alertError(e)}),f()}if(c.isInvalid(g.form))c.checkFieldsValidity(g.form);else{p();var l=angular.copy(g.metaData);switch(g.metaDataType){case o.TYPE.SUBJECT:t.subject.add(l,e,r);break;case o.TYPE.OBJECT:t.object.add(l,e,r);break;case o.TYPE.ACTION:t.action.add(l,e,r)}}}function u(){function c(t){i("moon.model.metadata.edit.delete.success",{name:s.name}).then(function(e){n.alertSuccess(e)}),r.findOneWithMetaData(g.metaRule.id).then(function(t){angular.copy(t,g.metaRule),m(),l(),f(),e.$emit("event:deleteMetaDataFromMetaDataAddSuccess",g.metaRule)})}function a(e){i("moon.model.metadata.edit.delete.error",{name:s.name}).then(function(e){n.alertError(e)}),f()}if(g.selectedMetaData){p();var s=angular.copy(g.selectedMetaData);switch(g.metaDataType){case o.TYPE.SUBJECT:t.subject.delete(s,c,a);break;case o.TYPE.OBJECT:t.object.delete(s,c,a);break;case o.TYPE.ACTION:t.action.delete(s,c,a)}}}function m(){delete g.selectedMetaData}function p(){g.loading=!0}function f(){g.loading=!1}function h(){g.fromList=!0}var g=this;g.metaDataType=e.edit.metaDataType,g.metaRule=e.edit.metaRule,g.fromList=!0,g.form={},g.metaData={name:null,description:null},g.list=[],g.create=d,g.addToMetaRule=s,g.deleteMetaData=u,l()}angular.module("moon").directive("moonMetaDataEdit",e),e.$inject=[],angular.module("moon").controller("moonMetaDataEditController",t),t.$inject=["$scope","metaDataService","META_DATA_CST","alertService","$translate","formService","metaRuleService","utilService"]}(),function(){"use strict";function e(){return{templateUrl:"html/model/edit/metadata/metadata-list.tpl.html",bindToController:!0,controller:t,controllerAs:"list",scope:{metaRule:"=",editMode:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c,r,a){function l(){s(),d(),u()}function s(){j.loadingCatSub=!0,o.subject.findSomeWithCallback(j.metaRule.subject_categories,function(e){j.catSub=e,j.loadingCatSub=!1})}function d(){j.loadingCatObj=!0,o.object.findSomeWithCallback(j.metaRule.object_categories,function(e){j.catObj=e,j.loadingCatObj=!1})}function u(){j.loadingCatAct=!0,o.action.findSomeWithCallback(j.metaRule.action_categories,function(e){j.catAct=e,j.loadingCatAct=!1})}function m(e){function t(t){n("moon.model.metarules.update.success",{metaRuleName:j.metaRule.name}).then(function(e){i.alertSuccess(e)}),r=c.findMetaDataFromMetaRule(a.transformOne(t,"meta_rules")),angular.copy(r,j.metaRule),l(),e.loader=!1}function o(t){n("moon.model.metarules.update.error",{metaRuleName:j.metaRule.name,reason:t.message}).then(function(e){i.alertError(e)}),e.loader=!1}e.loader=!0;var r=angular.copy(j.metaRule);r.subject_categories=_.without(r.subject_categories,e.id),c.update(r,t,o)}function p(e){function t(t){n("moon.model.metarules.update.success",{metaRuleName:j.metaRule.name}).then(function(e){i.alertSuccess(e)}),r=c.findMetaDataFromMetaRule(a.transformOne(t,"meta_rules")),angular.copy(r,j.metaRule),l(),e.loader=!1}function o(t){n("moon.model.metarules.update.error",{metaRuleName:j.metaRule.name,reason:t.message}).then(function(e){i.alertError(e)}),e.loader=!1}e.loader=!0;var r=angular.copy(j.metaRule);r.object_categories=_.without(r.object_categories,e.id),c.update(r,t,o)}function f(e){function t(t){n("moon.model.metarules.update.success",{metaRuleName:j.metaRule.name}).then(function(e){i.alertSuccess(e)}),r=c.findMetaDataFromMetaRule(a.transformOne(t,"meta_rules")),angular.copy(r,j.metaRule),l(),e.loader=!1}function o(t){n("moon.model.metarules.update.error",{metaRuleName:j.metaRule.name,reason:t.message}).then(function(e){i.alertError(e)}),e.loader=!1}e.loader=!0;var r=angular.copy(j.metaRule);r.action_categories=_.without(r.action_categories,e.id),c.update(r,t,o)}function h(){return j.catSub?j.catSub:[]}function g(){return j.catObj?j.catObj:[]}function y(){return j.catAct?j.catAct:[]}function v(e,t){j.metaRule=t,l()}function b(e,t){j.metaRule=t,l()}var j=this;j.metaRule=e.list.metaRule,j.editMode=e.list.editMode,j.shortDisplay=e.list.shortDisplay,j.typeOfSubject=r.TYPE.SUBJECT,j.typeOfObject=r.TYPE.OBJECT,j.typeOfAction=r.TYPE.ACTION,j.unMapSub=m,j.unMapObj=p,j.unMapAct=f,j.getSubjectCategories=h,j.getObjectCategories=g,j.getActionCategories=y,l();var S={"event:updateMetaRuleFromMetaDataAddSuccess":t.$on("event:updateMetaRuleFromMetaDataAddSuccess",v),"event:deleteMetaDataFromMetaDataAddSuccess":t.$on("event:deleteMetaDataFromMetaDataAddSuccess",b)};for(var T in S)e.$on("$destroy",S[T])}angular.module("moon").directive("moonMetaDataList",e),e.$inject=[],angular.module("moon").controller("moonMetaDataListController",t),t.$inject=["$scope","$rootScope","metaDataService","$translate","alertService","metaRuleService","META_DATA_CST","utilService"]}(),function(){"use strict";function e(){return{templateUrl:"html/model/edit/metarules/metarules-list.tpl.html",bindToController:!0,controller:t,controllerAs:"list",scope:{editMode:"=",mappedModel:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c){function r(){return _.table=new o({page:1,count:10,sorting:{name:"asc"}},{total:function(){return _.getMetaRules().length},getData:function(e,t){var o=t.sorting()?n("orderBy")(_.getMetaRules(),t.orderBy()):_.getMetaRules();e.resolve(o.slice((t.page()-1)*t.count(),t.page()*t.count()))},$scope:{$data:{}}}),_.table}function a(){return _.metaRules?_.metaRules:[]}function l(){return _.getMetaRules().length>0}function s(e){e.id===u().id?(_.showDetailValue=!1,_.subject_list=[],_.object_list=[],_.action_list=[]):(_.subject_list=e.subject_categories_values,_.object_list=e.object_categories_values,_.action_list=e.action_categories_values,_.showDetailValue=e)}function d(e){_.edit.modal.$scope.metaRule=e,_.edit.modal.$promise.then(_.edit.modal.show)}function u(){return _.showDetailValue}function m(){return _.subject_list}function p(){return _.object_list}function f(){return _.action_list}function h(){_.map.modal.$scope.model=_.model,_.map.modal.$promise.then(_.map.modal.show)}function g(){_.metaRules=_.model.meta_rules_values,_.table.total(_.getMetaRules().length),_.table.reload()}function y(e,t){_.model=t,g(),_.map.modal.hide()}function v(e){_.unmap.modal.$scope.model=_.model,_.unmap.modal.$scope.metaRule=e,_.unmap.modal.$promise.then(_.unmap.modal.show)}function b(e,t){_.model=t,c.findSomeWithCallback(_.model.meta_rules,function(e){_.model.meta_rules_values=e,g(),_.unmap.modal.hide()})}function j(e){_.unmap.modal.hide()}var _=this;_.table={},_.editMode=e.list.editMode,_.model=e.list.mappedModel,_.metaRules=_.model.meta_rules_values,_.getMetaRules=a,_.hasMetaRules=l,_.showDetail=s,_.getSubjectList=m,_.getObjectList=p,_.getActionlist=f,_.getShowDetailValue=u,_.showDetailValue=!1,_.subject_list=[],_.object_list=[],_.action_list=[],_.edit={modal:i({template:"html/model/edit/metarules/action/metarules-edit.tpl.html",show:!1}),showModal:d},_.map={modal:i({template:"html/model/edit/metarules/action/mapping/metarules-map.tpl.html",show:!1}),showModal:h},_.unmap={modal:i({template:"html/model/edit/metarules/action/mapping/metarules-unmap.tpl.html",show:!1}),showModal:v},function(){r()}();var S={"event:metaRuleMapToModelSuccess":t.$on("event:metaRuleMapToModelSuccess",y),"event:metaRuleUnMappedToModelSuccess":t.$on("event:metaRuleUnMappedToModelSuccess",b),"event:metaRuleUnMappedToModelError":t.$on("event:metaRuleUnMappedToModelError",j)};for(var T in S)e.$on("$destroy",S[T]);e.$watch("list.editMode",function(e,t){_.showDetailValue=!1})}angular.module("moon").directive("moonMetaRulesList",e),e.$inject=[],angular.module("moon").controller("moonMetaRulesListController",t),t.$inject=["$scope","$rootScope","NgTableParams","$filter","$modal","metaRuleService"]}(),function(){"use strict";function e(e,t,o,n,i,c,r){function a(){s.policiesLoading=!0,i.findAllWithCallback(function(e){s.policies=e,s.policiesLoading=!1})}function l(){function i(n){var i=r.transformOne(n,"pdps");o("moon.policy.map.success",{pdpName:i.name,policyName:s.selectedPolicy.name}).then(function(e){t.alertSuccess(e)}),s.mappingLoading=!1,e.$emit("event:policyMapToPdpSuccess",i)}function a(n){o("moon.policy.map.error",{pdpName:s.pdp.name,policyName:s.selectedPolicy.name}).then(function(e){t.alertError(e)}),s.mappingLoading=!1,e.$emit("event:policyMapToPdpError")}if(n.isInvalid(s.form))n.checkFieldsValidity(s.form);else{s.mappingLoading=!0;var l=angular.copy(s.pdp);l.security_pipeline.push(s.selectedPolicy.id),c.update(l,i,a)}}var s=this;s.pdps=[],s.pdp=e.pdp,s.addPolicyToList=!1,s.map=l,function(){a()}()}angular.module("moon").controller("PolicyMapController",e),e.$inject=["$scope","alertService","$translate","formService","policyService","pdpService","utilService"]}(),function(){"use strict";function e(e,t,o,n,i){function c(){function c(n){t("moon.policy.unmap.success",{pdpName:r.pdp.name,policyName:r.policy.name}).then(function(e){o.alertSuccess(e)}),r.unMappingLoading=!1,e.$emit("event:policyUnMappedToPdpSuccess",i.transformOne(n,"pdps"))}function a(n){t("moon.policy.unmap.error",{pdpName:r.pdp.name,policyName:r.policy.name}).then(function(e){o.alertError(e)}),r.unMappingLoading=!1,e.$emit("event:policyUnMappedToPdpError")}r.unMappingLoading=!0;var l=angular.copy(r.pdp);l.security_pipeline=_.without(l.security_pipeline,r.policy.id),n.update(l,c,a)}var r=this;r.pdp=e.pdp,r.policy=e.policy,r.unMappingLoading=!1,r.unmap=c}angular.module("moon").controller("PolicyUnMapController",e),e.$inject=["$scope","$translate","alertService","pdpService","utilService"]}(),function(){"use strict";function e(e,t,o,n,i){function c(){i.findAllWithCallBack(r)}function r(e){l.pdps=_.filter(e,function(e){return _.isNull(e.keystone_project_id)}),l.pdpsLoading=!1}function a(){function c(n){l.project.pdp=l.selectedPDP,t("moon.project.map.success",{projectName:l.project.name,pdpName:l.selectedPDP.name}).then(function(e){o.alertSuccess(e)}),l.mappingLoading=!1,e.$emit("event:projectMappedSuccess",l.project)}function r(n){t("moon.project.map.error",{projectName:l.project.name,pdpName:l.selectedPDP.name}).then(function(e){o.alertError(e)}),l.mappingLoading=!1,e.$emit("event:projectMappedError",l.project)}n.isInvalid(l.form)?n.checkFieldsValidity(l.form):(l.mappingLoading=!0,i.map(l.selectedPDP,l.project.id,c,r))}var l=this;l.form={},l.project=e.project,l.pdps=[],l.pdpsLoading=!0,l.selectedPDP=null,l.map=a,function(){c()}()}angular.module("moon").controller("ProjectMapController",e),e.$inject=["$scope","$translate","alertService","formService","pdpService"]}(),function(){"use strict";function e(e,t,o,n){function i(){function i(n){t("moon.project.unmap.success",{projectName:c.project.name,pdpName:a}).then(function(e){o.alertSuccess(e)}),c.unMappingLoading=!1,delete c.project.mapping,delete c.project.pdp,e.$emit("event:projectUnmappedSuccess",c.project)}function r(n){t("moon.project.unmap.error",{projectName:c.project.name,pdpName:a}).then(function(e){o.alertError(e)}),c.unMappingLoading=!1,e.$emit("event:projectUnmappedError",c.project)}c.unMappingLoading=!0;var a=c.project.pdp.name;n.unMap(c.project.pdp,i,r)}var c=this;c.project=e.project,c.unMappingLoading=!1,c.unmap=i}angular.module("moon").controller("ProjectUnMapController",e),e.$inject=["$scope","$translate","alertService","pdpService"]}(),function(){"use strict";function e(e,t,o,n){return{data:e(t.MODELS+":model_id",{},{get:{method:"GET"},query:{method:"GET"},create:{method:"POST"},remove:{method:"DELETE"},update:{method:"PATCH"}}),findAll:function(){return this.data.query().$promise.then(function(e){return n.transform(e,"models")})},findAllWithCallBack:function(e){return this.data.query().$promise.then(function(t){e(n.transform(t,"models"))})},findOneWithCallback:function(e,t){return this.data.get({model_id:e}).$promise.then(function(e){t(n.transformOne(e,"models"))})},findOneWithMetaRules:function(e){return this.data.get({model_id:e}).$promise.then(function(t){var i=n.transformOne(t,"models");return i.meta_rules.length>0?o.findSomeWithMetaData(i.meta_rules).then(function(t){return i.meta_rules_values=t,i.id=e,i}):(i.meta_rules_values=[],i.id=e),i})},delete:function(e,t,o){delete e.meta_rules_values,this.data.remove({model_id:e.id},e,t,o)},update:function(e,t,o){delete e.meta_rules_values,this.data.update({model_id:e.id},e,t,o)}}}angular.module("moon").factory("modelService",e),e.$inject=["$resource","REST_URI","metaRuleService","utilService"]}(),function(){"use strict";function e(e,t,o,n){var i={subject:e(t.METADATA.subject+":subject_id",{},{get:{method:"GET",isArray:!1},create:{method:"POST"},remove:{method:"DELETE"}}),object:e(t.METADATA.object+":object_id",{},{get:{method:"GET",isArray:!1},create:{method:"POST"},remove:{method:"DELETE"}}),action:e(t.METADATA.action+":action_id",{},{get:{method:"GET",isArray:!1},create:{method:"POST"},remove:{method:"DELETE"}})};return{subject:{findOne:function(e,t){i.subject.get({subject_id:e}).$promise.then(function(e){t(n.transformOne(e,"subject_categories"))})},findOneReturningPromise:function(e){return i.subject.get({subject_id:e}).$promise},findSome:function(e){var t=this;if(0===e.length)return[];var i=_(e).map(function(e){return t.findOneReturningPromise(e)});return o.all(i).then(function(e){return _(e).map(function(e){return n.transformOne(e,"subject_categories")})})},findSomeWithCallback:function(e,t){var i=this;0===e.length&&t([]);var c=_(e).map(function(e){return i.findOneReturningPromise(e)});o.all(c).then(function(e){t(_(e).map(function(e){return n.transformOne(e,"subject_categories")}))})},findAll:function(){return i.subject.get().$promise.then(function(e){return n.transform(e,"subject_categories")})},findAllWithCallback:function(e){return i.subject.get().$promise.then(function(t){e(n.transform(t,"subject_categories"))})},delete:function(e,t,o){i.subject.remove({subject_id:e.id},e,t,o)},add:function(e,t,o){i.subject.create({},e,t,o)}},object:{findOne:function(e,t){i.object.get({object_id:e}).$promise.then(function(e){t(n.transformOne(e,"object_categories"))})},findOneReturningPromise:function(e){return i.object.get({object_id:e}).$promise},findSome:function(e){var t=this;if(0===e.length)return[];var i=_(e).map(function(e){return t.findOneReturningPromise(e)});return o.all(i).then(function(e){return _(e).map(function(e){return n.transformOne(e,"object_categories")})})},findSomeWithCallback:function(e,t){var i=this;0===e.length&&t([]);var c=_(e).map(function(e){return i.findOneReturningPromise(e)});o.all(c).then(function(e){t(_(e).map(function(e){return n.transformOne(e,"object_categories")}))})},findAll:function(){return i.object.get().$promise.then(function(e){return n.transform(e,"object_categories")})},findAllWithCallback:function(e){return i.object.get().$promise.then(function(t){e(n.transform(t,"object_categories"))})},delete:function(e,t,o){i.object.remove({object_id:e.id},e,t,o)},add:function(e,t,o){i.object.create({},e,t,o)}},action:{findOne:function(e,t){i.action.get({action_id:e}).$promise.then(function(e){t(n.transformOne(e,"action_categories"))})},findOneReturningPromise:function(e){return i.action.get({action_id:e}).$promise},findSome:function(e){var t=this;if(0===e.length)return[];var i=_(e).map(function(e){return t.findOneReturningPromise(e)});return o.all(i).then(function(e){return _(e).map(function(e){return n.transformOne(e,"action_categories")})})},findSomeWithCallback:function(e,t){var i=this;0===e.length&&t([]);var c=_(e).map(function(e){return i.findOneReturningPromise(e)});o.all(c).then(function(e){t(_(e).map(function(e){return n.transformOne(e,"action_categories")}))})},findAll:function(){return i.action.get().$promise.then(function(e){return n.transform(e,"action_categories")})},findAllWithCallback:function(e){return i.action.get().$promise.then(function(t){e(n.transform(t,"action_categories"))})},delete:function(e,t,o){i.action.remove({action_id:e.id},e,t,o)},add:function(e,t,o){i.action.create({},e,t,o)}}}}angular.module("moon").factory("metaDataService",e),e.$inject=["$resource","REST_URI","$q","utilService"]}(),function(){"use strict";function e(e,t,o,n,i){return{data:e(t.METARULES+":metarule_id",{},{query:{method:"GET"},get:{method:"GET",isArray:!1},update:{method:"PATCH"},create:{method:"POST"},remove:{method:"DELETE"}}),findAll:function(){return this.data.query().$promise.then(function(e){return i.transform(e,"meta_rules")})},findAllWithCallback:function(e){this.data.query().$promise.then(function(t){e(i.transform(t,"meta_rules"))})},findSomeWithMetaData:function(e){var t=this;if(0===e.length)return[];var o=_(e).map(function(e){return t.findOneReturningPromise(e)});return n.all(o).then(function(e){return _(e).map(function(e){var o=i.transformOne(e,"meta_rules");return o=t.findMetaDataFromMetaRule(o)})})},findSomeWithCallback:function(e,t){var o=this;if(0===e.length)return t([]);var c=_(e).map(function(e){return o.findOneReturningPromise(e)});return n.all(c).then(function(e){t(_(e).map(function(e){return i.transformOne(e,"meta_rules")}))})},findOneReturningPromise:function(e){return this.data.get({metarule_id:e}).$promise},findOne:function(e){return this.data.get({metarule_id:e}).$promise.then(function(e){return i.transformOne(e,"meta_rules")})},findOneWithCallback:function(e,t){this.data.get({metarule_id:e}).$promise.then(function(e){t(i.transformOne(e,"meta_rules"))})},findOneWithMetaData:function(e){var t=this;return this.data.get({metarule_id:e}).$promise.then(function(e){var o=i.transformOne(e,"meta_rules");return o=t.findMetaDataFromMetaRule(o)})},findMetaDataFromMetaRule:function(e){return e.subject_categories.length>0?o.subject.findSome(e.subject_categories).then(function(t){e.subject_categories_values=t}):e.subject_categories_values=[],e.object_categories.length>0?o.object.findSome(e.object_categories).then(function(t){e.object_categories_values=t}):e.object_categories_values=[],e.action_categories.length>0?o.action.findSome(e.action_categories).then(function(t){e.action_categories_values=t}):e.action_categories_values=[],e},delete:function(e,t,o){this.data.remove({metarule_id:e.id},e,t,o)},update:function(e,t,o){delete e.subject_categories_values,delete e.object_categories_values,delete e.action_categories_values,this.data.update({metarule_id:e.id},e,t,o)}}}angular.module("moon").factory("metaRuleService",e),e.$inject=["$resource","REST_URI","metaDataService","$q","utilService"]}(),function(){"use strict";function e(e,t,o,n){return{data:{policy:e(t.POLICIES+":policy_id",{},{query:{method:"GET"},create:{method:"POST"},update:{method:"PATCH"},remove:{method:"DELETE"}})},findAll:function(){return this.data.policy.query().$promise.then(function(e){return o.transform(e,"policies")})},findAllWithCallback:function(e){return this.data.policy.query().$promise.then(function(t){e(o.transform(t,"policies"))})},findOneReturningPromise:function(e){return this.data.policy.get({policy_id:e}).$promise},findSomeWithCallback:function(e,t){var i=this;0===e.length&&t([]);var c=_(e).map(function(e){return i.findOneReturningPromise(e)});n.all(c).then(function(e){t(_(e).map(function(e){return o.transformOne(e,"policies")}))})},findOne:function(e){return this.data.policy.get({policy_id:e}).$promise.then(function(e){return o.transformOne(e,"policies")})},update:function(e,t,o){this.data.policy.update({policy_id:e.id},e,t,o)},delete:function(e,t,o){this.data.policy.remove({policy_id:e.id},e,t,o)}}}angular.module("moon").factory("policyService",e),e.$inject=["$resource","REST_URI","utilService","$q"]}(),function(){"use strict";function e(e,t){function o(e,t){angular.copy(t,n.metaRule)}var n=this;n.metaRule=e.metaRule;var i={"event:metaRuleBasicUpdatedSuccess":t.$on("event:metaRuleBasicUpdatedSuccess",o)};for(var c in i)e.$on("$destroy",i[c])}angular.module("moon").controller("MetaRulesEditController",e),e.$inject=["$scope","$rootScope"]}(),function(){"use strict";function e(){return{templateUrl:"html/model/edit/metarules/action/metarules-edit-basic.tpl.html",bindToController:!0,controller:t,controllerAs:"edit",scope:{metaRule:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c){function r(){function r(t){var o=c.transformOne(t,"meta_rules");angular.copy(o,l.metaRule),i("moon.model.metarules.edit.basic.success",{metaRuleName:o.name}).then(function(e){n.alertSuccess(e)}),l.loading=!1,e.$emit("event:metaRuleBasicUpdatedSuccess",l.metaRule)}function a(e){i("moon.model.edit.basic.error",{metaRuleName:l.metaRule.name}).then(function(e){n.alertError(e)}),l.loading=!1}o.isInvalid(l.form)?o.checkFieldsValidity(l.form):(l.loading=!0,t.update(l.metaRuleToEdit,r,a))}function a(){l.metaRuleToEdit=angular.copy(l.metaRule)}var l=this;l.editMetaRule=r,l.init=a,l.form={},function(){l.metaRule=e.edit.metaRule,l.metaRuleToEdit=angular.copy(l.metaRule)}()}angular.module("moon").directive("moonMetaRulesEditBasic",e),e.$inject=[],angular.module("moon").controller("moonMetaRulesEditBasicController",t),t.$inject=["$scope","metaRuleService","formService","alertService","$translate","utilService"]}(),function(){"use strict";function e(){return{templateUrl:"html/policy/edit/parameter/assignments/assignments-edit.tpl.html",bindToController:!0,controller:t,controllerAs:"edit",scope:{assignmentsType:"=",policy:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c,r,a,l,s,d){function u(){P.assignments={id:null,category_id:null,data_id:null,policy_id:null},p(),h()}function m(){function c(t){var i={};switch(P.assignmentsType){case l.TYPE.SUBJECT:i=r.transformOne(t,"subject_assignments");break;case l.TYPE.OBJECT:i=r.transformOne(t,"object_assignments");break;case l.TYPE.ACTION:i=r.transformOne(t,"action_assignments")}n("moon.policy.assignments.edit.create.success").then(function(e){o.alertSuccess(e)}),s&&i.policy_id===P.policy.id?(e.$emit("event:createAssignmentsFromAssignmentsEditSuccess",P.assignmentsType),u(),E()):s&&(u(),E())}function a(e){n("moon.policy.rules.edit.action.add.create.error").then(function(e){o.alertError(e)}),E()}if(P.assignementsAttributeValid=!0,S(),i.isInvalid(P.form))i.checkFieldsValidity(P.form);else if(P.assignementsAttributeValid){T();var s=!1;P.assignments.id=P.selectedPerimeter.id,P.assignments.category_id=P.selectedCategory.id,P.assignments.policy_id=P.selectedPolicy.id;var d=angular.copy(P.selectedDataList);_.each(d,function(e){P.assignments.data_id=e.id;var o=angular.copy(P.assignments);switch(P.assignmentsType){case l.TYPE.SUBJECT:t.subject.add(o,P.policy.id,c,a);break;case l.TYPE.OBJECT:t.object.add(o,P.policy.id,c,a);break;case l.TYPE.ACTION:t.action.add(o,P.policy.id,c,a)}}),s=!0}}function p(){P.policyList=[],P.loadingPolicies=!0,c.findAllWithCallback(function(e){_.each(e,function(e){e.id===P.policy.id&&(P.selectedPolicy=e)}),P.policyList=e,P.loadingPolicies=!1})}function f(){function e(e){P.perimeterList=e,P.loadingPerimeters=!1}switch(P.perimeterList=[],P.loadingPerimeters=!0,P.assignmentsType){case l.TYPE.SUBJECT:a.subject.findAllFromPolicyWithCallback(P.selectedPolicy.id,e);break;case l.TYPE.OBJECT:a.object.findAllFromPolicyWithCallback(P.selectedPolicy.id,e);break;case l.TYPE.ACTION:a.action.findAllFromPolicyWithCallback(P.selectedPolicy.id,e);break;default:P.perimeterList=[],P.loadingPerimeters=!1}}function h(){function e(e){P.categoryList=e,P.loadingCategories=!1}switch(P.categoryList=[],P.loadingCategories=!0,P.assignmentsType){case l.TYPE.SUBJECT:s.subject.findAllWithCallback(e);break;case l.TYPE.OBJECT:s.object.findAllWithCallback(e);break;case l.TYPE.ACTION:s.action.findAllWithCallback(e);break;default:P.categoryList=[],P.loadingCategories=!1}}function g(e){function t(e){P.dataList=e,P.dataToBeSelected=angular.copy(P.dataList),P.selectedDataList=[],P.loadingData=!1}switch(P.dataList=[],P.dataToBeSelected=[],P.selectedDataList=[],P.loadingData=!0,P.assignmentsType){case l.TYPE.SUBJECT:d.subject.findAllFromCategoriesWithCallback(P.selectedPolicy.id,e,t);break;case l.TYPE.OBJECT:d.object.findAllFromCategoriesWithCallback(P.selectedPolicy.id,e,t);break;case l.TYPE.ACTION:d.action.findAllFromCategoriesWithCallback(P.selectedPolicy.id,e,t);break;default:P.loadingData=!1}}function y(){P.dataToBeSelected=_.without(P.dataToBeSelected,P.selectedData),P.selectedDataList.push(P.selectedData),b()}function v(e){P.dataToBeSelected.push(e),P.selectedDataList=_.without(P.selectedDataList,e)}function b(){P.selectedData=void 0}function j(e){if(_.isUndefined(e))return"(None)";switch(P.assignmentsType){case l.TYPE.SUBJECT:return e.name;case l.TYPE.OBJECT:case l.TYPE.ACTION:return e.value.name;default:return e.name}}function S(){P.selectedDataList.length>=1?P.assignementsAttributeValid=!0:P.assignementsAttributeValid=!1}function T(){P.loading=!0}function E(){P.loading=!1}var P=this;P.assignmentsType=e.edit.assignmentsType,P.policy=e.edit.policy,P.laoading=!1,P.form={},P.policyList=[],P.loadingPolicies=!0,P.categoryList=[],P.loadingCategories=!0,P.perimeterList=[],P.loadingPerimeters=!0,P.dataList=[],P.dataToBeSelected=[],P.selectedDataList=[],P.loadingData=!0,P.assignementsAttributeValid=!0,P.addSelectedData=y,P.removeSelectedData=v,P.getName=j,P.create=m,u(),e.$watch("edit.selectedPolicy",function(e){_.isUndefined(e)||f()}),e.$watch("edit.selectedCategory",function(e){b(),_.isUndefined(e)||g(e.id)})}angular.module("moon").directive("moonAssignmentsEdit",e),e.$inject=[],angular.module("moon").controller("moonAssignmentsEditController",t),t.$inject=["$scope","assignmentsService","alertService","$translate","formService","policyService","utilService","perimeterService","ASSIGNMENTS_CST","metaDataService","dataService"]}(),function(){"use strict";function e(){return{
+templateUrl:"html/policy/edit/parameter/assignments/assignments-list.tpl.html",bindToController:!0,controller:t,controllerAs:"list",scope:{policy:"=",editMode:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c,r,a,l,s,d){function u(){m(),p(),f()}function m(){$.loadingSub=!0,o.subject.findAllFromPolicyWithCallback($.policy.id,function(e){$.subjects=e,$.loadingSub=!1})}function p(){$.loadingObj=!0,o.object.findAllFromPolicyWithCallback($.policy.id,function(e){$.objects=e,$.loadingObj=!1})}function f(){$.loadingAct=!0,o.action.findAllFromPolicyWithCallback($.policy.id,function(e){$.actions=e,$.loadingAct=!1})}function h(e,t){function o(t){e.callPerimeterInProgress=!1,e.perimeter=t}if(_.has(e,"perimeter"))return e.perimeter;if(!_.has(e,"callPerimeterInProgress"))switch(e.callPerimeterInProgress=!0,t){case r.TYPE.SUBJECT:s.subject.findOneFromPolicyWithCallback($.policy.id,e.subject_id,o);break;case r.TYPE.OBJECT:s.object.findOneFromPolicyWithCallback($.policy.id,e.object_id,o);break;case r.TYPE.ACTION:s.action.findOneFromPolicyWithCallback($.policy.id,e.action_id,o)}return!1}function g(e,t){function o(t){e.callCategoryInProgress=!1,e.category=t}if(_.has(e,"category"))return e.category;if(!_.has(e,"callCategoryInProgress"))switch(e.callCategoryInProgress=!0,t){case r.TYPE.SUBJECT:l.subject.findOne(e.subject_cat_id,o);break;case r.TYPE.OBJECT:l.object.findOne(e.object_cat_id,o);break;case r.TYPE.ACTION:l.action.findOne(e.action_cat_id,o)}return!1}function y(e,t,o){function n(o){t.assignments_value[e].callDataInProgress=!1,t.assignments_value[e].data=o}if(_.has(t,"assignments_value")||(t.assignments_value=Array.apply(null,new Array(t.assignments.length)).map(function(){return{data:{}}})),_.has(t.assignments_value[e],"callDataInProgress")&&!t.assignments_value[e].callDataInProgress)return t.assignments_value[e].data;if(!_.has(t.assignments_value[e],"callDataInProgress"))switch(t.assignments_value[e].callDataInProgress=!0,o){case r.TYPE.SUBJECT:d.subject.data.findOne($.policy.id,t.category_id,t.assignments[e],n);break;case r.TYPE.OBJECT:d.object.data.findOne($.policy.id,t.category_id,t.assignments[e],n);break;case r.TYPE.ACTION:d.action.data.findOne($.policy.id,t.category_id,t.assignments[e],n)}return!1}function v(e,t){function c(t){n("moon.policy.assignments.subject.delete.success").then(function(e){i.alertSuccess(e)}),m(),e.loader=!1}function r(t){n("moon.policy.assignments.subject.delete.error",{subjectName:e.name,reason:t.message}).then(function(e){i.alertError(e)}),e.loader=!1}e.loader=!0,o.subject.delete($.policy.id,e.subject_id,e.subject_cat_id,t,c,r)}function b(e,t){function c(t){n("moon.policy.assignments.object.delete.success").then(function(e){i.alertSuccess(e)}),p(),e.loader=!1}function r(t){n("moon.policy.assignments.object.delete.error",{objectName:e.name,reason:t.message}).then(function(e){i.alertError(e)}),e.loader=!1}e.loader=!0,o.object.delete($.policy.id,e.object_id,e.object_cat_id,t,c,r)}function j(e,t){function c(t){n("moon.policy.assignments.action.delete.success").then(function(e){i.alertSuccess(e)}),f(),e.loader=!1}function r(t){n("moon.policy.assignments.action.delete.error",{actionName:e.name,reason:t.message}).then(function(e){i.alertError(e)}),e.loader=!1}e.loader=!0,o.action.delete($.policy.id,e.action_id,e.action_cat_id,t,c,r)}function S(){return $.subjects?$.subjects:[]}function T(){return $.objects?$.objects:[]}function E(){return $.actions?$.actions:[]}function P(e,t){switch(t){case r.TYPE.SUBJECT:m();break;case r.TYPE.OBJECT:p();break;case r.TYPE.ACTION:f();break;default:u()}}var $=this;$.policy=e.list.policy,$.editMode=e.list.editMode,$.typeOfSubject=r.TYPE.SUBJECT,$.typeOfObject=r.TYPE.OBJECT,$.typeOfAction=r.TYPE.ACTION,$.deleteSub=v,$.deleteObj=b,$.deleteAct=j,$.getSubjects=S,$.getObjects=T,$.getActions=E,$.getCategoryFromAssignment=g,$.getPerimeterFromAssignment=h,$.getDataFromAssignmentsIndex=y,u();var C={"event:createAssignmentsFromAssignmentsEditSuccess":t.$on("event:createAssignmentsFromAssignmentsEditSuccess",P)};_.each(C,function(t){e.$on("$destroy",C[t])})}angular.module("moon").directive("moonAssignmentsList",e),e.$inject=[],angular.module("moon").controller("moonAssignmentsListController",t),t.$inject=["$scope","$rootScope","assignmentsService","$translate","alertService","policyService","ASSIGNMENTS_CST","utilService","metaDataService","perimeterService","dataService"]}(),function(){"use strict";function e(){return{templateUrl:"html/policy/edit/parameter/data/data-edit.tpl.html",bindToController:!0,controller:t,controllerAs:"edit",scope:{mnDataType:"=",policy:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c,r,a,l,s,d){function u(){s.findOneWithCallback(h.policy.model_id,function(e){d.findSomeWithCallback(e.meta_rules,function(e){function t(e){h.categoriesToBeSelected=e}switch(h.dataType){case o.TYPE.SUBJECT:var n=_.reduce(e,function(e,t){return e.concat(t.subject_categories)},[]);l.subject.findSomeWithCallback(n,t);break;case o.TYPE.OBJECT:var i=_.reduce(e,function(e,t){return e.concat(t.object_categories)},[]);l.object.findSomeWithCallback(i,t);break;case o.TYPE.ACTION:var c=_.reduce(e,function(e,t){return e.concat(t.action_categories)},[]);l.action.findSomeWithCallback(c,t);break;default:h.categoriesToBeSelected=[]}})})}function m(){function r(t){var c={},r="";switch(h.dataType){case o.TYPE.SUBJECT:c=a.transformOne(t.subject_data,"data"),r=c.name;break;case o.TYPE.OBJECT:c=a.transformOne(t.object_data,"data"),r=c.value.name;break;case o.TYPE.ACTION:c=a.transformOne(t.action_data,"data"),r=c.value.name}i("moon.policy.data.edit.create.success",{name:r}).then(function(e){n.alertSuccess(e)}),e.$emit("event:createDataFromDataEditSuccess",c,h.dataType),f(),h.list.push(c)}function l(e){i("moon.policy.data.edit.create.error",{name:s.name}).then(function(e){n.alertError(e)}),f()}if(c.isInvalid(h.form))c.checkFieldsValidity(h.form);else{p();var s=angular.copy(h.data);switch(h.dataType){case o.TYPE.SUBJECT:t.subject.add(s,h.policy.id,h.selectedCategory.id,r,l);break;case o.TYPE.OBJECT:t.object.add(s,h.policy.id,h.selectedCategory.id,r,l);break;case o.TYPE.ACTION:t.action.add(s,h.policy.id,h.selectedCategory.id,r,l)}}}function p(){h.loading=!0}function f(){h.loading=!1}var h=this;h.dataType=e.edit.mnDataType,h.policy=e.edit.policy,h.fromList=!1,h.loading=!1,h.form={},h.data={name:null,description:null},h.list=[],h.categoriesToBeSelected=[],h.create=m,function(){function e(e){_.each(e,function(e){e.policy_id!==h.policy.id&&h.list.push(e)})}switch(u(),h.dataType){case o.TYPE.SUBJECT:t.subject.findAllFromPolicyWithCallback(h.policy.id,e);break;case o.TYPE.OBJECT:t.object.findAllFromPolicyWithCallback(h.policy.id,e);break;case o.TYPE.ACTION:t.action.findAllFromPolicyWithCallback(h.policy.id,e);break;default:h.list=[]}}()}angular.module("moon").directive("moonDataEdit",e),e.$inject=[],angular.module("moon").controller("moonDataEditController",t),t.$inject=["$scope","dataService","DATA_CST","alertService","$translate","formService","policyService","utilService","metaDataService","modelService","metaRuleService"]}(),function(){"use strict";function e(){return{templateUrl:"html/policy/edit/parameter/data/data-list.tpl.html",bindToController:!0,controller:t,controllerAs:"list",scope:{policy:"=",editMode:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c,r){function a(){S.loadingSub=!0,o.subject.findAllFromPolicyWithCallback(S.policy.id,function(e){S.subjects=e,S.loadingSub=!1})}function l(){S.loadingObj=!0,o.object.findAllFromPolicyWithCallback(S.policy.id,function(e){S.objects=e,S.loadingObj=!1})}function s(){S.loadingAct=!0,o.action.findAllFromPolicyWithCallback(S.policy.id,function(e){S.actions=e,S.loadingAct=!1})}function d(e,t){function o(t){e.callCategoryInProgress=!1,e.category=t}if(_.has(e,"category"))return e.category;if(!_.has(e,"callCategoryInProgress"))switch(e.callCategoryInProgress=!0,t){case c.TYPE.SUBJECT:r.subject.findOne(e.category_id,o);break;case c.TYPE.OBJECT:r.object.findOne(e.category_id,o);break;case c.TYPE.ACTION:r.action.findOne(e.category_id,o)}return!1}function u(e){function t(t){n("moon.policy.data.subject.delete.success",{subjectName:e.name}).then(function(e){i.alertSuccess(e)}),y(e),e.loader=!1}function c(t){n("moon.policy.data.subject.delete.error",{subjectName:e.name,reason:t.message}).then(function(e){i.alertError(e)}),e.loader=!1}e.loader=!0,o.subject.delete(e,S.policy.id,e.category_id,t,c)}function m(e){function t(t){n("moon.policy.data.object.delete.success",{objectName:e.name}).then(function(e){i.alertSuccess(e)}),v(e),e.loader=!1}function c(t){n("moon.policy.data.object.delete.error",{objectName:e.name,reason:t.message}).then(function(e){i.alertError(e)}),e.loader=!1}e.loader=!0,o.object.delete(e,S.policy.id,e.category_id,t,c)}function p(e){function t(t){n("moon.policy.data.action.delete.success",{actionName:e.name}).then(function(e){i.alertSuccess(e)}),b(e),e.loader=!1}function c(t){n("moon.policy.data.action.delete.error",{actionName:e.name,reason:t.message}).then(function(e){i.alertError(e)}),e.loader=!1}e.loader=!0,o.action.delete(e,S.policy.id,e.category_id,t,c)}function f(){return S.subjects?S.subjects:[]}function h(){return S.objects?S.objects:[]}function g(){return S.actions?S.actions:[]}function y(e){S.subjects=_.without(S.subjects,e)}function v(e){S.objects=_.without(S.objects,e)}function b(e){S.actions=_.without(S.actions,e)}function j(e,t,o){switch(o){case c.TYPE.SUBJECT:S.subjects.push(t);break;case c.TYPE.OBJECT:S.objects.push(t);break;case c.TYPE.ACTION:S.actions.push(t)}}var S=this;S.policy=e.list.policy,S.editMode=e.list.editMode,S.typeOfSubject=c.TYPE.SUBJECT,S.typeOfObject=c.TYPE.OBJECT,S.typeOfAction=c.TYPE.ACTION,S.deleteSub=u,S.deleteObj=m,S.deleteAct=p,S.getSubjects=f,S.getObjects=h,S.getActions=g,S.getCategoryFromData=d,function(){a(),l(),s()}();var T={"event:createDataFromDataEditSuccess":t.$on("event:createDataFromDataEditSuccess",j)};_.each(T,function(t){e.$on("$destroy",T[t])})}angular.module("moon").directive("moonDataList",e),e.$inject=[],angular.module("moon").controller("moonDataListController",t),t.$inject=["$scope","$rootScope","dataService","$translate","alertService","DATA_CST","metaDataService"]}(),function(){"use strict";function e(){return{templateUrl:"html/policy/edit/parameter/perimeter/perimeter-edit.tpl.html",bindToController:!0,controller:t,controllerAs:"edit",scope:{perimeterType:"=",policy:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c,r,a,l){function s(){function e(e){_.each(e,function(e){-1===_.indexOf(e.policy_list,T.policy.id)&&T.list.push(e)})}switch(d(),T.perimeterType){case n.TYPE.SUBJECT:o.subject.findAllWithCallback(e);break;case n.TYPE.OBJECT:o.object.findAllWithCallback(e);break;case n.TYPE.ACTION:o.action.findAllWithCallback(e);break;default:T.list=[]}}function d(){T.policyList=[],a.findAllWithCallback(function(e){T.policyList=e,T.policiesToBeSelected=angular.copy(T.policyList)})}function u(){T.selectedPolicy&&!_.contains(T.perimeter.policy_list,T.selectedPolicy.id)&&(T.perimeter.policy_list.push(T.selectedPolicy.id),T.selectedPolicyList.push(T.selectedPolicy),T.policiesToBeSelected=_.without(T.policiesToBeSelected,T.selectedPolicy))}function m(){T.perimeter.policy_list=[],T.selectedPolicyList=[],T.policiesToBeSelected=angular.copy(T.policyList)}function p(e){T.policiesToBeSelected.push(e),T.perimeter.policy_list=_.without(T.perimeter.policy_list,e.id),T.selectedPolicyList=_.without(T.selectedPolicyList,e)}function f(){function e(e){c("moon.perimeter.update.success",{policyName:r.name}).then(function(e){i.alertSuccess(e)}),b()}function t(e){c("moon.policy.update.error",{policyName:r.name,reason:e.message}).then(function(e){i.alertError(e)}),b()}if(T.selectedPerimeter){v();var r=T.selectedPerimeter;switch(r.policy_list.push(T.policy.id),T.perimeterType){case n.TYPE.SUBJECT:o.subject.update(r,e,t);break;case n.TYPE.OBJECT:o.object.update(r,e,t);break;case n.TYPE.ACTION:o.action.update(r,e,t)}}}function h(){function t(t){var o={};switch(T.perimeterType){case n.TYPE.SUBJECT:o=l.transformOne(t,"subjects");break;case n.TYPE.OBJECT:o=l.transformOne(t,"objects");break;case n.TYPE.ACTION:o=l.transformOne(t,"actions")}c("moon.policy.perimeter.edit.create.success",{name:o.name}).then(function(e){i.alertSuccess(e)}),b(),-1===_.indexOf(o.policy_list,T.policy.id)?T.list.push(o):e.$emit("event:createAssignmentsFromAssignmentsEditSuccess",o,T.perimeterType),j(),m()}function a(e){c("moon.policy.perimeter.edit.create.error",{name:s.name}).then(function(e){i.alertError(e)}),b()}if(r.isInvalid(T.form))r.checkFieldsValidity(T.form);else{v();var s=angular.copy(T.perimeter);switch(T.perimeterType){case n.TYPE.SUBJECT:o.subject.add(s,t,a);break;case n.TYPE.OBJECT:o.object.add(s,t,a);break;case n.TYPE.ACTION:o.action.add(s,t,a)}}}function g(){function t(t){c("moon.policy.perimeter.edit.delete.success",{name:d.name}).then(function(e){i.alertSuccess(e)}),a.findOneReturningPromise(T.policy.id).then(function(t){T.policy=l.transformOne(t,"policies"),y(),s(),b(),e.$emit("event:deletePerimeterFromPerimeterAddSuccess",T.policy)})}function r(e){c("moon.policy.perimeter.edit.delete.error",{name:d.name}).then(function(e){i.alertError(e)}),b()}if(T.selectedPerimeter){v();var d=angular.copy(T.selectedPerimeter);switch(T.perimeterType){case n.TYPE.SUBJECT:o.subject.delete(d,t,r);break;case n.TYPE.OBJECT:o.object.delete(d,t,r);break;case n.TYPE.ACTION:o.action.delete(d,t,r)}}}function y(){T.list=_.without(T.list,T.selectedPerimeter),delete T.selectedPerimeter}function v(){T.loading=!0}function b(){T.loading=!1}function j(){T.fromList=!0}function S(e,t,o){o===T.perimeterType&&-1===_.indexOf(t.policy_list,T.policy.id)&&T.list.push(t)}var T=this;T.perimeterType=e.edit.perimeterType,T.subjectType=n.TYPE.SUBJECT,T.policy=e.edit.policy,T.fromList=!0,T.loading=!1,T.form={},T.perimeter={name:null,description:null,partner_id:null,policy_list:[],email:null},T.list=[],T.policyList=[],T.policiesToBeSelected=[],T.selectedPolicyList=[],T.create=h,T.addToPolicy=f,T.addPolicyToPerimeter=u,T.clearSelectedPolicies=m,T.removeSelectedPolicy=p,T.deletePerimeter=g,s();var E={"event:unMapPerimeterFromPerimeterList":t.$on("event:unMapPerimeterFromPerimeterList",S)};_.each(E,function(t){e.$on("$destroy",E[t])})}angular.module("moon").directive("moonPerimeterEdit",e),e.$inject=[],angular.module("moon").controller("moonPerimeterEditController",t),t.$inject=["$scope","$rootScope","perimeterService","PERIMETER_CST","alertService","$translate","formService","policyService","utilService"]}(),function(){"use strict";function e(){return{templateUrl:"html/policy/edit/parameter/perimeter/perimeter-list.tpl.html",bindToController:!0,controller:t,controllerAs:"list",scope:{policy:"=",editMode:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c){function r(){a(),l(),s()}function a(){v.loadingSub=!0,o.subject.findAllFromPolicyWithCallback(v.policy.id,function(e){v.subjects=e,v.loadingSub=!1})}function l(){v.loadingObj=!0,o.object.findAllFromPolicyWithCallback(v.policy.id,function(e){v.objects=e,v.loadingObj=!1})}function s(){v.loadingAct=!0,o.action.findAllFromPolicyWithCallback(v.policy.id,function(e){v.actions=e,v.loadingAct=!1})}function d(t){function a(o){n("moon.policy.perimeter.update.success",{perimeterName:s.name}).then(function(e){i.alertSuccess(e)}),e.$emit("event:unMapPerimeterFromPerimeterList",t,c.TYPE.SUBJECT),r(),t.loader=!1}function l(e){n("moon.policy.perimeter.update.error",{perimeterName:t.name,reason:e.message}).then(function(e){i.alertError(e)}),t.loader=!1}t.policy_list=_.without(t.policy_list,v.policy.id),t.loader=!0;var s=angular.copy(t);o.subject.unMapPerimeterFromPolicy(v.policy.id,t.id,a,l)}function u(t){function a(o){n("moon.policy.perimeter.update.success",{perimeterName:s.name}).then(function(e){i.alertSuccess(e)}),e.$emit("event:unMapPerimeterFromPerimeterList",t,c.TYPE.OBJECT),r(),t.loader=!1}function l(e){n("moon.policy.perimeter.update.error",{perimeterName:t.name,reason:e.message}).then(function(e){i.alertError(e)}),t.loader=!1}t.policy_list=_.without(t.policy_list,v.policy.id),t.loader=!0;var s=angular.copy(t);o.object.unMapPerimeterFromPolicy(v.policy.id,t.id,a,l)}function m(t){function a(o){n("moon.policy.perimeter.update.success",{perimeterName:s.name}).then(function(e){i.alertSuccess(e)}),e.$emit("event:unMapPerimeterFromPerimeterList",t,c.TYPE.ACTION),r(),t.loader=!1}function l(e){n("moon.policy.perimeter.update.error",{perimeterName:t.name,reason:e.message}).then(function(e){i.alertError(e)}),t.loader=!1}t.policy_list=_.without(t.policy_list,v.policy.id),t.loader=!0;var s=angular.copy(t);o.action.unMapPerimeterFromPolicy(v.policy.id,t.id,a,l)}function p(){return v.subjects?v.subjects:[]}function f(){return v.objects?v.objects:[]}function h(){return v.actions?v.actions:[]}function g(e,t){v.policy=t,r()}function y(e,t,o){switch(o){case c.TYPE.SUBJECT:v.subjects.push(t);break;case c.TYPE.OBJECT:v.objects.push(t);break;case c.TYPE.ACTION:v.actions.push(t)}}var v=this;v.policy=e.list.policy,v.editMode=e.list.editMode,v.typeOfSubject=c.TYPE.SUBJECT,v.typeOfObject=c.TYPE.OBJECT,v.typeOfAction=c.TYPE.ACTION,v.unMapSub=d,v.unMapObj=u,v.unMapAct=m,v.getSubjects=p,v.getObjects=f,v.getActions=h,r();var b={"event:deletePerimeterFromPerimeterAddSuccess":t.$on("event:deletePerimeterFromPerimeterAddSuccess",g),"event:createAssignmentsFromAssignmentsEditSuccess":t.$on("event:createAssignmentsFromAssignmentsEditSuccess",y)};_.each(b,function(t){e.$on("$destroy",b[t])})}angular.module("moon").directive("moonPerimeterList",e),e.$inject=[],angular.module("moon").controller("moonPerimeterListController",t),t.$inject=["$scope","$rootScope","perimeterService","$translate","alertService","PERIMETER_CST"]}(),function(){"use strict";function e(){return{templateUrl:"html/policy/edit/parameter/rules/rules-edit.tpl.html",bindToController:!0,controller:t,controllerAs:"edit",scope:{policy:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c,r,a,l,s,d,u){function m(){M.rules={meta_rule_id:null,rule:[],policy_id:null,instructions:'[{"decision": "grant"}]',enabled:!0},R(),p(),E()}function p(){M.policyList=[],c.findAllWithCallback(function(e){_.each(e,function(e){e.id===M.policy.id&&(M.selectedPolicy=e)}),M.policyList=e})}function f(){M.selectedPolicy.meta_rules_values=void 0,s.findOneWithCallback(M.selectedPolicy.model_id,function(e){a.findSomeWithCallback(e.meta_rules,function(e){M.selectedPolicy.meta_rules_values=e})})}function h(e,t,o){l.subject.findSomeWithCallback(e,function(e){M.categories.subject=e,M.categories.loadingSubjects=!1,_.each(M.categories.subject,function(e){d.subject.findAllFromCategoriesWithCallback(M.selectedPolicy.id,e.id,function(e){M.data.subject=e,M.data.loadingSubjects=!1,M.data.subjectsToBeSelected=angular.copy(M.data.subject)})})}),l.object.findSomeWithCallback(t,function(e){M.categories.object=e,M.categories.loadingObjects=!1,_.each(M.categories.object,function(e){d.object.findAllFromCategoriesWithCallback(M.selectedPolicy.id,e.id,function(e){M.data.object=e,M.data.loadingObjects=!1,M.data.objectsToBeSelected=angular.copy(M.data.object)})})}),l.action.findSomeWithCallback(o,function(e){M.categories.action=e,M.categories.loadingActions=!1,_.each(M.categories.action,function(e){d.action.findAllFromCategoriesWithCallback(M.selectedPolicy.id,e.id,function(e){M.data.action=e,M.data.loadingActions=!1,M.data.actionsToBeSelected=angular.copy(M.data.action)})})})}function g(){function c(t){var i=r.transformOne(t,"rules");n("moon.policy.rules.edit.action.add.create.success").then(function(e){o.alertSuccess(e)}),e.$emit("event:createRulesFromDataRulesSuccess",i),m(),T()}function a(e){n("moon.policy.rules.edit.action.add.create.error").then(function(e){o.alertError(e)}),T()}if(M.instructionsValid=!0,M.numberOfSelectedSubjectValid=!0,M.numberOfSelectedObjecttValid=!0,M.numberOfSelectedActionsValid=!0,y(),v(),i.isInvalid(M.form))i.checkFieldsValidity(M.form);else if(M.instructionsValid&&v()){S(),A(),M.rules.meta_rule_id=M.selectedMetaRules.id,M.rules.policy_id=M.selectedPolicy.id;var l=angular.copy(M.rules);l.instructions=JSON.parse(M.rules.instructions),t.add(l,M.policy.id,c,a)}}function y(){b(M.rules.instructions)?M.instructionsValid=!0:M.instructionsValid=!1}function v(){return $(u.TYPE.SUBJECT)?M.numberOfSelectedSubjectValid=!0:M.numberOfSelectedSubjectValid=!1,$(u.TYPE.OBJECT)?M.numberOfSelectedObjecttValid=!0:M.numberOfSelectedObjecttValid=!1,$(u.TYPE.ACTION)?M.numberOfSelectedActionsValid=!0:M.numberOfSelectedActionsValid=!1,M.numberOfSelectedSubjectValid&&M.numberOfSelectedObjecttValid&&M.numberOfSelectedActionsValid}function b(e){return!_.isUndefined(e)&&j(e)}function j(e){var t=null;try{t=JSON.parse(e)}catch(e){return!1}return"object"==typeof t&&null!==t}function S(){M.loading=!0}function T(){M.loading=!1}function E(){M.selectedMetaRules=void 0,P()}function P(){M.selectedSubject=void 0,M.selectedObject=void 0,M.selectedAction=void 0}function $(e){if(!M.selectedMetaRules)return!1;switch(e){case u.TYPE.SUBJECT:return M.data.selectedSubjectsList.length===M.selectedMetaRules.subject_categories.length;case u.TYPE.OBJECT:return M.data.selectedObjectsList.length===M.selectedMetaRules.object_categories.length;case u.TYPE.ACTION:return M.data.selectedActionsList.length===M.selectedMetaRules.action_categories.length}}function C(e){switch(e){case u.TYPE.SUBJECT:if(!M.selectedSubject||$(e)||_.contains(M.data.selectedSubjectsList,M.selectedSubject))return;M.data.selectedSubjectsList.push(M.selectedSubject),M.data.subjectsToBeSelected=_.without(M.data.subjectsToBeSelected,M.selectedSubject);break;case u.TYPE.OBJECT:if(!M.selectedObject||$(e)||_.contains(M.data.selectedObjectsList,M.selectedObject))return;M.data.selectedObjectsList.push(M.selectedObject),M.data.objectsToBeSelected=_.without(M.data.objectsToBeSelected,M.selectedObject);break;case u.TYPE.ACTION:if(!M.selectedAction||$(e)||_.contains(M.data.selectedActionsList,M.selectedAction))return;M.data.selectedActionsList.push(M.selectedAction),M.data.actionsToBeSelected=_.without(M.data.actionsToBeSelected,M.selectedAction)}}function O(e,t){switch(t){case u.TYPE.SUBJECT:M.data.subjectsToBeSelected.push(e),M.data.selectedSubjectsList=_.without(M.data.selectedSubjectsList,e);break;case u.TYPE.OBJECT:M.data.objectsToBeSelected.push(e),M.data.selectedObjectsList=_.without(M.data.selectedObjectsList,e);break;case u.TYPE.ACTION:M.data.actionsToBeSelected.push(e),M.data.selectedActionsList=_.without(M.data.selectedActionsList,e)}}function A(){function e(e){M.rules.rule.push(e.id)}_.each(M.data.selectedSubjectsList,e),_.each(M.data.selectedObjectsList,e),_.each(M.data.selectedActionsList,e)}function R(){M.data={subject:[],loadingSubjects:!0,subjectsToBeSelected:[],selectedSubjectsList:[],subjectCST:u.TYPE.SUBJECT,object:[],loadingObjects:!0,objectsToBeSelected:[],selectedObjectsList:[],objectCST:u.TYPE.OBJECT,action:[],loadingActions:!0,actionsToBeSelected:[],selectedActionsList:[],actionCST:u.TYPE.ACTION}}var M=this;M.policy=e.edit.policy,M.editMode=!0,M.fromList=!1,M.loading=!1,M.form={},M.showDetailselectedMetaRules=!1,M.list=[],M.policyList=[],M.categories={subject:[],loadingSubjects:!0,object:[],loadingObjects:!0,action:[],loadingActions:!0},M.data={},M.create=g,M.addDataToRules=C,M.removeSelectedDataFromRules=O,M.isNumberSelectedDataAtMaximum=$,M.instructionsValid=!0,M.numberOfSelectedSubjectValid=!0,M.numberOfSelectedObjecttValid=!0,M.numberOfSelectedActionsValid=!0,m(),e.$watch("edit.selectedPolicy",function(e){E(),_.isUndefined(e)||f()}),e.$watch("edit.selectedMetaRules",function(e){P(),M.categories={subject:[],loadingSubjects:!0,object:[],loadingObjects:!0,action:[],loadingActions:!0},R(),_.isUndefined(e)||h(e.subject_categories,e.object_categories,e.action_categories)})}angular.module("moon").directive("moonRulesEdit",e),e.$inject=[],angular.module("moon").controller("moonRulesEditController",t),t.$inject=["$scope","rulesService","alertService","$translate","formService","policyService","utilService","metaRuleService","metaDataService","modelService","dataService","DATA_CST"]}(),function(){"use strict";function e(){return{templateUrl:"html/policy/edit/parameter/rules/rules-list.tpl.html",bindToController:!0,controller:t,controllerAs:"list",scope:{policy:"=",editMode:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c,r,a,l){function s(){c.findAllFromPolicyWithCallback(T.policy.id,function(e){T.rules=e,T.loadingRules=!1,v()})}function d(){return T.table=new o({page:1,count:10},{total:function(){return T.getRules().length},getData:function(e,t){var o=t.sorting()?n("orderBy")(T.getRules(),t.orderBy()):T.getRules();e.resolve(o.slice((t.page()-1)*t.count(),t.page()*t.count()))},$scope:{$data:{}}}),T.table}function u(e){return _.has(e,"meta_rule")?e.meta_rule:(_.has(e,"callMetaRuleInProgress")||(e.callMetaRuleInProgress=!0,i.findOneWithCallback(e.meta_rule_id,function(t){e.callMetaRuleInProgress=!1,e.meta_rule=t})),!1)}function m(e,t){if(_.has(t,"rule_value")||(t.rule_value=Array.apply(null,new Array(t.rule.length)).map(function(){return{category:{}}})),_.has(t.rule_value[e],"callCategoryInProgress")&&!t.rule_value[e].callCategoryInProgress)return t.rule_value[e].category;if(!_.has(t.rule_value[e],"callCategoryInProgress")){t.rule_value[e].callCategoryInProgress=!0;var o=0;T.isRuleIndexSubjectCategory(e,t)?(o=t.meta_rule.subject_categories[e],r.subject.data.findOne(T.policy.id,o,t.rule[e],function(o){t.rule_value[e].callCategoryInProgress=!1,t.rule_value[e].category=o})):T.isRuleIndexObjectCategory(e,t)?(o=t.meta_rule.object_categories[e-t.meta_rule.subject_categories.length],r.object.data.findOne(T.policy.id,o,t.rule[e],function(o){t.rule_value[e].callCategoryInProgress=!1,t.rule_value[e].category=o})):T.isRuleIndexActionCategory(e,t)?(o=t.meta_rule.action_categories[e-t.meta_rule.subject_categories.length-t.meta_rule.object_categories.length],r.action.data.findOne(T.policy.id,o,t.rule[e],function(o){t.rule_value[e].callCategoryInProgress=!1,t.rule_value[e].category=o})):(t.rule_value[e].callCategoryInProgress=!1,t.rule_value[e].category={name:"ERROR"})}return!1}function p(e,t){return e+1<=t.meta_rule.subject_categories.length}function f(e,t){var o=e+1;return t.meta_rule.subject_categories.length<o&&o<=t.meta_rule.object_categories.length+t.meta_rule.subject_categories.length}function h(e,t){var o=e+1;return t.meta_rule.object_categories.length+t.meta_rule.subject_categories.length<o&&o<=t.meta_rule.object_categories.length+t.meta_rule.subject_categories.length+t.meta_rule.action_categories.length}function g(){return T.rules?T.rules:[]}function y(){return T.getRules().length>0}function v(){T.table.total(T.rules.length),T.table.reload()}function b(e,t){T.rules.push(t),v()}function j(e){function t(){a("moon.policy.rules.edit.action.add.delete.success").then(function(e){l.alertSuccess(e)}),S(e),v(),e.loader=!1}function o(t){a("moon.policy.rules.edit.action.add.delete.success",{reason:t.message}).then(function(e){l.alertError(e)}),e.loader=!1}e.loader=!0,c.delete(e.id,T.policy.id,t,o)}function S(e){T.rules=_.without(T.rules,e)}var T=this;T.rules=[],T.editMode=e.list.editMode,T.loadingRules=!0,T.table={},T.getRules=g,T.hasRules=y,T.refreshRules=v,T.deleteRules=j,T.getMetaRuleFromRule=u,T.getCategoryFromRuleIndex=m,T.isRuleIndexSubjectCategory=p,T.isRuleIndexObjectCategory=f,T.isRuleIndexActionCategory=h,function(){d(),s()}();var E={"event:createRulesFromDataRulesSuccess":t.$on("event:createRulesFromDataRulesSuccess",b)};_.each(E,function(t){e.$on("$destroy",E[t])})}angular.module("moon").directive("moonRulesList",e),e.$inject=[],angular.module("moon").controller("moonRulesListController",t),t.$inject=["$scope","$rootScope","NgTableParams","$filter","metaRuleService","rulesService","dataService","$translate","alertService"]}(),function(){"use strict";function e(e,t,o){var n={subject:{policy:e(t.POLICIES+":policy_id/subject_assignments/:perimeter_id/:category_id/:data_id",{},{get:{method:"GET"},create:{method:"POST"},remove:{method:"DELETE"}})},object:{policy:e(t.POLICIES+":policy_id/object_assignments/:perimeter_id/:category_id/:data_id",{},{get:{method:"GET"},create:{method:"POST"},remove:{method:"DELETE"}})},action:{policy:e(t.POLICIES+":policy_id/action_assignments/:perimeter_id/:category_id/:data_id",{},{get:{method:"GET"},create:{method:"POST"},remove:{method:"DELETE"}})}};return{subject:{delete:function(e,t,o,i,c,r){n.subject.policy.remove({policy_id:e,perimeter_id:t,category_id:o,data_id:i},{},c,r)},add:function(e,t,o,i){n.subject.policy.create({policy_id:t},e,o,i)},findAllFromPolicyWithCallback:function(e,t){n.subject.policy.get({policy_id:e}).$promise.then(function(e){t(o.transform(e,"subject_assignments"))})}},object:{delete:function(e,t,o,i,c,r){n.object.policy.remove({policy_id:e,perimeter_id:t,category_id:o,data_id:i},{},c,r)},add:function(e,t,o,i){n.object.policy.create({policy_id:t},e,o,i)},findAllFromPolicyWithCallback:function(e,t){n.object.policy.get({policy_id:e}).$promise.then(function(e){t(o.transform(e,"object_assignments"))})}},action:{delete:function(e,t,o,i,c,r){n.action.policy.remove({policy_id:e,perimeter_id:t,category_id:o,data_id:i},{},c,r)},add:function(e,t,o,i){n.action.policy.create({policy_id:t},e,o,i)},findAllFromPolicyWithCallback:function(e,t){n.action.policy.get({policy_id:e}).$promise.then(function(e){t(o.transform(e,"action_assignments"))})}}}}angular.module("moon").factory("assignmentsService",e),e.$inject=["$resource","REST_URI","utilService"]}(),function(){"use strict";function e(e,t,o){var n={subject:{policy:e(t.POLICIES+":policy_id/subject_data/:subject_id/:category_id/:data_id",{},{get:{method:"GET"},create:{method:"POST"},remove:{method:"DELETE"}})},object:{policy:e(t.POLICIES+":policy_id/object_data/:object_id/:category_id/:data_id",{},{get:{method:"GET",isArray:!1},create:{method:"POST"},remove:{method:"DELETE"}})},action:{policy:e(t.POLICIES+":policy_id/action_data/:action_id/:category_id/:data_id",{},{get:{method:"GET",isArray:!1},create:{method:"POST"},remove:{method:"DELETE"}})}};return{subject:{findAllFromPolicyWithCallback:function(e,t){n.subject.policy.get({policy_id:e}).$promise.then(function(e){t(o.transform(e.subject_data[0],"data"))})},findAllFromCategoriesWithCallback:function(e,t,i){n.subject.policy.get({policy_id:e,category_id:t}).$promise.then(function(e){i(e.subject_data[0]?o.transform(e.subject_data[0],"data"):[])})},delete:function(e,t,o,i,c){n.subject.policy.remove({policy_id:t,category_id:o,data_id:e.id},e,i,c)},add:function(e,t,o,i,c){n.subject.policy.create({policy_id:t,category_id:o},e,i,c)},data:{findOne:function(e,t,i,c){n.subject.policy.get({policy_id:e,subject_id:t,data_id:i}).$promise.then(function(e){c(e.subject_data[0]?o.transformOne(e.subject_data[0],"data"):{})})}}},object:{findAllFromPolicyWithCallback:function(e,t){n.object.policy.get({policy_id:e}).$promise.then(function(e){t(o.transform(e.object_data[0],"data"))})},findAllFromCategoriesWithCallback:function(e,t,i){n.object.policy.get({policy_id:e,category_id:t}).$promise.then(function(e){i(e.object_data[0]?o.transform(e.object_data[0],"data"):[])})},delete:function(e,t,o,i,c){n.object.policy.remove({policy_id:t,category_id:o,data_id:e.id},e,i,c)},add:function(e,t,o,i,c){n.object.policy.create({policy_id:t,category_id:o},e,i,c)},data:{findOne:function(e,t,i,c){n.object.policy.get({policy_id:e,object_id:t,data_id:i}).$promise.then(function(e){c(e.object_data[0]?o.transformOne(e.object_data[0],"data"):{})})}}},action:{findAllFromPolicyWithCallback:function(e,t){n.action.policy.get({policy_id:e}).$promise.then(function(e){t(o.transform(e.action_data[0],"data"))})},findAllFromCategoriesWithCallback:function(e,t,i){n.action.policy.get({policy_id:e,category_id:t}).$promise.then(function(e){i(e.action_data[0]?o.transform(e.action_data[0],"data"):[])})},delete:function(e,t,o,i,c){n.action.policy.remove({policy_id:t,category_id:o,data_id:e.id},e,i,c)},add:function(e,t,o,i,c){n.action.policy.create({policy_id:t,category_id:o},e,i,c)},data:{
+findOne:function(e,t,i,c){n.action.policy.get({policy_id:e,action_id:t,data_id:i}).$promise.then(function(e){c(e.action_data[0]?o.transformOne(e.action_data[0],"data"):{})})}}}}}angular.module("moon").factory("dataService",e),e.$inject=["$resource","REST_URI","utilService"]}(),function(){"use strict";function e(e,t,o,n){var i={subject:{perimeter:e(t.PERIMETERS.subject+":subject_id",{},{get:{method:"GET",isArray:!1},create:{method:"POST"},remove:{method:"DELETE"},update:{method:"PATCH"}}),policy:e(t.POLICIES+":policy_id/subjects/:subject_id",{},{get:{method:"GET"},create:{method:"POST"},remove:{method:"DELETE"},update:{method:"PATCH"}})},object:{perimeter:e(t.PERIMETERS.object+":object_id",{},{get:{method:"GET",isArray:!1},create:{method:"POST"},remove:{method:"DELETE"},update:{method:"PATCH"}}),policy:e(t.POLICIES+":policy_id/objects/:object_id",{},{get:{method:"GET",isArray:!1},create:{method:"POST"},remove:{method:"DELETE"},update:{method:"PATCH"}})},action:{perimeter:e(t.PERIMETERS.action+":action_id",{},{get:{method:"GET",isArray:!1},create:{method:"POST"},remove:{method:"DELETE"},update:{method:"PATCH"}}),policy:e(t.POLICIES+":policy_id/actions/:action_id",{},{get:{method:"GET",isArray:!1},create:{method:"POST"},remove:{method:"DELETE"},update:{method:"PATCH"}})}};return{subject:{findOne:function(e,t){i.subject.perimeter.get({subject_id:e}).$promise.then(function(e){t(n.transformOne(e,"subjects"))})},findOneReturningPromise:function(e){return i.subject.perimeter.get({subject_id:e}).$promise},findSome:function(e){var t=this;if(0===e.length)return[];var i=_(e).map(function(e){return t.findOneReturningPromise(e)});return o.all(i).then(function(e){return _(e).map(function(e){return n.transformOne(e,"subjects")})})},unMapPerimeterFromPolicy:function(e,t,o,n){i.subject.policy.remove({policy_id:e,subject_id:t},{},o,n)},findAllFromPolicyWithCallback:function(e,t){i.subject.policy.get({policy_id:e}).$promise.then(function(e){t(n.transform(e,"subjects"))})},findOneFromPolicyWithCallback:function(e,t,o){i.subject.policy.get({policy_id:e,subject_id:t}).$promise.then(function(e){o(n.transformOne(e,"subjects"))})},findAll:function(){return i.subject.perimeter.get().$promise.then(function(e){return n.transform(e,"subjects")})},findAllWithCallback:function(e){return i.subject.perimeter.get().$promise.then(function(t){e(n.transform(t,"subjects"))})},delete:function(e,t,o){i.subject.perimeter.remove({subject_id:e.id},e,t,o)},add:function(e,t,o){i.subject.perimeter.create({},e,t,o)},update:function(e,t,o){i.subject.perimeter.update({subject_id:e.id},e,t,o)}},object:{findOne:function(e,t){i.object.perimeter.get({object_id:e}).$promise.then(function(e){t(n.transformOne(e,"objects"))})},findOneReturningPromise:function(e){return i.object.perimeter.get({object_id:e}).$promise},findSome:function(e){var t=this;if(0===e.length)return[];var i=_(e).map(function(e){return t.findOneReturningPromise(e)});return o.all(i).then(function(e){return _(e).map(function(e){return n.transformOne(e,"objects")})})},unMapPerimeterFromPolicy:function(e,t,o,n){i.object.policy.remove({policy_id:e,object_id:t},{},o,n)},findSomeWithCallback:function(e,t){var i=this;0===e.length&&t([]);var c=_(e).map(function(e){return i.findOneReturningPromise(e)});o.all(c).then(function(e){t(_(e).map(function(e){return n.transformOne(e,"objects")}))})},findAll:function(){return i.object.perimeter.get().$promise.then(function(e){return n.transform(e,"objects")})},findAllFromPolicyWithCallback:function(e,t){i.object.policy.get({policy_id:e}).$promise.then(function(e){t(n.transform(e,"objects"))})},findOneFromPolicyWithCallback:function(e,t,o){i.object.policy.get({policy_id:e,object_id:t}).$promise.then(function(e){o(n.transformOne(e,"objects"))})},findAllWithCallback:function(e){return i.object.perimeter.get().$promise.then(function(t){e(n.transform(t,"objects"))})},delete:function(e,t,o){i.object.perimeter.remove({object_id:e.id},e,t,o)},add:function(e,t,o){i.object.perimeter.create({},e,t,o)},update:function(e,t,o){i.object.perimeter.update({object_id:e.id},e,t,o)}},action:{findOne:function(e,t){i.action.perimeter.get({actionId:e}).$promise.then(function(e){t(n.transformOne(e,"actions"))})},findOneReturningPromise:function(e){return i.action.perimeter.get({actionId:e}).$promise},findSome:function(e){var t=this;if(0===e.length)return[];var i=_(e).map(function(e){return t.findOneReturningPromise(e)});return o.all(i).then(function(e){return _(e).map(function(e){return n.transformOne(e,"actions")})})},unMapPerimeterFromPolicy:function(e,t,o,n){i.action.policy.remove({policy_id:e,action_id:t},{},o,n)},findSomeWithCallback:function(e,t){var i=this;0===e.length&&t([]);var c=_(e).map(function(e){return i.findOneReturningPromise(e)});o.all(c).then(function(e){t(_(e).map(function(e){return n.transformOne(e,"actions")}))})},findAll:function(){return i.action.perimeter.get().$promise.then(function(e){return n.transform(e,"actions")})},findAllFromPolicyWithCallback:function(e,t){i.action.policy.get({policy_id:e}).$promise.then(function(e){t(n.transform(e,"actions"))})},findOneFromPolicyWithCallback:function(e,t,o){i.action.policy.get({policy_id:e,action_id:t}).$promise.then(function(e){o(n.transformOne(e,"actions"))})},findAllWithCallback:function(e){return i.action.perimeter.get().$promise.then(function(t){e(n.transform(t,"actions"))})},delete:function(e,t,o){i.action.perimeter.remove({action_id:e.id},e,t,o)},add:function(e,t,o){i.action.perimeter.create({},e,t,o)},update:function(e,t,o){i.action.perimeter.update({action_id:e.id},e,t,o)}}}}angular.module("moon").factory("perimeterService",e),e.$inject=["$resource","REST_URI","$q","utilService"]}(),function(){"use strict";function e(e,t,o){return{data:{policy:e(t.POLICIES+":policy_id/rules/:rule_id",{},{get:{method:"GET"},create:{method:"POST"},remove:{method:"DELETE"}})},findAllFromPolicyWithCallback:function(e,t){this.data.policy.get({policy_id:e}).$promise.then(function(e){console.log("ruleService - findAllFromPolicyWithCallback()"),console.log(e);var n=e.rules;console.log(JSON.stringify(n)),t(o.transform(n,"rules"))})}}}angular.module("moon").factory("ruleService",e),e.$inject=["$resource","REST_URI","utilService"]}(),function(){"use strict";function e(e,t,o){return{data:{policy:e(t.POLICIES+":policy_id/rules/:rule_id",{},{get:{method:"GET"},create:{method:"POST"},remove:{method:"DELETE"}})},add:function(e,t,o,n){this.data.policy.create({policy_id:t},e,o,n)},delete:function(e,t,o,n){this.data.policy.remove({policy_id:t,rule_id:e},{},o,n)},findAllFromPolicyWithCallback:function(e,t){this.data.policy.get({policy_id:e}).$promise.then(function(e){t(e.rules.rules)})}}}angular.module("moon").factory("rulesService",e),e.$inject=["$resource","REST_URI","utilService"]}(),function(){"use strict";function e(){return{templateUrl:"html/model/edit/metarules/action/mapping/metarules-add.tpl.html",bindToController:!0,controller:t,controllerAs:"add",scope:{metaRules:"="},restrict:"E",replace:!0}}function t(e,t,o,n,i,c){function r(){function r(t){var i=c.transformOne(t,"meta_rules");n("moon.model.metarules.add.success",{metaRuleName:i.name}).then(function(e){o.alertSuccess(e)}),a.loading=!1,e.$emit("event:metaRuleCreatedSuccess",i)}function l(t){n("moon.model.metarules.add.error",{metaRuleName:a.metaRule.name}).then(function(e){o.alertError(e)}),a.loading=!1,e.$emit("event:metaRuleCreatedError",a.project)}i.isInvalid(a.form)?i.checkFieldsValidity(a.form):(a.loading=!0,t.data.create({},a.metaRule,r,l))}var a=this;a.laoading=!1,a.form={},a.metaRule={name:null,description:null,subject_categories:[],object_categories:[],action_categories:[]},a.create=r}angular.module("moon").directive("moonMetaRulesAdd",e),e.$inject=[],angular.module("moon").controller("moonMetaRulesAddController",t),t.$inject=["$scope","metaRuleService","alertService","$translate","formService","utilService"]}(),function(){"use strict";function e(e,t,o,n,i,c,r,a){function l(){h.metaRulesLoading=!0,c.findAllWithCallback(function(e){h.metaRules=e,h.metaRulesLoading=!1})}function s(){function t(t){var i=a.transformOne(t,"models");c.findSomeWithMetaData(i.meta_rules).then(function(t){i.meta_rules_values=t,n("moon.model.metarules.map.success",{modelName:i.name,metaRuleName:h.selectedMetaRule.name}).then(function(e){o.alertSuccess(e)}),h.mappingLoading=!1,e.$emit("event:metaRuleMapToModelSuccess",i)})}function l(e){n("moon.model.metarules.map.error",{modelName:h.model.name,metaRuleName:h.selectedMetaRule.name}).then(function(e){o.alertError(e)}),h.mappingLoading=!1}if(i.isInvalid(h.form))i.checkFieldsValidity(h.form);else{h.mappingLoading=!0;var s=angular.copy(h.model);s.meta_rules.push(h.selectedMetaRule.id),r.update(s,t,l)}}function d(){delete h.selectedMetaRule}function u(){function t(t){n("moon.model.metarules.delete.success",{metaRuleName:r.name}).then(function(e){o.alertSuccess(e)}),d(),h.mappingLoading=!1,l(),e.$emit("event:deleteMetaRule",r)}function i(e){n("moon.model.metarules.delete.error",{metaRuleName:r.name}).then(function(e){o.alertError(e)}),h.mappingLoading=!1}if(h.selectedMetaRule){h.mappingLoading=!0;var r=angular.copy(h.selectedMetaRule);c.delete(r,t,i)}}function m(e,t){h.metaRules.push(t),f()}function p(e){}function f(){h.addMetaRuleToList=!1}var h=this;h.metaRules=[],h.model=e.model,h.addMetaRuleToList=!1,h.mapToModel=s,h.deleteMetaRule=u,function(){l()}();var g={"event:metaRuleCreatedSuccess":t.$on("event:metaRuleCreatedSuccess",m),"event:metaRuleCreatedError":t.$on("event:metaRuleCreatedError",p)};for(var y in g)e.$on("$destroy",g[y])}angular.module("moon").controller("moonMetaRulesMapController",e),e.$inject=["$scope","$rootScope","alertService","$translate","formService","metaRuleService","modelService","utilService"]}(),function(){"use strict";function e(e,t,o,n){function i(){function i(n){t("moon.model.metarules.unmap.success",{modelName:c.model.name,metaRuleName:c.metaRule.name}).then(function(e){o.alertSuccess(e)}),c.unMappingLoading=!1,e.$emit("event:metaRuleUnMappedToModelSuccess",a)}function r(n){t("moon.model.metarules.unmap.error",{modelName:c.model.name,metaRuleName:c.metaRule.name}).then(function(e){o.alertError(e)}),c.unMappingLoading=!1,e.$emit("event:metaRuleUnMappedToModelError")}c.unMappingLoading=!0;var a=angular.copy(c.model);a.meta_rules=_.without(a.meta_rules,c.metaRule.id),n.update(a,i,r)}var c=this;c.model=e.model,c.metaRule=e.metaRule,c.unMappingLoading=!1,c.unmap=i}angular.module("moon").controller("MetaRulesUnMapController",e),e.$inject=["$scope","$translate","alertService","modelService"]}(); \ No newline at end of file
diff --git a/old/moon_gui/delivery/js/modules.js b/old/moon_gui/delivery/js/modules.js
new file mode 100644
index 00000000..ec3b37a3
--- /dev/null
+++ b/old/moon_gui/delivery/js/modules.js
@@ -0,0 +1,20 @@
+function require(e,t,n){var i=require.resolve(e);if(null==i){n=n||e,t=t||"root";var r=new Error('Failed to require "'+n+'" from "'+t+'"');throw r.path=n,r.parent=t,r.require=!0,r}var o=require.modules[i];if(!o._resolving&&!o.exports){var a={};a.exports={},a.client=a.component=!0,o._resolving=!0,o.call(this,a.exports,require.relative(i),a),delete o._resolving,o.exports=a.exports}return o.exports}if(function(e,t){"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){function n(e){var t=e.length,n=J.type(e);return"function"!==n&&!J.isWindow(e)&&(!(1!==e.nodeType||!t)||("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e))}function i(e,t,n){if(J.isFunction(t))return J.grep(e,function(e,i){return!!t.call(e,i,e)!==n});if(t.nodeType)return J.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(ae.test(t))return J.filter(t,e,n);t=J.filter(t,e)}return J.grep(e,function(e){return z.call(t,e)>=0!==n})}function r(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}function o(e){var t=fe[e]={};return J.each(e.match(de)||[],function(e,n){t[n]=!0}),t}function a(){Z.removeEventListener("DOMContentLoaded",a,!1),e.removeEventListener("load",a,!1),J.ready()}function s(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=J.expando+Math.random()}function l(e,t,n){var i;if(void 0===n&&1===e.nodeType)if(i="data-"+t.replace($e,"-$1").toLowerCase(),"string"==typeof(n=e.getAttribute(i))){try{n="true"===n||"false"!==n&&("null"===n?null:+n+""===n?+n:ve.test(n)?J.parseJSON(n):n)}catch(e){}me.set(e,t,n)}else n=void 0;return n}function c(){return!0}function u(){return!1}function d(){try{return Z.activeElement}catch(e){}}function f(e,t){return J.nodeName(e,"table")&&J.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function p(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function h(e){var t=Pe.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function g(e,t){for(var n=0,i=e.length;n<i;n++)ge.set(e[n],"globalEval",!t||ge.get(t[n],"globalEval"))}function m(e,t){var n,i,r,o,a,s,l,c;if(1===t.nodeType){if(ge.hasData(e)&&(o=ge.access(e),a=ge.set(t,o),c=o.events)){delete a.handle,a.events={};for(r in c)for(n=0,i=c[r].length;n<i;n++)J.event.add(t,r,c[r][n])}me.hasData(e)&&(s=me.access(e),l=J.extend({},s),me.set(t,l))}}function v(e,t){var n=e.getElementsByTagName?e.getElementsByTagName(t||"*"):e.querySelectorAll?e.querySelectorAll(t||"*"):[];return void 0===t||t&&J.nodeName(e,t)?J.merge([e],n):n}function $(e,t){var n=t.nodeName.toLowerCase();"input"===n&&xe.test(e.type)?t.checked=e.checked:"input"!==n&&"textarea"!==n||(t.defaultValue=e.defaultValue)}function y(t,n){var i,r=J(n.createElement(t)).appendTo(n.body),o=e.getDefaultComputedStyle&&(i=e.getDefaultComputedStyle(r[0]))?i.display:J.css(r[0],"display");return r.detach(),o}function b(e){var t=Z,n=Le[e];return n||(n=y(e,t),"none"!==n&&n||(Fe=(Fe||J("<iframe frameborder='0' width='0' height='0'/>")).appendTo(t.documentElement),t=Fe[0].contentDocument,t.write(),t.close(),n=y(e,t),Fe.detach()),Le[e]=n),n}function w(e,t,n){var i,r,o,a,s=e.style;return n=n||He(e),n&&(a=n.getPropertyValue(t)||n[t]),n&&(""!==a||J.contains(e.ownerDocument,e)||(a=J.style(e,t)),Ve.test(a)&&Re.test(t)&&(i=s.width,r=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=i,s.minWidth=r,s.maxWidth=o)),void 0!==a?a+"":a}function x(e,t){return{get:function(){return e()?void delete this.get:(this.get=t).apply(this,arguments)}}}function C(e,t){if(t in e)return t;for(var n=t[0].toUpperCase()+t.slice(1),i=t,r=ze.length;r--;)if((t=ze[r]+n)in e)return t;return i}function k(e,t,n){var i=Ue.exec(t);return i?Math.max(0,i[1]-(n||0))+(i[2]||"px"):t}function S(e,t,n,i,r){for(var o=n===(i?"border":"content")?4:"width"===t?1:0,a=0;o<4;o+=2)"margin"===n&&(a+=J.css(e,n+be[o],!0,r)),i?("content"===n&&(a-=J.css(e,"padding"+be[o],!0,r)),"margin"!==n&&(a-=J.css(e,"border"+be[o]+"Width",!0,r))):(a+=J.css(e,"padding"+be[o],!0,r),"padding"!==n&&(a+=J.css(e,"border"+be[o]+"Width",!0,r)));return a}function E(e,t,n){var i=!0,r="width"===t?e.offsetWidth:e.offsetHeight,o=He(e),a="border-box"===J.css(e,"boxSizing",!1,o);if(r<=0||null==r){if(r=w(e,t,o),(r<0||null==r)&&(r=e.style[t]),Ve.test(r))return r;i=a&&(X.boxSizingReliable()||r===e.style[t]),r=parseFloat(r)||0}return r+S(e,t,n||(a?"border":"content"),i,o)+"px"}function T(e,t){for(var n,i,r,o=[],a=0,s=e.length;a<s;a++)i=e[a],i.style&&(o[a]=ge.get(i,"olddisplay"),n=i.style.display,t?(o[a]||"none"!==n||(i.style.display=""),""===i.style.display&&we(i)&&(o[a]=ge.access(i,"olddisplay",b(i.nodeName)))):(r=we(i),"none"===n&&r||ge.set(i,"olddisplay",r?n:J.css(i,"display"))));for(a=0;a<s;a++)i=e[a],i.style&&(t&&"none"!==i.style.display&&""!==i.style.display||(i.style.display=t?o[a]||"":"none"));return e}function D(e,t,n,i,r){return new D.prototype.init(e,t,n,i,r)}function A(){return setTimeout(function(){Ye=void 0}),Ye=J.now()}function M(e,t){var n,i=0,r={height:e};for(t=t?1:0;i<4;i+=2-t)n=be[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}function O(e,t,n){for(var i,r=(Qe[t]||[]).concat(Qe["*"]),o=0,a=r.length;o<a;o++)if(i=r[o].call(n,t,e))return i}function I(e,t,n){var i,r,o,a,s,l,c,u=this,d={},f=e.style,p=e.nodeType&&we(e),h=ge.get(e,"fxshow");n.queue||(s=J._queueHooks(e,"fx"),null==s.unqueued&&(s.unqueued=0,l=s.empty.fire,s.empty.fire=function(){s.unqueued||l()}),s.unqueued++,u.always(function(){u.always(function(){s.unqueued--,J.queue(e,"fx").length||s.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[f.overflow,f.overflowX,f.overflowY],c=J.css(e,"display"),"inline"===("none"===c?ge.get(e,"olddisplay")||b(e.nodeName):c)&&"none"===J.css(e,"float")&&(f.display="inline-block")),n.overflow&&(f.overflow="hidden",u.always(function(){f.overflow=n.overflow[0],f.overflowX=n.overflow[1],f.overflowY=n.overflow[2]}));for(i in t)if(r=t[i],Ge.exec(r)){if(delete t[i],o=o||"toggle"===r,r===(p?"hide":"show")){if("show"!==r||!h||void 0===h[i])continue;p=!0}d[i]=h&&h[i]||J.style(e,i)}else c=void 0;if(J.isEmptyObject(d))"inline"===("none"===c?b(e.nodeName):c)&&(f.display=c);else{h?"hidden"in h&&(p=h.hidden):h=ge.access(e,"fxshow",{}),o&&(h.hidden=!p),p?J(e).show():u.done(function(){J(e).hide()}),u.done(function(){var t;ge.remove(e,"fxshow");for(t in d)J.style(e,t,d[t])});for(i in d)a=O(p?h[i]:0,i,u),i in h||(h[i]=a.start,p&&(a.end=a.start,a.start="width"===i||"height"===i?1:0))}}function P(e,t){var n,i,r,o,a;for(n in e)if(i=J.camelCase(n),r=t[i],o=e[n],J.isArray(o)&&(r=o[1],o=e[n]=o[0]),n!==i&&(e[i]=o,delete e[n]),(a=J.cssHooks[i])&&"expand"in a){o=a.expand(o),delete e[i];for(n in o)n in e||(e[n]=o[n],t[n]=r)}else t[i]=r}function N(e,t,n){var i,r,o=0,a=Je.length,s=J.Deferred().always(function(){delete l.elem}),l=function(){if(r)return!1;for(var t=Ye||A(),n=Math.max(0,c.startTime+c.duration-t),i=n/c.duration||0,o=1-i,a=0,l=c.tweens.length;a<l;a++)c.tweens[a].run(o);return s.notifyWith(e,[c,o,n]),o<1&&l?n:(s.resolveWith(e,[c]),!1)},c=s.promise({elem:e,props:J.extend({},t),opts:J.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Ye||A(),duration:n.duration,tweens:[],createTween:function(t,n){var i=J.Tween(e,c.opts,t,n,c.opts.specialEasing[t]||c.opts.easing);return c.tweens.push(i),i},stop:function(t){var n=0,i=t?c.tweens.length:0;if(r)return this;for(r=!0;n<i;n++)c.tweens[n].run(1);return t?s.resolveWith(e,[c,t]):s.rejectWith(e,[c,t]),this}}),u=c.props;for(P(u,c.opts.specialEasing);o<a;o++)if(i=Je[o].call(c,e,u,c.opts))return i;return J.map(u,O,c),J.isFunction(c.opts.start)&&c.opts.start.call(e,c),J.fx.timer(J.extend(l,{elem:e,anim:c,queue:c.opts.queue})),c.progress(c.opts.progress).done(c.opts.done,c.opts.complete).fail(c.opts.fail).always(c.opts.always)}function j(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var i,r=0,o=t.toLowerCase().match(de)||[];if(J.isFunction(n))for(;i=o[r++];)"+"===i[0]?(i=i.slice(1)||"*",(e[i]=e[i]||[]).unshift(n)):(e[i]=e[i]||[]).push(n)}}function F(e,t,n,i){function r(s){var l;return o[s]=!0,J.each(e[s]||[],function(e,s){var c=s(t,n,i);return"string"!=typeof c||a||o[c]?a?!(l=c):void 0:(t.dataTypes.unshift(c),r(c),!1)}),l}var o={},a=e===vt;return r(t.dataTypes[0])||!o["*"]&&r("*")}function L(e,t){var n,i,r=J.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((r[n]?e:i||(i={}))[n]=t[n]);return i&&J.extend(!0,e,i),e}function R(e,t,n){for(var i,r,o,a,s=e.contents,l=e.dataTypes;"*"===l[0];)l.shift(),void 0===i&&(i=e.mimeType||t.getResponseHeader("Content-Type"));if(i)for(r in s)if(s[r]&&s[r].test(i)){l.unshift(r);break}if(l[0]in n)o=l[0];else{for(r in n){if(!l[0]||e.converters[r+" "+l[0]]){o=r;break}a||(a=r)}o=o||a}if(o)return o!==l[0]&&l.unshift(o),n[o]}function V(e,t,n,i){var r,o,a,s,l,c={},u=e.dataTypes.slice();if(u[1])for(a in e.converters)c[a.toLowerCase()]=e.converters[a];for(o=u.shift();o;)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!l&&i&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),l=o,o=u.shift())if("*"===o)o=l;else if("*"!==l&&l!==o){if(!(a=c[l+" "+o]||c["* "+o]))for(r in c)if(s=r.split(" "),s[1]===o&&(a=c[l+" "+s[0]]||c["* "+s[0]])){!0===a?a=c[r]:!0!==c[r]&&(o=s[0],u.unshift(s[1]));break}if(!0!==a)if(a&&e.throws)t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+l+" to "+o}}}return{state:"success",data:t}}function H(e,t,n,i){var r;if(J.isArray(t))J.each(t,function(t,r){n||bt.test(e)?i(e,r):H(e+"["+("object"==typeof r?t:"")+"]",r,n,i)});else if(n||"object"!==J.type(t))i(e,t);else for(r in t)H(e+"["+r+"]",t[r],n,i)}function q(e){return J.isWindow(e)?e:9===e.nodeType&&e.defaultView}var U=[],_=U.slice,B=U.concat,W=U.push,z=U.indexOf,Y={},K=Y.toString,G=Y.hasOwnProperty,X={},Z=e.document,J=function(e,t){return new J.fn.init(e,t)},Q=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,ee=/^-ms-/,te=/-([\da-z])/gi,ne=function(e,t){return t.toUpperCase()};J.fn=J.prototype={jquery:"2.1.1",constructor:J,selector:"",length:0,toArray:function(){return _.call(this)},get:function(e){return null!=e?e<0?this[e+this.length]:this[e]:_.call(this)},pushStack:function(e){var t=J.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return J.each(this,e,t)},map:function(e){return this.pushStack(J.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(_.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:W,sort:U.sort,splice:U.splice},J.extend=J.fn.extend=function(){var e,t,n,i,r,o,a=arguments[0]||{},s=1,l=arguments.length,c=!1;for("boolean"==typeof a&&(c=a,a=arguments[s]||{},s++),"object"==typeof a||J.isFunction(a)||(a={}),s===l&&(a=this,s--);s<l;s++)if(null!=(e=arguments[s]))for(t in e)n=a[t],i=e[t],a!==i&&(c&&i&&(J.isPlainObject(i)||(r=J.isArray(i)))?(r?(r=!1,o=n&&J.isArray(n)?n:[]):o=n&&J.isPlainObject(n)?n:{},a[t]=J.extend(c,o,i)):void 0!==i&&(a[t]=i));return a},J.extend({expando:"jQuery"+("2.1.1"+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isFunction:function(e){return"function"===J.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!J.isArray(e)&&e-parseFloat(e)>=0},isPlainObject:function(e){return"object"===J.type(e)&&!e.nodeType&&!J.isWindow(e)&&!(e.constructor&&!G.call(e.constructor.prototype,"isPrototypeOf"))},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?Y[K.call(e)]||"object":typeof e},globalEval:function(e){var t,n=eval;(e=J.trim(e))&&(1===e.indexOf("use strict")?(t=Z.createElement("script"),t.text=e,Z.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(ee,"ms-").replace(te,ne)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,i){var r=0,o=e.length,a=n(e);if(i){if(a)for(;r<o&&!1!==t.apply(e[r],i);r++);else for(r in e)if(!1===t.apply(e[r],i))break}else if(a)for(;r<o&&!1!==t.call(e[r],r,e[r]);r++);else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?"":(e+"").replace(Q,"")},makeArray:function(e,t){var i=t||[];return null!=e&&(n(Object(e))?J.merge(i,"string"==typeof e?[e]:e):W.call(i,e)),i},inArray:function(e,t,n){return null==t?-1:z.call(t,e,n)},merge:function(e,t){for(var n=+t.length,i=0,r=e.length;i<n;i++)e[r++]=t[i];return e.length=r,e},grep:function(e,t,n){for(var i=[],r=0,o=e.length,a=!n;r<o;r++)!t(e[r],r)!==a&&i.push(e[r]);return i},map:function(e,t,i){var r,o=0,a=e.length,s=n(e),l=[];if(s)for(;o<a;o++)null!=(r=t(e[o],o,i))&&l.push(r);else for(o in e)null!=(r=t(e[o],o,i))&&l.push(r);return B.apply([],l)},guid:1,proxy:function(e,t){var n,i,r;if("string"==typeof t&&(n=e[t],t=e,e=n),J.isFunction(e))return i=_.call(arguments,2),r=function(){return e.apply(t||this,i.concat(_.call(arguments)))},r.guid=e.guid=e.guid||J.guid++,r},now:Date.now,support:X}),J.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){Y["[object "+t+"]"]=t.toLowerCase()});var ie=function(e){function t(e,t,n,i){var r,o,a,s,c,d,f,p,h,g;if((t?t.ownerDocument||t:R)!==M&&A(t),t=t||M,n=n||[],!e||"string"!=typeof e)return n;if(1!==(s=t.nodeType)&&9!==s)return[];if(I&&!i){if(r=me.exec(e))if(a=r[1]){if(9===s){if(!(o=t.getElementById(a))||!o.parentNode)return n;if(o.id===a)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(a))&&F(t,o)&&o.id===a)return n.push(o),n}else{if(r[2])return Z.apply(n,t.getElementsByTagName(e)),n;if((a=r[3])&&y.getElementsByClassName&&t.getElementsByClassName)return Z.apply(n,t.getElementsByClassName(a)),n}if(y.qsa&&(!P||!P.test(e))){if(p=f=L,h=t,g=9===s&&e,1===s&&"object"!==t.nodeName.toLowerCase()){for(d=C(e),(f=t.getAttribute("id"))?p=f.replace($e,"\\$&"):t.setAttribute("id",p),p="[id='"+p+"'] ",c=d.length;c--;)d[c]=p+u(d[c]);h=ve.test(e)&&l(t.parentNode)||t,g=d.join(",")}if(g)try{return Z.apply(n,h.querySelectorAll(g)),n}catch(e){}finally{f||t.removeAttribute("id")}}}return S(e.replace(ae,"$1"),t,n,i)}function n(){function e(n,i){return t.push(n+" ")>b.cacheLength&&delete e[t.shift()],e[n+" "]=i}var t=[];return e}function i(e){return e[L]=!0,e}function r(e){var t=M.createElement("div");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function o(e,t){for(var n=e.split("|"),i=e.length;i--;)b.attrHandle[n[i]]=t}function a(e,t){var n=t&&e,i=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||z)-(~e.sourceIndex||z);if(i)return i;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function s(e){return i(function(t){return t=+t,i(function(n,i){for(var r,o=e([],n.length,t),a=o.length;a--;)n[r=o[a]]&&(n[r]=!(i[r]=n[r]))})})}function l(e){return e&&typeof e.getElementsByTagName!==W&&e}function c(){}function u(e){for(var t=0,n=e.length,i="";t<n;t++)i+=e[t].value;return i}function d(e,t,n){var i=t.dir,r=n&&"parentNode"===i,o=H++;return t.first?function(t,n,o){for(;t=t[i];)if(1===t.nodeType||r)return e(t,n,o)}:function(t,n,a){var s,l,c=[V,o];if(a){for(;t=t[i];)if((1===t.nodeType||r)&&e(t,n,a))return!0}else for(;t=t[i];)if(1===t.nodeType||r){if(l=t[L]||(t[L]={}),(s=l[i])&&s[0]===V&&s[1]===o)return c[2]=s[2];if(l[i]=c,c[2]=e(t,n,a))return!0}}}function f(e){return e.length>1?function(t,n,i){for(var r=e.length;r--;)if(!e[r](t,n,i))return!1;return!0}:e[0]}function p(e,n,i){for(var r=0,o=n.length;r<o;r++)t(e,n[r],i);return i}function h(e,t,n,i,r){for(var o,a=[],s=0,l=e.length,c=null!=t;s<l;s++)(o=e[s])&&(n&&!n(o,i,r)||(a.push(o),c&&t.push(s)));return a}function g(e,t,n,r,o,a){return r&&!r[L]&&(r=g(r)),o&&!o[L]&&(o=g(o,a)),i(function(i,a,s,l){var c,u,d,f=[],g=[],m=a.length,v=i||p(t||"*",s.nodeType?[s]:s,[]),$=!e||!i&&t?v:h(v,f,e,s,l),y=n?o||(i?e:m||r)?[]:a:$;if(n&&n($,y,s,l),r)for(c=h(y,g),r(c,[],s,l),u=c.length;u--;)(d=c[u])&&(y[g[u]]=!($[g[u]]=d));if(i){if(o||e){if(o){for(c=[],u=y.length;u--;)(d=y[u])&&c.push($[u]=d);o(null,y=[],c,l)}for(u=y.length;u--;)(d=y[u])&&(c=o?Q.call(i,d):f[u])>-1&&(i[c]=!(a[c]=d))}}else y=h(y===a?y.splice(m,y.length):y),o?o(null,a,y,l):Z.apply(a,y)})}function m(e){for(var t,n,i,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,l=d(function(e){return e===t},a,!0),c=d(function(e){return Q.call(t,e)>-1},a,!0),p=[function(e,n,i){return!o&&(i||n!==E)||((t=n).nodeType?l(e,n,i):c(e,n,i))}];s<r;s++)if(n=b.relative[e[s].type])p=[d(f(p),n)];else{if(n=b.filter[e[s].type].apply(null,e[s].matches),n[L]){for(i=++s;i<r&&!b.relative[e[i].type];i++);return g(s>1&&f(p),s>1&&u(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(ae,"$1"),n,s<i&&m(e.slice(s,i)),i<r&&m(e=e.slice(i)),i<r&&u(e))}p.push(n)}return f(p)}function v(e,n){var r=n.length>0,o=e.length>0,a=function(i,a,s,l,c){var u,d,f,p=0,g="0",m=i&&[],v=[],$=E,y=i||o&&b.find.TAG("*",c),w=V+=null==$?1:Math.random()||.1,x=y.length;for(c&&(E=a!==M&&a);g!==x&&null!=(u=y[g]);g++){if(o&&u){for(d=0;f=e[d++];)if(f(u,a,s)){l.push(u);break}c&&(V=w)}r&&((u=!f&&u)&&p--,i&&m.push(u))}if(p+=g,r&&g!==p){for(d=0;f=n[d++];)f(m,v,a,s);if(i){if(p>0)for(;g--;)m[g]||v[g]||(v[g]=G.call(l));v=h(v)}Z.apply(l,v),c&&!i&&v.length>0&&p+n.length>1&&t.uniqueSort(l)}return c&&(V=w,E=$),m};return r?i(a):a}var $,y,b,w,x,C,k,S,E,T,D,A,M,O,I,P,N,j,F,L="sizzle"+-new Date,R=e.document,V=0,H=0,q=n(),U=n(),_=n(),B=function(e,t){return e===t&&(D=!0),0},W="undefined",z=1<<31,Y={}.hasOwnProperty,K=[],G=K.pop,X=K.push,Z=K.push,J=K.slice,Q=K.indexOf||function(e){for(var t=0,n=this.length;t<n;t++)if(this[t]===e)return t;return-1},ee="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",te="[\\x20\\t\\r\\n\\f]",ne="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",ie=ne.replace("w","w#"),re="\\["+te+"*("+ne+")(?:"+te+"*([*^$|!~]?=)"+te+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+ie+"))|)"+te+"*\\]",oe=":("+ne+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+re+")*)|.*)\\)|)",ae=new RegExp("^"+te+"+|((?:^|[^\\\\])(?:\\\\.)*)"+te+"+$","g"),se=new RegExp("^"+te+"*,"+te+"*"),le=new RegExp("^"+te+"*([>+~]|"+te+")"+te+"*"),ce=new RegExp("="+te+"*([^\\]'\"]*?)"+te+"*\\]","g"),ue=new RegExp(oe),de=new RegExp("^"+ie+"$"),fe={ID:new RegExp("^#("+ne+")"),CLASS:new RegExp("^\\.("+ne+")"),TAG:new RegExp("^("+ne.replace("w","w*")+")"),ATTR:new RegExp("^"+re),PSEUDO:new RegExp("^"+oe),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+te+"*(even|odd|(([+-]|)(\\d*)n|)"+te+"*(?:([+-]|)"+te+"*(\\d+)|))"+te+"*\\)|)","i"),bool:new RegExp("^(?:"+ee+")$","i"),needsContext:new RegExp("^"+te+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+te+"*((?:-\\d)?\\d*)"+te+"*\\)|)(?=[^-]|$)","i")},pe=/^(?:input|select|textarea|button)$/i,he=/^h\d$/i,ge=/^[^{]+\{\s*\[native \w/,me=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ve=/[+~]/,$e=/'|\\/g,ye=new RegExp("\\\\([\\da-f]{1,6}"+te+"?|("+te+")|.)","ig"),be=function(e,t,n){var i="0x"+t-65536;return i!==i||n?t:i<0?String.fromCharCode(i+65536):String.fromCharCode(i>>10|55296,1023&i|56320)};try{Z.apply(K=J.call(R.childNodes),R.childNodes),K[R.childNodes.length].nodeType}catch(e){Z={apply:K.length?function(e,t){X.apply(e,J.call(t))}:function(e,t){for(var n=e.length,i=0;e[n++]=t[i++];);e.length=n-1}}}y=t.support={},x=t.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},A=t.setDocument=function(e){var t,n=e?e.ownerDocument||e:R,i=n.defaultView;return n!==M&&9===n.nodeType&&n.documentElement?(M=n,O=n.documentElement,I=!x(n),i&&i!==i.top&&(i.addEventListener?i.addEventListener("unload",function(){A()},!1):i.attachEvent&&i.attachEvent("onunload",function(){A()})),y.attributes=r(function(e){return e.className="i",!e.getAttribute("className")}),y.getElementsByTagName=r(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),y.getElementsByClassName=ge.test(n.getElementsByClassName)&&r(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),y.getById=r(function(e){return O.appendChild(e).id=L,!n.getElementsByName||!n.getElementsByName(L).length}),y.getById?(b.find.ID=function(e,t){if(typeof t.getElementById!==W&&I){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},b.filter.ID=function(e){var t=e.replace(ye,be);return function(e){return e.getAttribute("id")===t}}):(delete b.find.ID,b.filter.ID=function(e){var t=e.replace(ye,be);return function(e){var n=typeof e.getAttributeNode!==W&&e.getAttributeNode("id");return n&&n.value===t}}),b.find.TAG=y.getElementsByTagName?function(e,t){if(typeof t.getElementsByTagName!==W)return t.getElementsByTagName(e)}:function(e,t){var n,i=[],r=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[r++];)1===n.nodeType&&i.push(n);return i}return o},b.find.CLASS=y.getElementsByClassName&&function(e,t){if(typeof t.getElementsByClassName!==W&&I)return t.getElementsByClassName(e)},N=[],P=[],(y.qsa=ge.test(n.querySelectorAll))&&(r(function(e){e.innerHTML="<select msallowclip=''><option selected=''></option></select>",e.querySelectorAll("[msallowclip^='']").length&&P.push("[*^$]="+te+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||P.push("\\["+te+"*(?:value|"+ee+")"),e.querySelectorAll(":checked").length||P.push(":checked")}),r(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&P.push("name"+te+"*[*^$|!~]?="),e.querySelectorAll(":enabled").length||P.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),P.push(",.*:")})),(y.matchesSelector=ge.test(j=O.matches||O.webkitMatchesSelector||O.mozMatchesSelector||O.oMatchesSelector||O.msMatchesSelector))&&r(function(e){y.disconnectedMatch=j.call(e,"div"),j.call(e,"[s!='']:x"),N.push("!=",oe)}),P=P.length&&new RegExp(P.join("|")),N=N.length&&new RegExp(N.join("|")),t=ge.test(O.compareDocumentPosition),F=t||ge.test(O.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,i=t&&t.parentNode;return e===i||!(!i||1!==i.nodeType||!(n.contains?n.contains(i):e.compareDocumentPosition&&16&e.compareDocumentPosition(i)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},B=t?function(e,t){if(e===t)return D=!0,0;var i=!e.compareDocumentPosition-!t.compareDocumentPosition;return i||(i=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1,1&i||!y.sortDetached&&t.compareDocumentPosition(e)===i?e===n||e.ownerDocument===R&&F(R,e)?-1:t===n||t.ownerDocument===R&&F(R,t)?1:T?Q.call(T,e)-Q.call(T,t):0:4&i?-1:1)}:function(e,t){if(e===t)return D=!0,0;var i,r=0,o=e.parentNode,s=t.parentNode,l=[e],c=[t];if(!o||!s)return e===n?-1:t===n?1:o?-1:s?1:T?Q.call(T,e)-Q.call(T,t):0;if(o===s)return a(e,t);for(i=e;i=i.parentNode;)l.unshift(i);for(i=t;i=i.parentNode;)c.unshift(i);for(;l[r]===c[r];)r++;return r?a(l[r],c[r]):l[r]===R?-1:c[r]===R?1:0},n):M},t.matches=function(e,n){return t(e,null,null,n)},t.matchesSelector=function(e,n){if((e.ownerDocument||e)!==M&&A(e),n=n.replace(ce,"='$1']"),y.matchesSelector&&I&&(!N||!N.test(n))&&(!P||!P.test(n)))try{var i=j.call(e,n);if(i||y.disconnectedMatch||e.document&&11!==e.document.nodeType)return i}catch(e){}return t(n,M,null,[e]).length>0},t.contains=function(e,t){return(e.ownerDocument||e)!==M&&A(e),F(e,t)},t.attr=function(e,t){(e.ownerDocument||e)!==M&&A(e);var n=b.attrHandle[t.toLowerCase()],i=n&&Y.call(b.attrHandle,t.toLowerCase())?n(e,t,!I):void 0;return void 0!==i?i:y.attributes||!I?e.getAttribute(t):(i=e.getAttributeNode(t))&&i.specified?i.value:null},t.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},t.uniqueSort=function(e){var t,n=[],i=0,r=0;if(D=!y.detectDuplicates,T=!y.sortStable&&e.slice(0),e.sort(B),D){for(;t=e[r++];)t===e[r]&&(i=n.push(r));for(;i--;)e.splice(n[i],1)}return T=null,e},w=t.getText=function(e){var t,n="",i=0,r=e.nodeType;if(r){if(1===r||9===r||11===r){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=w(e)}else if(3===r||4===r)return e.nodeValue}else for(;t=e[i++];)n+=w(t);return n},b=t.selectors={cacheLength:50,createPseudo:i,match:fe,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(ye,be),e[3]=(e[3]||e[4]||e[5]||"").replace(ye,be),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||t.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&t.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return fe.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&ue.test(n)&&(t=C(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(ye,be).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=q[e+" "];return t||(t=new RegExp("(^|"+te+")"+e+"("+te+"|$)"))&&q(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==W&&e.getAttribute("class")||"")})},ATTR:function(e,n,i){return function(r){var o=t.attr(r,e);return null==o?"!="===n:!n||(o+="","="===n?o===i:"!="===n?o!==i:"^="===n?i&&0===o.indexOf(i):"*="===n?i&&o.indexOf(i)>-1:"$="===n?i&&o.slice(-i.length)===i:"~="===n?(" "+o+" ").indexOf(i)>-1:"|="===n&&(o===i||o.slice(0,i.length+1)===i+"-"))}},CHILD:function(e,t,n,i,r){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===i&&0===r?function(e){return!!e.parentNode}:function(t,n,l){var c,u,d,f,p,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,v=s&&t.nodeName.toLowerCase(),$=!l&&!s;if(m){if(o){for(;g;){for(d=t;d=d[g];)if(s?d.nodeName.toLowerCase()===v:1===d.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&$){for(u=m[L]||(m[L]={}),c=u[e]||[],p=c[0]===V&&c[1],f=c[0]===V&&c[2],d=p&&m.childNodes[p];d=++p&&d&&d[g]||(f=p=0)||h.pop();)if(1===d.nodeType&&++f&&d===t){u[e]=[V,p,f];break}}else if($&&(c=(t[L]||(t[L]={}))[e])&&c[0]===V)f=c[1];else for(;(d=++p&&d&&d[g]||(f=p=0)||h.pop())&&((s?d.nodeName.toLowerCase()!==v:1!==d.nodeType)||!++f||($&&((d[L]||(d[L]={}))[e]=[V,f]),d!==t)););return(f-=r)===i||f%i==0&&f/i>=0}}},PSEUDO:function(e,n){var r,o=b.pseudos[e]||b.setFilters[e.toLowerCase()]||t.error("unsupported pseudo: "+e);return o[L]?o(n):o.length>1?(r=[e,e,"",n],b.setFilters.hasOwnProperty(e.toLowerCase())?i(function(e,t){for(var i,r=o(e,n),a=r.length;a--;)i=Q.call(e,r[a]),e[i]=!(t[i]=r[a])}):function(e){return o(e,0,r)}):o}},pseudos:{not:i(function(e){var t=[],n=[],r=k(e.replace(ae,"$1"));return r[L]?i(function(e,t,n,i){for(var o,a=r(e,null,i,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:i(function(e){return function(n){return t(e,n).length>0}}),contains:i(function(e){return function(t){return(t.textContent||t.innerText||w(t)).indexOf(e)>-1}}),lang:i(function(e){return de.test(e||"")||t.error("unsupported lang: "+e),e=e.replace(ye,be).toLowerCase(),function(t){var n;do{if(n=I?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===O},focus:function(e){return e===M.activeElement&&(!M.hasFocus||M.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return!1===e.disabled},disabled:function(e){return!0===e.disabled},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return he.test(e.nodeName)},input:function(e){return pe.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:s(function(){return[0]}),last:s(function(e,t){return[t-1]}),eq:s(function(e,t,n){return[n<0?n+t:n]}),even:s(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:s(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:s(function(e,t,n){for(var i=n<0?n+t:n;--i>=0;)e.push(i);return e}),gt:s(function(e,t,n){for(var i=n<0?n+t:n;++i<t;)e.push(i);return e})}},b.pseudos.nth=b.pseudos.eq;for($ in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[$]=function(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}($);for($ in{submit:!0,reset:!0})b.pseudos[$]=function(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}($);return c.prototype=b.filters=b.pseudos,b.setFilters=new c,C=t.tokenize=function(e,n){var i,r,o,a,s,l,c,u=U[e+" "];if(u)return n?0:u.slice(0);for(s=e,l=[],c=b.preFilter;s;){i&&!(r=se.exec(s))||(r&&(s=s.slice(r[0].length)||s),l.push(o=[])),i=!1,(r=le.exec(s))&&(i=r.shift(),o.push({value:i,type:r[0].replace(ae," ")}),s=s.slice(i.length));for(a in b.filter)!(r=fe[a].exec(s))||c[a]&&!(r=c[a](r))||(i=r.shift(),o.push({value:i,type:a,matches:r}),s=s.slice(i.length));if(!i)break}return n?s.length:s?t.error(e):U(e,l).slice(0)},k=t.compile=function(e,t){var n,i=[],r=[],o=_[e+" "];if(!o){for(t||(t=C(e)),n=t.length;n--;)o=m(t[n]),o[L]?i.push(o):r.push(o);o=_(e,v(r,i)),o.selector=e}return o},S=t.select=function(e,t,n,i){var r,o,a,s,c,d="function"==typeof e&&e,f=!i&&C(e=d.selector||e);if(n=n||[],1===f.length){if(o=f[0]=f[0].slice(0),o.length>2&&"ID"===(a=o[0]).type&&y.getById&&9===t.nodeType&&I&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(ye,be),t)||[])[0]))return n;d&&(t=t.parentNode),e=e.slice(o.shift().value.length)}for(r=fe.needsContext.test(e)?0:o.length;r--&&(a=o[r],!b.relative[s=a.type]);)if((c=b.find[s])&&(i=c(a.matches[0].replace(ye,be),ve.test(o[0].type)&&l(t.parentNode)||t))){if(o.splice(r,1),!(e=i.length&&u(o)))return Z.apply(n,i),n;break}}return(d||k(e,f))(i,t,!I,n,ve.test(e)&&l(t.parentNode)||t),n},y.sortStable=L.split("").sort(B).join("")===L,y.detectDuplicates=!!D,A(),y.sortDetached=r(function(e){return 1&e.compareDocumentPosition(M.createElement("div"))}),r(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||o("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),y.attributes&&r(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||o("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),r(function(e){return null==e.getAttribute("disabled")})||o(ee,function(e,t,n){var i;if(!n)return!0===e[t]?t.toLowerCase():(i=e.getAttributeNode(t))&&i.specified?i.value:null}),t}(e);J.find=ie,J.expr=ie.selectors,J.expr[":"]=J.expr.pseudos,J.unique=ie.uniqueSort,J.text=ie.getText,J.isXMLDoc=ie.isXML,J.contains=ie.contains;var re=J.expr.match.needsContext,oe=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,ae=/^.[^:#\[\.,]*$/
+;J.filter=function(e,t,n){var i=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===i.nodeType?J.find.matchesSelector(i,e)?[i]:[]:J.find.matches(e,J.grep(t,function(e){return 1===e.nodeType}))},J.fn.extend({find:function(e){var t,n=this.length,i=[],r=this;if("string"!=typeof e)return this.pushStack(J(e).filter(function(){for(t=0;t<n;t++)if(J.contains(r[t],this))return!0}));for(t=0;t<n;t++)J.find(e,r[t],i);return i=this.pushStack(n>1?J.unique(i):i),i.selector=this.selector?this.selector+" "+e:e,i},filter:function(e){return this.pushStack(i(this,e||[],!1))},not:function(e){return this.pushStack(i(this,e||[],!0))},is:function(e){return!!i(this,"string"==typeof e&&re.test(e)?J(e):e||[],!1).length}});var se,le=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/;(J.fn.init=function(e,t){var n,i;if(!e)return this;if("string"==typeof e){if(!(n="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:le.exec(e))||!n[1]&&t)return!t||t.jquery?(t||se).find(e):this.constructor(t).find(e);if(n[1]){if(t=t instanceof J?t[0]:t,J.merge(this,J.parseHTML(n[1],t&&t.nodeType?t.ownerDocument||t:Z,!0)),oe.test(n[1])&&J.isPlainObject(t))for(n in t)J.isFunction(this[n])?this[n](t[n]):this.attr(n,t[n]);return this}return i=Z.getElementById(n[2]),i&&i.parentNode&&(this.length=1,this[0]=i),this.context=Z,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):J.isFunction(e)?void 0!==se.ready?se.ready(e):e(J):(void 0!==e.selector&&(this.selector=e.selector,this.context=e.context),J.makeArray(e,this))}).prototype=J.fn,se=J(Z);var ce=/^(?:parents|prev(?:Until|All))/,ue={children:!0,contents:!0,next:!0,prev:!0};J.extend({dir:function(e,t,n){for(var i=[],r=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(r&&J(e).is(n))break;i.push(e)}return i},sibling:function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}}),J.fn.extend({has:function(e){var t=J(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(J.contains(this,t[e]))return!0})},closest:function(e,t){for(var n,i=0,r=this.length,o=[],a=re.test(e)||"string"!=typeof e?J(e,t||this.context):0;i<r;i++)for(n=this[i];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?a.index(n)>-1:1===n.nodeType&&J.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?J.unique(o):o)},index:function(e){return e?"string"==typeof e?z.call(J(e),this[0]):z.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(J.unique(J.merge(this.get(),J(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),J.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return J.dir(e,"parentNode")},parentsUntil:function(e,t,n){return J.dir(e,"parentNode",n)},next:function(e){return r(e,"nextSibling")},prev:function(e){return r(e,"previousSibling")},nextAll:function(e){return J.dir(e,"nextSibling")},prevAll:function(e){return J.dir(e,"previousSibling")},nextUntil:function(e,t,n){return J.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return J.dir(e,"previousSibling",n)},siblings:function(e){return J.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return J.sibling(e.firstChild)},contents:function(e){return e.contentDocument||J.merge([],e.childNodes)}},function(e,t){J.fn[e]=function(n,i){var r=J.map(this,t,n);return"Until"!==e.slice(-5)&&(i=n),i&&"string"==typeof i&&(r=J.filter(i,r)),this.length>1&&(ue[e]||J.unique(r),ce.test(e)&&r.reverse()),this.pushStack(r)}});var de=/\S+/g,fe={};J.Callbacks=function(e){e="string"==typeof e?fe[e]||o(e):J.extend({},e);var t,n,i,r,a,s,l=[],c=!e.once&&[],u=function(o){for(t=e.memory&&o,n=!0,s=r||0,r=0,a=l.length,i=!0;l&&s<a;s++)if(!1===l[s].apply(o[0],o[1])&&e.stopOnFalse){t=!1;break}i=!1,l&&(c?c.length&&u(c.shift()):t?l=[]:d.disable())},d={add:function(){if(l){var n=l.length;!function t(n){J.each(n,function(n,i){var r=J.type(i);"function"===r?e.unique&&d.has(i)||l.push(i):i&&i.length&&"string"!==r&&t(i)})}(arguments),i?a=l.length:t&&(r=n,u(t))}return this},remove:function(){return l&&J.each(arguments,function(e,t){for(var n;(n=J.inArray(t,l,n))>-1;)l.splice(n,1),i&&(n<=a&&a--,n<=s&&s--)}),this},has:function(e){return e?J.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],a=0,this},disable:function(){return l=c=t=void 0,this},disabled:function(){return!l},lock:function(){return c=void 0,t||d.disable(),this},locked:function(){return!c},fireWith:function(e,t){return!l||n&&!c||(t=t||[],t=[e,t.slice?t.slice():t],i?c.push(t):u(t)),this},fire:function(){return d.fireWith(this,arguments),this},fired:function(){return!!n}};return d},J.extend({Deferred:function(e){var t=[["resolve","done",J.Callbacks("once memory"),"resolved"],["reject","fail",J.Callbacks("once memory"),"rejected"],["notify","progress",J.Callbacks("memory")]],n="pending",i={state:function(){return n},always:function(){return r.done(arguments).fail(arguments),this},then:function(){var e=arguments;return J.Deferred(function(n){J.each(t,function(t,o){var a=J.isFunction(e[t])&&e[t];r[o[1]](function(){var e=a&&a.apply(this,arguments);e&&J.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[o[0]+"With"](this===i?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?J.extend(e,i):i}},r={};return i.pipe=i.then,J.each(t,function(e,o){var a=o[2],s=o[3];i[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),r[o[0]]=function(){return r[o[0]+"With"](this===r?i:this,arguments),this},r[o[0]+"With"]=a.fireWith}),i.promise(r),e&&e.call(r,r),r},when:function(e){var t,n,i,r=0,o=_.call(arguments),a=o.length,s=1!==a||e&&J.isFunction(e.promise)?a:0,l=1===s?e:J.Deferred(),c=function(e,n,i){return function(r){n[e]=this,i[e]=arguments.length>1?_.call(arguments):r,i===t?l.notifyWith(n,i):--s||l.resolveWith(n,i)}};if(a>1)for(t=new Array(a),n=new Array(a),i=new Array(a);r<a;r++)o[r]&&J.isFunction(o[r].promise)?o[r].promise().done(c(r,i,o)).fail(l.reject).progress(c(r,n,t)):--s;return s||l.resolveWith(i,o),l.promise()}});var pe;J.fn.ready=function(e){return J.ready.promise().done(e),this},J.extend({isReady:!1,readyWait:1,holdReady:function(e){e?J.readyWait++:J.ready(!0)},ready:function(e){(!0===e?--J.readyWait:J.isReady)||(J.isReady=!0,!0!==e&&--J.readyWait>0||(pe.resolveWith(Z,[J]),J.fn.triggerHandler&&(J(Z).triggerHandler("ready"),J(Z).off("ready"))))}}),J.ready.promise=function(t){return pe||(pe=J.Deferred(),"complete"===Z.readyState?setTimeout(J.ready):(Z.addEventListener("DOMContentLoaded",a,!1),e.addEventListener("load",a,!1))),pe.promise(t)},J.ready.promise();var he=J.access=function(e,t,n,i,r,o,a){var s=0,l=e.length,c=null==n;if("object"===J.type(n)){r=!0;for(s in n)J.access(e,t,s,n[s],!0,o,a)}else if(void 0!==i&&(r=!0,J.isFunction(i)||(a=!0),c&&(a?(t.call(e,i),t=null):(c=t,t=function(e,t,n){return c.call(J(e),n)})),t))for(;s<l;s++)t(e[s],n,a?i:i.call(e[s],s,t(e[s],n)));return r?e:c?t.call(e):l?t(e[0],n):o};J.acceptData=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType},s.uid=1,s.accepts=J.acceptData,s.prototype={key:function(e){if(!s.accepts(e))return 0;var t={},n=e[this.expando];if(!n){n=s.uid++;try{t[this.expando]={value:n},Object.defineProperties(e,t)}catch(i){t[this.expando]=n,J.extend(e,t)}}return this.cache[n]||(this.cache[n]={}),n},set:function(e,t,n){var i,r=this.key(e),o=this.cache[r];if("string"==typeof t)o[t]=n;else if(J.isEmptyObject(o))J.extend(this.cache[r],t);else for(i in t)o[i]=t[i];return o},get:function(e,t){var n=this.cache[this.key(e)];return void 0===t?n:n[t]},access:function(e,t,n){var i;return void 0===t||t&&"string"==typeof t&&void 0===n?(i=this.get(e,t),void 0!==i?i:this.get(e,J.camelCase(t))):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,i,r,o=this.key(e),a=this.cache[o];if(void 0===t)this.cache[o]={};else{J.isArray(t)?i=t.concat(t.map(J.camelCase)):(r=J.camelCase(t),t in a?i=[t,r]:(i=r,i=i in a?[i]:i.match(de)||[])),n=i.length;for(;n--;)delete a[i[n]]}},hasData:function(e){return!J.isEmptyObject(this.cache[e[this.expando]]||{})},discard:function(e){e[this.expando]&&delete this.cache[e[this.expando]]}};var ge=new s,me=new s,ve=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,$e=/([A-Z])/g;J.extend({hasData:function(e){return me.hasData(e)||ge.hasData(e)},data:function(e,t,n){return me.access(e,t,n)},removeData:function(e,t){me.remove(e,t)},_data:function(e,t,n){return ge.access(e,t,n)},_removeData:function(e,t){ge.remove(e,t)}}),J.fn.extend({data:function(e,t){var n,i,r,o=this[0],a=o&&o.attributes;if(void 0===e){if(this.length&&(r=me.get(o),1===o.nodeType&&!ge.get(o,"hasDataAttrs"))){for(n=a.length;n--;)a[n]&&(i=a[n].name,0===i.indexOf("data-")&&(i=J.camelCase(i.slice(5)),l(o,i,r[i])));ge.set(o,"hasDataAttrs",!0)}return r}return"object"==typeof e?this.each(function(){me.set(this,e)}):he(this,function(t){var n,i=J.camelCase(e);if(o&&void 0===t){if(void 0!==(n=me.get(o,e)))return n;if(void 0!==(n=me.get(o,i)))return n;if(void 0!==(n=l(o,i,void 0)))return n}else this.each(function(){var n=me.get(this,i);me.set(this,i,t),-1!==e.indexOf("-")&&void 0!==n&&me.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){me.remove(this,e)})}}),J.extend({queue:function(e,t,n){var i;if(e)return t=(t||"fx")+"queue",i=ge.get(e,t),n&&(!i||J.isArray(n)?i=ge.access(e,t,J.makeArray(n)):i.push(n)),i||[]},dequeue:function(e,t){t=t||"fx";var n=J.queue(e,t),i=n.length,r=n.shift(),o=J._queueHooks(e,t),a=function(){J.dequeue(e,t)};"inprogress"===r&&(r=n.shift(),i--),r&&("fx"===t&&n.unshift("inprogress"),delete o.stop,r.call(e,a,o)),!i&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return ge.get(e,n)||ge.access(e,n,{empty:J.Callbacks("once memory").add(function(){ge.remove(e,[t+"queue",n])})})}}),J.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length<n?J.queue(this[0],e):void 0===t?this:this.each(function(){var n=J.queue(this,e,t);J._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&J.dequeue(this,e)})},dequeue:function(e){return this.each(function(){J.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,i=1,r=J.Deferred(),o=this,a=this.length,s=function(){--i||r.resolveWith(o,[o])};for("string"!=typeof e&&(t=e,e=void 0),e=e||"fx";a--;)(n=ge.get(o[a],e+"queueHooks"))&&n.empty&&(i++,n.empty.add(s));return s(),r.promise(t)}});var ye=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,be=["Top","Right","Bottom","Left"],we=function(e,t){return e=t||e,"none"===J.css(e,"display")||!J.contains(e.ownerDocument,e)},xe=/^(?:checkbox|radio)$/i;!function(){var e=Z.createDocumentFragment(),t=e.appendChild(Z.createElement("div")),n=Z.createElement("input");n.setAttribute("type","radio"),n.setAttribute("checked","checked"),n.setAttribute("name","t"),t.appendChild(n),X.checkClone=t.cloneNode(!0).cloneNode(!0).lastChild.checked,t.innerHTML="<textarea>x</textarea>",X.noCloneChecked=!!t.cloneNode(!0).lastChild.defaultValue}();X.focusinBubbles="onfocusin"in e;var Ce=/^key/,ke=/^(?:mouse|pointer|contextmenu)|click/,Se=/^(?:focusinfocus|focusoutblur)$/,Ee=/^([^.]*)(?:\.(.+)|)$/;J.event={global:{},add:function(e,t,n,i,r){var o,a,s,l,c,u,d,f,p,h,g,m=ge.get(e);if(m)for(n.handler&&(o=n,n=o.handler,r=o.selector),n.guid||(n.guid=J.guid++),(l=m.events)||(l=m.events={}),(a=m.handle)||(a=m.handle=function(t){return void 0!==J&&J.event.triggered!==t.type?J.event.dispatch.apply(e,arguments):void 0}),t=(t||"").match(de)||[""],c=t.length;c--;)s=Ee.exec(t[c])||[],p=g=s[1],h=(s[2]||"").split(".").sort(),p&&(d=J.event.special[p]||{},p=(r?d.delegateType:d.bindType)||p,d=J.event.special[p]||{},u=J.extend({type:p,origType:g,data:i,handler:n,guid:n.guid,selector:r,needsContext:r&&J.expr.match.needsContext.test(r),namespace:h.join(".")},o),(f=l[p])||(f=l[p]=[],f.delegateCount=0,d.setup&&!1!==d.setup.call(e,i,h,a)||e.addEventListener&&e.addEventListener(p,a,!1)),d.add&&(d.add.call(e,u),u.handler.guid||(u.handler.guid=n.guid)),r?f.splice(f.delegateCount++,0,u):f.push(u),J.event.global[p]=!0)},remove:function(e,t,n,i,r){var o,a,s,l,c,u,d,f,p,h,g,m=ge.hasData(e)&&ge.get(e);if(m&&(l=m.events)){for(t=(t||"").match(de)||[""],c=t.length;c--;)if(s=Ee.exec(t[c])||[],p=g=s[1],h=(s[2]||"").split(".").sort(),p){for(d=J.event.special[p]||{},p=(i?d.delegateType:d.bindType)||p,f=l[p]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=f.length;o--;)u=f[o],!r&&g!==u.origType||n&&n.guid!==u.guid||s&&!s.test(u.namespace)||i&&i!==u.selector&&("**"!==i||!u.selector)||(f.splice(o,1),u.selector&&f.delegateCount--,d.remove&&d.remove.call(e,u));a&&!f.length&&(d.teardown&&!1!==d.teardown.call(e,h,m.handle)||J.removeEvent(e,p,m.handle),delete l[p])}else for(p in l)J.event.remove(e,p+t[c],n,i,!0);J.isEmptyObject(l)&&(delete m.handle,ge.remove(e,"events"))}},trigger:function(t,n,i,r){var o,a,s,l,c,u,d,f=[i||Z],p=G.call(t,"type")?t.type:t,h=G.call(t,"namespace")?t.namespace.split("."):[];if(a=s=i=i||Z,3!==i.nodeType&&8!==i.nodeType&&!Se.test(p+J.event.triggered)&&(p.indexOf(".")>=0&&(h=p.split("."),p=h.shift(),h.sort()),c=p.indexOf(":")<0&&"on"+p,t=t[J.expando]?t:new J.Event(p,"object"==typeof t&&t),t.isTrigger=r?2:3,t.namespace=h.join("."),t.namespace_re=t.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:J.makeArray(n,[t]),d=J.event.special[p]||{},r||!d.trigger||!1!==d.trigger.apply(i,n))){if(!r&&!d.noBubble&&!J.isWindow(i)){for(l=d.delegateType||p,Se.test(l+p)||(a=a.parentNode);a;a=a.parentNode)f.push(a),s=a;s===(i.ownerDocument||Z)&&f.push(s.defaultView||s.parentWindow||e)}for(o=0;(a=f[o++])&&!t.isPropagationStopped();)t.type=o>1?l:d.bindType||p,u=(ge.get(a,"events")||{})[t.type]&&ge.get(a,"handle"),u&&u.apply(a,n),(u=c&&a[c])&&u.apply&&J.acceptData(a)&&(t.result=u.apply(a,n),!1===t.result&&t.preventDefault());return t.type=p,r||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(f.pop(),n)||!J.acceptData(i)||c&&J.isFunction(i[p])&&!J.isWindow(i)&&(s=i[c],s&&(i[c]=null),J.event.triggered=p,i[p](),J.event.triggered=void 0,s&&(i[c]=s)),t.result}},dispatch:function(e){e=J.event.fix(e);var t,n,i,r,o,a=[],s=_.call(arguments),l=(ge.get(this,"events")||{})[e.type]||[],c=J.event.special[e.type]||{};if(s[0]=e,e.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,e)){for(a=J.event.handlers.call(this,e,l),t=0;(r=a[t++])&&!e.isPropagationStopped();)for(e.currentTarget=r.elem,n=0;(o=r.handlers[n++])&&!e.isImmediatePropagationStopped();)e.namespace_re&&!e.namespace_re.test(o.namespace)||(e.handleObj=o,e.data=o.data,void 0!==(i=((J.event.special[o.origType]||{}).handle||o.handler).apply(r.elem,s))&&!1===(e.result=i)&&(e.preventDefault(),e.stopPropagation()));return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,i,r,o,a=[],s=t.delegateCount,l=e.target;if(s&&l.nodeType&&(!e.button||"click"!==e.type))for(;l!==this;l=l.parentNode||this)if(!0!==l.disabled||"click"!==e.type){for(i=[],n=0;n<s;n++)o=t[n],r=o.selector+" ",void 0===i[r]&&(i[r]=o.needsContext?J(r,this).index(l)>=0:J.find(r,this,null,[l]).length),i[r]&&i.push(o);i.length&&a.push({elem:l,handlers:i})}return s<t.length&&a.push({elem:this,handlers:t.slice(s)}),a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,t){var n,i,r,o=t.button;return null==e.pageX&&null!=t.clientX&&(n=e.target.ownerDocument||Z,i=n.documentElement,r=n.body,e.pageX=t.clientX+(i&&i.scrollLeft||r&&r.scrollLeft||0)-(i&&i.clientLeft||r&&r.clientLeft||0),e.pageY=t.clientY+(i&&i.scrollTop||r&&r.scrollTop||0)-(i&&i.clientTop||r&&r.clientTop||0)),e.which||void 0===o||(e.which=1&o?1:2&o?3:4&o?2:0),e}},fix:function(e){if(e[J.expando])return e;var t,n,i,r=e.type,o=e,a=this.fixHooks[r];for(a||(this.fixHooks[r]=a=ke.test(r)?this.mouseHooks:Ce.test(r)?this.keyHooks:{}),i=a.props?this.props.concat(a.props):this.props,e=new J.Event(o),t=i.length;t--;)n=i[t],e[n]=o[n];return e.target||(e.target=Z),3===e.target.nodeType&&(e.target=e.target.parentNode),a.filter?a.filter(e,o):e},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==d()&&this.focus)return this.focus(),!1},delegateType:"focusin"},blur:{trigger:function(){if(this===d()&&this.blur)return this.blur(),!1},delegateType:"focusout"},click:{trigger:function(){if("checkbox"===this.type&&this.click&&J.nodeName(this,"input"))return this.click(),!1},_default:function(e){return J.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,i){var r=J.extend(new J.Event,n,{type:e,isSimulated:!0,originalEvent:{}});i?J.event.trigger(r,null,t):J.event.dispatch.call(t,r),r.isDefaultPrevented()&&n.preventDefault()}},J.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)},J.Event=function(e,t){if(!(this instanceof J.Event))return new J.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?c:u):this.type=e,t&&J.extend(this,t),this.timeStamp=e&&e.timeStamp||J.now(),this[J.expando]=!0},J.Event.prototype={isDefaultPrevented:u,isPropagationStopped:u,isImmediatePropagationStopped:u,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=c,e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=c,e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=c,e&&e.stopImmediatePropagation&&e.stopImmediatePropagation(),this.stopPropagation()}},J.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,t){J.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,i=this,r=e.relatedTarget,o=e.handleObj;return r&&(r===i||J.contains(i,r))||(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),X.focusinBubbles||J.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){J.event.simulate(t,e.target,J.event.fix(e),!0)};J.event.special[t]={setup:function(){var i=this.ownerDocument||this,r=ge.access(i,t);r||i.addEventListener(e,n,!0),ge.access(i,t,(r||0)+1)},teardown:function(){var i=this.ownerDocument||this,r=ge.access(i,t)-1;r?ge.access(i,t,r):(i.removeEventListener(e,n,!0),ge.remove(i,t))}}}),J.fn.extend({on:function(e,t,n,i,r){var o,a;if("object"==typeof e){"string"!=typeof t&&(n=n||t,t=void 0);for(a in e)this.on(a,t,n,e[a],r);return this}if(null==n&&null==i?(i=t,n=t=void 0):null==i&&("string"==typeof t?(i=n,n=void 0):(i=n,n=t,t=void 0)),!1===i)i=u;else if(!i)return this;return 1===r&&(o=i,i=function(e){return J().off(e),o.apply(this,arguments)},i.guid=o.guid||(o.guid=J.guid++)),this.each(function(){J.event.add(this,e,i,n,t)})},one:function(e,t,n,i){return this.on(e,t,n,i,1)},off:function(e,t,n){var i,r;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,J(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(r in e)this.off(r,t,e[r]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=u),this.each(function(){J.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){J.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return J.event.trigger(e,t,n,!0)}});var Te=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,De=/<([\w:]+)/,Ae=/<|&#?\w+;/,Me=/<(?:script|style|link)/i,Oe=/checked\s*(?:[^=]|=\s*.checked.)/i,Ie=/^$|\/(?:java|ecma)script/i,Pe=/^true\/(.*)/,Ne=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,je={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};je.optgroup=je.option,je.tbody=je.tfoot=je.colgroup=je.caption=je.thead,je.th=je.td,J.extend({clone:function(e,t,n){var i,r,o,a,s=e.cloneNode(!0),l=J.contains(e.ownerDocument,e);if(!(X.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||J.isXMLDoc(e)))for(a=v(s),o=v(e),i=0,r=o.length;i<r;i++)$(o[i],a[i]);if(t)if(n)for(o=o||v(e),a=a||v(s),i=0,r=o.length;i<r;i++)m(o[i],a[i]);else m(e,s);return a=v(s,"script"),a.length>0&&g(a,!l&&v(e,"script")),s},buildFragment:function(e,t,n,i){for(var r,o,a,s,l,c,u=t.createDocumentFragment(),d=[],f=0,p=e.length;f<p;f++)if((r=e[f])||0===r)if("object"===J.type(r))J.merge(d,r.nodeType?[r]:r);else if(Ae.test(r)){for(o=o||u.appendChild(t.createElement("div")),a=(De.exec(r)||["",""])[1].toLowerCase(),s=je[a]||je._default,o.innerHTML=s[1]+r.replace(Te,"<$1></$2>")+s[2],c=s[0];c--;)o=o.lastChild;J.merge(d,o.childNodes),o=u.firstChild,o.textContent=""}else d.push(t.createTextNode(r));for(u.textContent="",f=0;r=d[f++];)if((!i||-1===J.inArray(r,i))&&(l=J.contains(r.ownerDocument,r),o=v(u.appendChild(r),"script"),l&&g(o),n))for(c=0;r=o[c++];)Ie.test(r.type||"")&&n.push(r);return u},cleanData:function(e){for(var t,n,i,r,o=J.event.special,a=0;void 0!==(n=e[a]);a++){if(J.acceptData(n)&&(r=n[ge.expando])&&(t=ge.cache[r])){if(t.events)for(i in t.events)o[i]?J.event.remove(n,i):J.removeEvent(n,i,t.handle);ge.cache[r]&&delete ge.cache[r]}delete me.cache[n[me.expando]]}}}),J.fn.extend({text:function(e){return he(this,function(e){return void 0===e?J.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){f(this,e).appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=f(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){for(var n,i=e?J.filter(e,this):this,r=0;null!=(n=i[r]);r++)t||1!==n.nodeType||J.cleanData(v(n)),n.parentNode&&(t&&J.contains(n.ownerDocument,n)&&g(v(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(J.cleanData(v(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return J.clone(this,e,t)})},html:function(e){return he(this,function(e){var t=this[0]||{},n=0,i=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Me.test(e)&&!je[(De.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(Te,"<$1></$2>");try{for(;n<i;n++)t=this[n]||{},1===t.nodeType&&(J.cleanData(v(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=arguments[0];return this.domManip(arguments,function(t){e=this.parentNode,J.cleanData(v(this)),e&&e.replaceChild(t,this)}),e&&(e.length||e.nodeType)?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t){e=B.apply([],e);var n,i,r,o,a,s,l=0,c=this.length,u=this,d=c-1,f=e[0],g=J.isFunction(f);if(g||c>1&&"string"==typeof f&&!X.checkClone&&Oe.test(f))return this.each(function(n){var i=u.eq(n);g&&(e[0]=f.call(this,n,i.html())),i.domManip(e,t)});if(c&&(n=J.buildFragment(e,this[0].ownerDocument,!1,this),i=n.firstChild,1===n.childNodes.length&&(n=i),i)){for(r=J.map(v(n,"script"),p),o=r.length;l<c;l++)a=n,l!==d&&(a=J.clone(a,!0,!0),o&&J.merge(r,v(a,"script"))),t.call(this[l],a,l);if(o)for(s=r[r.length-1].ownerDocument,J.map(r,h),l=0;l<o;l++)a=r[l],Ie.test(a.type||"")&&!ge.access(a,"globalEval")&&J.contains(s,a)&&(a.src?J._evalUrl&&J._evalUrl(a.src):J.globalEval(a.textContent.replace(Ne,"")))}return this}}),J.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){J.fn[e]=function(e){for(var n,i=[],r=J(e),o=r.length-1,a=0;a<=o;a++)n=a===o?this:this.clone(!0),J(r[a])[t](n),W.apply(i,n.get());return this.pushStack(i)}});var Fe,Le={},Re=/^margin/,Ve=new RegExp("^("+ye+")(?!px)[a-z%]+$","i"),He=function(e){return e.ownerDocument.defaultView.getComputedStyle(e,null)};!function(){function t(){a.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",a.innerHTML="",r.appendChild(o);var t=e.getComputedStyle(a,null);n="1%"!==t.top,i="4px"===t.width,r.removeChild(o)}var n,i,r=Z.documentElement,o=Z.createElement("div"),a=Z.createElement("div");a.style&&(a.style.backgroundClip="content-box",a.cloneNode(!0).style.backgroundClip="",X.clearCloneStyle="content-box"===a.style.backgroundClip,o.style.cssText="border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;position:absolute",o.appendChild(a),e.getComputedStyle&&J.extend(X,{pixelPosition:function(){return t(),n},boxSizingReliable:function(){return null==i&&t(),i},reliableMarginRight:function(){var t,n=a.appendChild(Z.createElement("div"));return n.style.cssText=a.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",n.style.marginRight=n.style.width="0",a.style.width="1px",r.appendChild(o),t=!parseFloat(e.getComputedStyle(n,null).marginRight),r.removeChild(o),t}}))}(),J.swap=function(e,t,n,i){var r,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];r=n.apply(e,i||[]);for(o in t)e.style[o]=a[o];return r};var qe=/^(none|table(?!-c[ea]).+)/,Ue=new RegExp("^("+ye+")(.*)$","i"),_e=new RegExp("^([+-])=("+ye+")","i"),Be={position:"absolute",visibility:"hidden",display:"block"},We={letterSpacing:"0",fontWeight:"400"},ze=["Webkit","O","Moz","ms"];J.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=w(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{float:"cssFloat"},style:function(e,t,n,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var r,o,a,s=J.camelCase(t),l=e.style;if(t=J.cssProps[s]||(J.cssProps[s]=C(l,s)),a=J.cssHooks[t]||J.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(r=a.get(e,!1,i))?r:l[t];o=typeof n,"string"===o&&(r=_e.exec(n))&&(n=(r[1]+1)*r[2]+parseFloat(J.css(e,t)),o="number"),null!=n&&n===n&&("number"!==o||J.cssNumber[s]||(n+="px"),X.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,i))||(l[t]=n))}},css:function(e,t,n,i){var r,o,a,s=J.camelCase(t);return t=J.cssProps[s]||(J.cssProps[s]=C(e.style,s)),a=J.cssHooks[t]||J.cssHooks[s],a&&"get"in a&&(r=a.get(e,!0,n)),void 0===r&&(r=w(e,t,i)),"normal"===r&&t in We&&(r=We[t]),""===n||n?(o=parseFloat(r),!0===n||J.isNumeric(o)?o||0:r):r}}),J.each(["height","width"],function(e,t){J.cssHooks[t]={get:function(e,n,i){if(n)return qe.test(J.css(e,"display"))&&0===e.offsetWidth?J.swap(e,Be,function(){return E(e,t,i)}):E(e,t,i)},set:function(e,n,i){var r=i&&He(e);return k(e,n,i?S(e,t,i,"border-box"===J.css(e,"boxSizing",!1,r),r):0)}}}),J.cssHooks.marginRight=x(X.reliableMarginRight,function(e,t){if(t)return J.swap(e,{display:"inline-block"},w,[e,"marginRight"])}),J.each({margin:"",padding:"",border:"Width"},function(e,t){J.cssHooks[e+t]={expand:function(n){for(var i=0,r={},o="string"==typeof n?n.split(" "):[n];i<4;i++)r[e+be[i]+t]=o[i]||o[i-2]||o[0];return r}},Re.test(e)||(J.cssHooks[e+t].set=k)}),J.fn.extend({css:function(e,t){return he(this,function(e,t,n){var i,r,o={},a=0;if(J.isArray(t)){for(i=He(e),r=t.length;a<r;a++)o[t[a]]=J.css(e,t[a],!1,i);return o}return void 0!==n?J.style(e,t,n):J.css(e,t)},e,t,arguments.length>1)},show:function(){return T(this,!0)},hide:function(){return T(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){we(this)?J(this).show():J(this).hide()})}}),J.Tween=D,D.prototype={constructor:D,init:function(e,t,n,i,r,o){this.elem=e,this.prop=n,this.easing=r||"swing",this.options=t,this.start=this.now=this.cur(),this.end=i,this.unit=o||(J.cssNumber[n]?"":"px")},cur:function(){var e=D.propHooks[this.prop];return e&&e.get?e.get(this):D.propHooks._default.get(this)},run:function(e){var t,n=D.propHooks[this.prop];return this.options.duration?this.pos=t=J.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):D.propHooks._default.set(this),this}},D.prototype.init.prototype=D.prototype,D.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=J.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){J.fx.step[e.prop]?J.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[J.cssProps[e.prop]]||J.cssHooks[e.prop])?J.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},D.propHooks.scrollTop=D.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},J.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},J.fx=D.prototype.init,J.fx.step={};var Ye,Ke,Ge=/^(?:toggle|show|hide)$/,Xe=new RegExp("^(?:([+-])=|)("+ye+")([a-z%]*)$","i"),Ze=/queueHooks$/,Je=[I],Qe={"*":[function(e,t){var n=this.createTween(e,t),i=n.cur(),r=Xe.exec(t),o=r&&r[3]||(J.cssNumber[e]?"":"px"),a=(J.cssNumber[e]||"px"!==o&&+i)&&Xe.exec(J.css(n.elem,e)),s=1,l=20;if(a&&a[3]!==o){o=o||a[3],r=r||[],a=+i||1;do{s=s||".5",a/=s,J.style(n.elem,e,a+o)}while(s!==(s=n.cur()/i)&&1!==s&&--l)}return r&&(a=n.start=+a||+i||0,n.unit=o,n.end=r[1]?a+(r[1]+1)*r[2]:+r[2]),n}]};J.Animation=J.extend(N,{tweener:function(e,t){J.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");for(var n,i=0,r=e.length;i<r;i++)n=e[i],Qe[n]=Qe[n]||[],Qe[n].unshift(t)},prefilter:function(e,t){t?Je.unshift(e):Je.push(e)}}),J.speed=function(e,t,n){var i=e&&"object"==typeof e?J.extend({},e):{complete:n||!n&&t||J.isFunction(e)&&e,duration:e,easing:n&&t||t&&!J.isFunction(t)&&t};return i.duration=J.fx.off?0:"number"==typeof i.duration?i.duration:i.duration in J.fx.speeds?J.fx.speeds[i.duration]:J.fx.speeds._default,null!=i.queue&&!0!==i.queue||(i.queue="fx"),i.old=i.complete,i.complete=function(){J.isFunction(i.old)&&i.old.call(this),i.queue&&J.dequeue(this,i.queue)},i},J.fn.extend({fadeTo:function(e,t,n,i){return this.filter(we).css("opacity",0).show().end().animate({opacity:t},e,n,i)},animate:function(e,t,n,i){var r=J.isEmptyObject(e),o=J.speed(t,n,i),a=function(){var t=N(this,J.extend({},e),o);(r||ge.get(this,"finish"))&&t.stop(!0)};return a.finish=a,r||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(e,t,n){var i=function(e){var t=e.stop;delete e.stop,t(n)};return"string"!=typeof e&&(n=t,t=e,e=void 0),t&&!1!==e&&this.queue(e||"fx",[]),this.each(function(){var t=!0,r=null!=e&&e+"queueHooks",o=J.timers,a=ge.get(this);if(r)a[r]&&a[r].stop&&i(a[r]);else for(r in a)a[r]&&a[r].stop&&Ze.test(r)&&i(a[r]);for(r=o.length;r--;)o[r].elem!==this||null!=e&&o[r].queue!==e||(o[r].anim.stop(n),t=!1,o.splice(r,1));!t&&n||J.dequeue(this,e)})},finish:function(e){return!1!==e&&(e=e||"fx"),this.each(function(){
+var t,n=ge.get(this),i=n[e+"queue"],r=n[e+"queueHooks"],o=J.timers,a=i?i.length:0;for(n.finish=!0,J.queue(this,e,[]),r&&r.stop&&r.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;t<a;t++)i[t]&&i[t].finish&&i[t].finish.call(this);delete n.finish})}}),J.each(["toggle","show","hide"],function(e,t){var n=J.fn[t];J.fn[t]=function(e,i,r){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(M(t,!0),e,i,r)}}),J.each({slideDown:M("show"),slideUp:M("hide"),slideToggle:M("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){J.fn[e]=function(e,n,i){return this.animate(t,e,n,i)}}),J.timers=[],J.fx.tick=function(){var e,t=0,n=J.timers;for(Ye=J.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||J.fx.stop(),Ye=void 0},J.fx.timer=function(e){J.timers.push(e),e()?J.fx.start():J.timers.pop()},J.fx.interval=13,J.fx.start=function(){Ke||(Ke=setInterval(J.fx.tick,J.fx.interval))},J.fx.stop=function(){clearInterval(Ke),Ke=null},J.fx.speeds={slow:600,fast:200,_default:400},J.fn.delay=function(e,t){return e=J.fx?J.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var i=setTimeout(t,e);n.stop=function(){clearTimeout(i)}})},function(){var e=Z.createElement("input"),t=Z.createElement("select"),n=t.appendChild(Z.createElement("option"));e.type="checkbox",X.checkOn=""!==e.value,X.optSelected=n.selected,t.disabled=!0,X.optDisabled=!n.disabled,e=Z.createElement("input"),e.value="t",e.type="radio",X.radioValue="t"===e.value}();var et,tt=J.expr.attrHandle;J.fn.extend({attr:function(e,t){return he(this,J.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){J.removeAttr(this,e)})}}),J.extend({attr:function(e,t,n){var i,r,o=e.nodeType;if(e&&3!==o&&8!==o&&2!==o)return void 0===e.getAttribute?J.prop(e,t,n):(1===o&&J.isXMLDoc(e)||(t=t.toLowerCase(),i=J.attrHooks[t]||(J.expr.match.bool.test(t)?et:void 0)),void 0===n?i&&"get"in i&&null!==(r=i.get(e,t))?r:(r=J.find.attr(e,t),null==r?void 0:r):null!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):void J.removeAttr(e,t))},removeAttr:function(e,t){var n,i,r=0,o=t&&t.match(de);if(o&&1===e.nodeType)for(;n=o[r++];)i=J.propFix[n]||n,J.expr.match.bool.test(n)&&(e[i]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!X.radioValue&&"radio"===t&&J.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}}}),et={set:function(e,t,n){return!1===t?J.removeAttr(e,n):e.setAttribute(n,n),n}},J.each(J.expr.match.bool.source.match(/\w+/g),function(e,t){var n=tt[t]||J.find.attr;tt[t]=function(e,t,i){var r,o;return i||(o=tt[t],tt[t]=r,r=null!=n(e,t,i)?t.toLowerCase():null,tt[t]=o),r}});var nt=/^(?:input|select|textarea|button)$/i;J.fn.extend({prop:function(e,t){return he(this,J.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[J.propFix[e]||e]})}}),J.extend({propFix:{for:"htmlFor",class:"className"},prop:function(e,t,n){var i,r,o,a=e.nodeType;if(e&&3!==a&&8!==a&&2!==a)return o=1!==a||!J.isXMLDoc(e),o&&(t=J.propFix[t]||t,r=J.propHooks[t]),void 0!==n?r&&"set"in r&&void 0!==(i=r.set(e,n,t))?i:e[t]=n:r&&"get"in r&&null!==(i=r.get(e,t))?i:e[t]},propHooks:{tabIndex:{get:function(e){return e.hasAttribute("tabindex")||nt.test(e.nodeName)||e.href?e.tabIndex:-1}}}}),X.optSelected||(J.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null}}),J.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){J.propFix[this.toLowerCase()]=this});var it=/[\t\r\n\f]/g;J.fn.extend({addClass:function(e){var t,n,i,r,o,a,s="string"==typeof e&&e,l=0,c=this.length;if(J.isFunction(e))return this.each(function(t){J(this).addClass(e.call(this,t,this.className))});if(s)for(t=(e||"").match(de)||[];l<c;l++)if(n=this[l],i=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(it," "):" ")){for(o=0;r=t[o++];)i.indexOf(" "+r+" ")<0&&(i+=r+" ");a=J.trim(i),n.className!==a&&(n.className=a)}return this},removeClass:function(e){var t,n,i,r,o,a,s=0===arguments.length||"string"==typeof e&&e,l=0,c=this.length;if(J.isFunction(e))return this.each(function(t){J(this).removeClass(e.call(this,t,this.className))});if(s)for(t=(e||"").match(de)||[];l<c;l++)if(n=this[l],i=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(it," "):"")){for(o=0;r=t[o++];)for(;i.indexOf(" "+r+" ")>=0;)i=i.replace(" "+r+" "," ");a=e?J.trim(i):"",n.className!==a&&(n.className=a)}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):J.isFunction(e)?this.each(function(n){J(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n)for(var t,i=0,r=J(this),o=e.match(de)||[];t=o[i++];)r.hasClass(t)?r.removeClass(t):r.addClass(t);else"undefined"!==n&&"boolean"!==n||(this.className&&ge.set(this,"__className__",this.className),this.className=this.className||!1===e?"":ge.get(this,"__className__")||"")})},hasClass:function(e){for(var t=" "+e+" ",n=0,i=this.length;n<i;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(it," ").indexOf(t)>=0)return!0;return!1}});var rt=/\r/g;J.fn.extend({val:function(e){var t,n,i,r=this[0];{if(arguments.length)return i=J.isFunction(e),this.each(function(n){var r;1===this.nodeType&&(r=i?e.call(this,n,J(this).val()):e,null==r?r="":"number"==typeof r?r+="":J.isArray(r)&&(r=J.map(r,function(e){return null==e?"":e+""})),(t=J.valHooks[this.type]||J.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,r,"value")||(this.value=r))});if(r)return(t=J.valHooks[r.type]||J.valHooks[r.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(r,"value"))?n:(n=r.value,"string"==typeof n?n.replace(rt,""):null==n?"":n)}}}),J.extend({valHooks:{option:{get:function(e){var t=J.find.attr(e,"value");return null!=t?t:J.trim(J.text(e))}},select:{get:function(e){for(var t,n,i=e.options,r=e.selectedIndex,o="select-one"===e.type||r<0,a=o?null:[],s=o?r+1:i.length,l=r<0?s:o?r:0;l<s;l++)if(n=i[l],(n.selected||l===r)&&(X.optDisabled?!n.disabled:null===n.getAttribute("disabled"))&&(!n.parentNode.disabled||!J.nodeName(n.parentNode,"optgroup"))){if(t=J(n).val(),o)return t;a.push(t)}return a},set:function(e,t){for(var n,i,r=e.options,o=J.makeArray(t),a=r.length;a--;)i=r[a],(i.selected=J.inArray(i.value,o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),J.each(["radio","checkbox"],function(){J.valHooks[this]={set:function(e,t){if(J.isArray(t))return e.checked=J.inArray(J(e).val(),t)>=0}},X.checkOn||(J.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),J.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){J.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),J.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,i){return this.on(t,e,n,i)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var ot=J.now(),at=/\?/;J.parseJSON=function(e){return JSON.parse(e+"")},J.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||J.error("Invalid XML: "+e),t};var st,lt,ct=/#.*$/,ut=/([?&])_=[^&]*/,dt=/^(.*?):[ \t]*([^\r\n]*)$/gm,ft=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,pt=/^(?:GET|HEAD)$/,ht=/^\/\//,gt=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,mt={},vt={},$t="*/".concat("*");try{lt=location.href}catch(e){lt=Z.createElement("a"),lt.href="",lt=lt.href}st=gt.exec(lt.toLowerCase())||[],J.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:lt,type:"GET",isLocal:ft.test(st[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":J.parseJSON,"text xml":J.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?L(L(e,J.ajaxSettings),t):L(J.ajaxSettings,e)},ajaxPrefilter:j(mt),ajaxTransport:j(vt),ajax:function(e,t){function n(e,t,n,a){var l,u,v,$,b,x=t;2!==y&&(y=2,s&&clearTimeout(s),i=void 0,o=a||"",w.readyState=e>0?4:0,l=e>=200&&e<300||304===e,n&&($=R(d,w,n)),$=V(d,$,w,l),l?(d.ifModified&&(b=w.getResponseHeader("Last-Modified"),b&&(J.lastModified[r]=b),(b=w.getResponseHeader("etag"))&&(J.etag[r]=b)),204===e||"HEAD"===d.type?x="nocontent":304===e?x="notmodified":(x=$.state,u=$.data,v=$.error,l=!v)):(v=x,!e&&x||(x="error",e<0&&(e=0))),w.status=e,w.statusText=(t||x)+"",l?h.resolveWith(f,[u,x,w]):h.rejectWith(f,[w,x,v]),w.statusCode(m),m=void 0,c&&p.trigger(l?"ajaxSuccess":"ajaxError",[w,d,l?u:v]),g.fireWith(f,[w,x]),c&&(p.trigger("ajaxComplete",[w,d]),--J.active||J.event.trigger("ajaxStop")))}"object"==typeof e&&(t=e,e=void 0),t=t||{};var i,r,o,a,s,l,c,u,d=J.ajaxSetup({},t),f=d.context||d,p=d.context&&(f.nodeType||f.jquery)?J(f):J.event,h=J.Deferred(),g=J.Callbacks("once memory"),m=d.statusCode||{},v={},$={},y=0,b="canceled",w={readyState:0,getResponseHeader:function(e){var t;if(2===y){if(!a)for(a={};t=dt.exec(o);)a[t[1].toLowerCase()]=t[2];t=a[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===y?o:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return y||(e=$[n]=$[n]||e,v[e]=t),this},overrideMimeType:function(e){return y||(d.mimeType=e),this},statusCode:function(e){var t;if(e)if(y<2)for(t in e)m[t]=[m[t],e[t]];else w.always(e[w.status]);return this},abort:function(e){var t=e||b;return i&&i.abort(t),n(0,t),this}};if(h.promise(w).complete=g.add,w.success=w.done,w.error=w.fail,d.url=((e||d.url||lt)+"").replace(ct,"").replace(ht,st[1]+"//"),d.type=t.method||t.type||d.method||d.type,d.dataTypes=J.trim(d.dataType||"*").toLowerCase().match(de)||[""],null==d.crossDomain&&(l=gt.exec(d.url.toLowerCase()),d.crossDomain=!(!l||l[1]===st[1]&&l[2]===st[2]&&(l[3]||("http:"===l[1]?"80":"443"))===(st[3]||("http:"===st[1]?"80":"443")))),d.data&&d.processData&&"string"!=typeof d.data&&(d.data=J.param(d.data,d.traditional)),F(mt,d,t,w),2===y)return w;c=d.global,c&&0==J.active++&&J.event.trigger("ajaxStart"),d.type=d.type.toUpperCase(),d.hasContent=!pt.test(d.type),r=d.url,d.hasContent||(d.data&&(r=d.url+=(at.test(r)?"&":"?")+d.data,delete d.data),!1===d.cache&&(d.url=ut.test(r)?r.replace(ut,"$1_="+ot++):r+(at.test(r)?"&":"?")+"_="+ot++)),d.ifModified&&(J.lastModified[r]&&w.setRequestHeader("If-Modified-Since",J.lastModified[r]),J.etag[r]&&w.setRequestHeader("If-None-Match",J.etag[r])),(d.data&&d.hasContent&&!1!==d.contentType||t.contentType)&&w.setRequestHeader("Content-Type",d.contentType),w.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+("*"!==d.dataTypes[0]?", "+$t+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)w.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(!1===d.beforeSend.call(f,w,d)||2===y))return w.abort();b="abort";for(u in{success:1,error:1,complete:1})w[u](d[u]);if(i=F(vt,d,t,w)){w.readyState=1,c&&p.trigger("ajaxSend",[w,d]),d.async&&d.timeout>0&&(s=setTimeout(function(){w.abort("timeout")},d.timeout));try{y=1,i.send(v,n)}catch(e){if(!(y<2))throw e;n(-1,e)}}else n(-1,"No Transport");return w},getJSON:function(e,t,n){return J.get(e,t,n,"json")},getScript:function(e,t){return J.get(e,void 0,t,"script")}}),J.each(["get","post"],function(e,t){J[t]=function(e,n,i,r){return J.isFunction(n)&&(r=r||i,i=n,n=void 0),J.ajax({url:e,type:t,dataType:r,data:n,success:i})}}),J.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){J.fn[t]=function(e){return this.on(t,e)}}),J._evalUrl=function(e){return J.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,throws:!0})},J.fn.extend({wrapAll:function(e){var t;return J.isFunction(e)?this.each(function(t){J(this).wrapAll(e.call(this,t))}):(this[0]&&(t=J(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return J.isFunction(e)?this.each(function(t){J(this).wrapInner(e.call(this,t))}):this.each(function(){var t=J(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=J.isFunction(e);return this.each(function(n){J(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){J.nodeName(this,"body")||J(this).replaceWith(this.childNodes)}).end()}}),J.expr.filters.hidden=function(e){return e.offsetWidth<=0&&e.offsetHeight<=0},J.expr.filters.visible=function(e){return!J.expr.filters.hidden(e)};var yt=/%20/g,bt=/\[\]$/,wt=/\r?\n/g,xt=/^(?:submit|button|image|reset|file)$/i,Ct=/^(?:input|select|textarea|keygen)/i;J.param=function(e,t){var n,i=[],r=function(e,t){t=J.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(void 0===t&&(t=J.ajaxSettings&&J.ajaxSettings.traditional),J.isArray(e)||e.jquery&&!J.isPlainObject(e))J.each(e,function(){r(this.name,this.value)});else for(n in e)H(n,e[n],t,r);return i.join("&").replace(yt,"+")},J.fn.extend({serialize:function(){return J.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=J.prop(this,"elements");return e?J.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!J(this).is(":disabled")&&Ct.test(this.nodeName)&&!xt.test(e)&&(this.checked||!xe.test(e))}).map(function(e,t){var n=J(this).val();return null==n?null:J.isArray(n)?J.map(n,function(e){return{name:t.name,value:e.replace(wt,"\r\n")}}):{name:t.name,value:n.replace(wt,"\r\n")}}).get()}}),J.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(e){}};var kt=0,St={},Et={0:200,1223:204},Tt=J.ajaxSettings.xhr();e.ActiveXObject&&J(e).on("unload",function(){for(var e in St)St[e]()}),X.cors=!!Tt&&"withCredentials"in Tt,X.ajax=Tt=!!Tt,J.ajaxTransport(function(e){var t;if(X.cors||Tt&&!e.crossDomain)return{send:function(n,i){var r,o=e.xhr(),a=++kt;if(o.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(r in e.xhrFields)o[r]=e.xhrFields[r];e.mimeType&&o.overrideMimeType&&o.overrideMimeType(e.mimeType),e.crossDomain||n["X-Requested-With"]||(n["X-Requested-With"]="XMLHttpRequest");for(r in n)o.setRequestHeader(r,n[r]);t=function(e){return function(){t&&(delete St[a],t=o.onload=o.onerror=null,"abort"===e?o.abort():"error"===e?i(o.status,o.statusText):i(Et[o.status]||o.status,o.statusText,"string"==typeof o.responseText?{text:o.responseText}:void 0,o.getAllResponseHeaders()))}},o.onload=t(),o.onerror=t("error"),t=St[a]=t("abort");try{o.send(e.hasContent&&e.data||null)}catch(e){if(t)throw e}},abort:function(){t&&t()}}}),J.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return J.globalEval(e),e}}}),J.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),J.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,r){t=J("<script>").prop({async:!0,charset:e.scriptCharset,src:e.url}).on("load error",n=function(e){t.remove(),n=null,e&&r("error"===e.type?404:200,e.type)}),Z.head.appendChild(t[0])},abort:function(){n&&n()}}}});var Dt=[],At=/(=)\?(?=&|$)|\?\?/;J.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Dt.pop()||J.expando+"_"+ot++;return this[e]=!0,e}}),J.ajaxPrefilter("json jsonp",function(t,n,i){var r,o,a,s=!1!==t.jsonp&&(At.test(t.url)?"url":"string"==typeof t.data&&!(t.contentType||"").indexOf("application/x-www-form-urlencoded")&&At.test(t.data)&&"data");if(s||"jsonp"===t.dataTypes[0])return r=t.jsonpCallback=J.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,s?t[s]=t[s].replace(At,"$1"+r):!1!==t.jsonp&&(t.url+=(at.test(t.url)?"&":"?")+t.jsonp+"="+r),t.converters["script json"]=function(){return a||J.error(r+" was not called"),a[0]},t.dataTypes[0]="json",o=e[r],e[r]=function(){a=arguments},i.always(function(){e[r]=o,t[r]&&(t.jsonpCallback=n.jsonpCallback,Dt.push(r)),a&&J.isFunction(o)&&o(a[0]),a=o=void 0}),"script"}),J.parseHTML=function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||Z;var i=oe.exec(e),r=!n&&[];return i?[t.createElement(i[1])]:(i=J.buildFragment([e],t,r),r&&r.length&&J(r).remove(),J.merge([],i.childNodes))};var Mt=J.fn.load;J.fn.load=function(e,t,n){if("string"!=typeof e&&Mt)return Mt.apply(this,arguments);var i,r,o,a=this,s=e.indexOf(" ");return s>=0&&(i=J.trim(e.slice(s)),e=e.slice(0,s)),J.isFunction(t)?(n=t,t=void 0):t&&"object"==typeof t&&(r="POST"),a.length>0&&J.ajax({url:e,type:r,dataType:"html",data:t}).done(function(e){o=arguments,a.html(i?J("<div>").append(J.parseHTML(e)).find(i):e)}).complete(n&&function(e,t){a.each(n,o||[e.responseText,t,e])}),this},J.expr.filters.animated=function(e){return J.grep(J.timers,function(t){return e===t.elem}).length};var Ot=e.document.documentElement;J.offset={setOffset:function(e,t,n){var i,r,o,a,s,l,c,u=J.css(e,"position"),d=J(e),f={};"static"===u&&(e.style.position="relative"),s=d.offset(),o=J.css(e,"top"),l=J.css(e,"left"),c=("absolute"===u||"fixed"===u)&&(o+l).indexOf("auto")>-1,c?(i=d.position(),a=i.top,r=i.left):(a=parseFloat(o)||0,r=parseFloat(l)||0),J.isFunction(t)&&(t=t.call(e,n,s)),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+r),"using"in t?t.using.call(e,f):d.css(f)}},J.fn.extend({offset:function(e){if(arguments.length)return void 0===e?this:this.each(function(t){J.offset.setOffset(this,e,t)});var t,n,i=this[0],r={top:0,left:0},o=i&&i.ownerDocument;if(o)return t=o.documentElement,J.contains(t,i)?(void 0!==i.getBoundingClientRect&&(r=i.getBoundingClientRect()),n=q(o),{top:r.top+n.pageYOffset-t.clientTop,left:r.left+n.pageXOffset-t.clientLeft}):r},position:function(){if(this[0]){var e,t,n=this[0],i={top:0,left:0};return"fixed"===J.css(n,"position")?t=n.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),J.nodeName(e[0],"html")||(i=e.offset()),i.top+=J.css(e[0],"borderTopWidth",!0),i.left+=J.css(e[0],"borderLeftWidth",!0)),{top:t.top-i.top-J.css(n,"marginTop",!0),left:t.left-i.left-J.css(n,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){for(var e=this.offsetParent||Ot;e&&!J.nodeName(e,"html")&&"static"===J.css(e,"position");)e=e.offsetParent;return e||Ot})}}),J.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,n){var i="pageYOffset"===n;J.fn[t]=function(r){return he(this,function(t,r,o){var a=q(t);if(void 0===o)return a?a[n]:t[r];a?a.scrollTo(i?e.pageXOffset:o,i?o:e.pageYOffset):t[r]=o},t,r,arguments.length,null)}}),J.each(["top","left"],function(e,t){J.cssHooks[t]=x(X.pixelPosition,function(e,n){if(n)return n=w(e,t),Ve.test(n)?J(e).position()[t]+"px":n})}),J.each({Height:"height",Width:"width"},function(e,t){J.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,i){J.fn[i]=function(i,r){var o=arguments.length&&(n||"boolean"!=typeof i),a=n||(!0===i||!0===r?"margin":"border");return he(this,function(t,n,i){var r;return J.isWindow(t)?t.document.documentElement["client"+e]:9===t.nodeType?(r=t.documentElement,Math.max(t.body["scroll"+e],r["scroll"+e],t.body["offset"+e],r["offset"+e],r["client"+e])):void 0===i?J.css(t,n,a):J.style(t,n,i,a)},t,o?i:void 0,o,null)}})}),J.fn.size=function(){return this.length},J.fn.andSelf=J.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return J});var It=e.jQuery,Pt=e.$;return J.noConflict=function(t){return e.$===J&&(e.$=Pt),t&&e.jQuery===J&&(e.jQuery=It),J},void 0===t&&(e.jQuery=e.$=J),J}),function(){function e(e){function t(t,n,i,r,o,a){for(;o>=0&&o<a;o+=e){var s=r?r[o]:o;i=n(i,t[s],s,t)}return i}return function(n,i,r,o){i=y(i,o,4);var a=!E(n)&&$.keys(n),s=(a||n).length,l=e>0?0:s-1;return arguments.length<3&&(r=n[a?a[l]:l],l+=e),t(n,i,r,a,l,s)}}function t(e){return function(t,n,i){n=b(n,i);for(var r=S(t),o=e>0?0:r-1;o>=0&&o<r;o+=e)if(n(t[o],o,t))return o;return-1}}function n(e,t,n){return function(i,r,o){var a=0,s=S(i);if("number"==typeof o)e>0?a=o>=0?o:Math.max(o+s,a):s=o>=0?Math.min(o+1,s):o+s+1;else if(n&&o&&s)return o=n(i,r),i[o]===r?o:-1;if(r!==r)return o=t(u.call(i,a,s),$.isNaN),o>=0?o+a:-1;for(o=e>0?a:s-1;o>=0&&o<s;o+=e)if(i[o]===r)return o;return-1}}function i(e,t){var n=O.length,i=e.constructor,r=$.isFunction(i)&&i.prototype||s,o="constructor";for($.has(e,o)&&!$.contains(t,o)&&t.push(o);n--;)(o=O[n])in e&&e[o]!==r[o]&&!$.contains(t,o)&&t.push(o)}var r=this,o=r._,a=Array.prototype,s=Object.prototype,l=Function.prototype,c=a.push,u=a.slice,d=s.toString,f=s.hasOwnProperty,p=Array.isArray,h=Object.keys,g=l.bind,m=Object.create,v=function(){},$=function(e){return e instanceof $?e:this instanceof $?void(this._wrapped=e):new $(e)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=$),exports._=$):r._=$,$.VERSION="1.8.3";var y=function(e,t,n){if(void 0===t)return e;switch(null==n?3:n){case 1:return function(n){return e.call(t,n)};case 2:return function(n,i){return e.call(t,n,i)};case 3:return function(n,i,r){return e.call(t,n,i,r)};case 4:return function(n,i,r,o){return e.call(t,n,i,r,o)}}return function(){return e.apply(t,arguments)}},b=function(e,t,n){return null==e?$.identity:$.isFunction(e)?y(e,t,n):$.isObject(e)?$.matcher(e):$.property(e)};$.iteratee=function(e,t){return b(e,t,1/0)};var w=function(e,t){return function(n){var i=arguments.length;if(i<2||null==n)return n;for(var r=1;r<i;r++)for(var o=arguments[r],a=e(o),s=a.length,l=0;l<s;l++){var c=a[l];t&&void 0!==n[c]||(n[c]=o[c])}return n}},x=function(e){if(!$.isObject(e))return{};if(m)return m(e);v.prototype=e;var t=new v;return v.prototype=null,t},C=function(e){return function(t){return null==t?void 0:t[e]}},k=Math.pow(2,53)-1,S=C("length"),E=function(e){var t=S(e);return"number"==typeof t&&t>=0&&t<=k};$.each=$.forEach=function(e,t,n){t=y(t,n);var i,r;if(E(e))for(i=0,r=e.length;i<r;i++)t(e[i],i,e);else{var o=$.keys(e);for(i=0,r=o.length;i<r;i++)t(e[o[i]],o[i],e)}return e},$.map=$.collect=function(e,t,n){t=b(t,n);for(var i=!E(e)&&$.keys(e),r=(i||e).length,o=Array(r),a=0;a<r;a++){var s=i?i[a]:a;o[a]=t(e[s],s,e)}return o},$.reduce=$.foldl=$.inject=e(1),$.reduceRight=$.foldr=e(-1),$.find=$.detect=function(e,t,n){var i;if(void 0!==(i=E(e)?$.findIndex(e,t,n):$.findKey(e,t,n))&&-1!==i)return e[i]},$.filter=$.select=function(e,t,n){var i=[];return t=b(t,n),$.each(e,function(e,n,r){t(e,n,r)&&i.push(e)}),i},$.reject=function(e,t,n){return $.filter(e,$.negate(b(t)),n)},$.every=$.all=function(e,t,n){t=b(t,n);for(var i=!E(e)&&$.keys(e),r=(i||e).length,o=0;o<r;o++){var a=i?i[o]:o;if(!t(e[a],a,e))return!1}return!0},$.some=$.any=function(e,t,n){t=b(t,n);for(var i=!E(e)&&$.keys(e),r=(i||e).length,o=0;o<r;o++){var a=i?i[o]:o;if(t(e[a],a,e))return!0}return!1},$.contains=$.includes=$.include=function(e,t,n,i){return E(e)||(e=$.values(e)),("number"!=typeof n||i)&&(n=0),$.indexOf(e,t,n)>=0},$.invoke=function(e,t){var n=u.call(arguments,2),i=$.isFunction(t);return $.map(e,function(e){var r=i?t:e[t];return null==r?r:r.apply(e,n)})},$.pluck=function(e,t){return $.map(e,$.property(t))},$.where=function(e,t){return $.filter(e,$.matcher(t))},$.findWhere=function(e,t){return $.find(e,$.matcher(t))},$.max=function(e,t,n){var i,r,o=-1/0,a=-1/0;if(null==t&&null!=e){e=E(e)?e:$.values(e);for(var s=0,l=e.length;s<l;s++)(i=e[s])>o&&(o=i)}else t=b(t,n),$.each(e,function(e,n,i){((r=t(e,n,i))>a||r===-1/0&&o===-1/0)&&(o=e,a=r)});return o},$.min=function(e,t,n){var i,r,o=1/0,a=1/0;if(null==t&&null!=e){e=E(e)?e:$.values(e);for(var s=0,l=e.length;s<l;s++)(i=e[s])<o&&(o=i)}else t=b(t,n),$.each(e,function(e,n,i){((r=t(e,n,i))<a||r===1/0&&o===1/0)&&(o=e,a=r)});return o},$.shuffle=function(e){for(var t,n=E(e)?e:$.values(e),i=n.length,r=Array(i),o=0;o<i;o++)t=$.random(0,o),t!==o&&(r[o]=r[t]),r[t]=n[o];return r},$.sample=function(e,t,n){return null==t||n?(E(e)||(e=$.values(e)),e[$.random(e.length-1)]):$.shuffle(e).slice(0,Math.max(0,t))},$.sortBy=function(e,t,n){return t=b(t,n),$.pluck($.map(e,function(e,n,i){return{value:e,index:n,criteria:t(e,n,i)}}).sort(function(e,t){var n=e.criteria,i=t.criteria;if(n!==i){if(n>i||void 0===n)return 1;if(n<i||void 0===i)return-1}return e.index-t.index}),"value")};var T=function(e){return function(t,n,i){var r={};return n=b(n,i),$.each(t,function(i,o){var a=n(i,o,t);e(r,i,a)}),r}};$.groupBy=T(function(e,t,n){$.has(e,n)?e[n].push(t):e[n]=[t]}),$.indexBy=T(function(e,t,n){e[n]=t}),$.countBy=T(function(e,t,n){$.has(e,n)?e[n]++:e[n]=1}),$.toArray=function(e){return e?$.isArray(e)?u.call(e):E(e)?$.map(e,$.identity):$.values(e):[]},$.size=function(e){return null==e?0:E(e)?e.length:$.keys(e).length},$.partition=function(e,t,n){t=b(t,n);var i=[],r=[];return $.each(e,function(e,n,o){(t(e,n,o)?i:r).push(e)}),[i,r]},$.first=$.head=$.take=function(e,t,n){if(null!=e)return null==t||n?e[0]:$.initial(e,e.length-t)},$.initial=function(e,t,n){return u.call(e,0,Math.max(0,e.length-(null==t||n?1:t)))},$.last=function(e,t,n){if(null!=e)return null==t||n?e[e.length-1]:$.rest(e,Math.max(0,e.length-t))},$.rest=$.tail=$.drop=function(e,t,n){return u.call(e,null==t||n?1:t)},$.compact=function(e){return $.filter(e,$.identity)};var D=function(e,t,n,i){for(var r=[],o=0,a=i||0,s=S(e);a<s;a++){var l=e[a];if(E(l)&&($.isArray(l)||$.isArguments(l))){t||(l=D(l,t,n));var c=0,u=l.length;for(r.length+=u;c<u;)r[o++]=l[c++]}else n||(r[o++]=l)}return r};$.flatten=function(e,t){return D(e,t,!1)},$.without=function(e){return $.difference(e,u.call(arguments,1))},$.uniq=$.unique=function(e,t,n,i){$.isBoolean(t)||(i=n,n=t,t=!1),null!=n&&(n=b(n,i));for(var r=[],o=[],a=0,s=S(e);a<s;a++){var l=e[a],c=n?n(l,a,e):l;t?(a&&o===c||r.push(l),o=c):n?$.contains(o,c)||(o.push(c),r.push(l)):$.contains(r,l)||r.push(l)}return r},$.union=function(){return $.uniq(D(arguments,!0,!0))},$.intersection=function(e){for(var t=[],n=arguments.length,i=0,r=S(e);i<r;i++){var o=e[i];if(!$.contains(t,o)){for(var a=1;a<n&&$.contains(arguments[a],o);a++);a===n&&t.push(o)}}return t},$.difference=function(e){var t=D(arguments,!0,!0,1);return $.filter(e,function(e){return!$.contains(t,e)})},$.zip=function(){return $.unzip(arguments)},$.unzip=function(e){for(var t=e&&$.max(e,S).length||0,n=Array(t),i=0;i<t;i++)n[i]=$.pluck(e,i);return n},$.object=function(e,t){for(var n={},i=0,r=S(e);i<r;i++)t?n[e[i]]=t[i]:n[e[i][0]]=e[i][1];return n},$.findIndex=t(1),$.findLastIndex=t(-1),$.sortedIndex=function(e,t,n,i){n=b(n,i,1);for(var r=n(t),o=0,a=S(e);o<a;){var s=Math.floor((o+a)/2);n(e[s])<r?o=s+1:a=s}return o},$.indexOf=n(1,$.findIndex,$.sortedIndex),$.lastIndexOf=n(-1,$.findLastIndex),$.range=function(e,t,n){null==t&&(t=e||0,e=0),n=n||1;for(var i=Math.max(Math.ceil((t-e)/n),0),r=Array(i),o=0;o<i;o++,e+=n)r[o]=e;return r};var A=function(e,t,n,i,r){if(!(i instanceof t))return e.apply(n,r);var o=x(e.prototype),a=e.apply(o,r);return $.isObject(a)?a:o};$.bind=function(e,t){if(g&&e.bind===g)return g.apply(e,u.call(arguments,1));if(!$.isFunction(e))throw new TypeError("Bind must be called on a function");var n=u.call(arguments,2),i=function(){return A(e,i,t,this,n.concat(u.call(arguments)))};return i},$.partial=function(e){var t=u.call(arguments,1),n=function(){for(var i=0,r=t.length,o=Array(r),a=0;a<r;a++)o[a]=t[a]===$?arguments[i++]:t[a];for(;i<arguments.length;)o.push(arguments[i++]);return A(e,n,this,this,o)};return n},$.bindAll=function(e){var t,n,i=arguments.length;if(i<=1)throw new Error("bindAll must be passed function names");for(t=1;t<i;t++)n=arguments[t],e[n]=$.bind(e[n],e);return e},$.memoize=function(e,t){var n=function(i){var r=n.cache,o=""+(t?t.apply(this,arguments):i);return $.has(r,o)||(r[o]=e.apply(this,arguments)),r[o]};return n.cache={},n},$.delay=function(e,t){var n=u.call(arguments,2);return setTimeout(function(){return e.apply(null,n)},t)},$.defer=$.partial($.delay,$,1),$.throttle=function(e,t,n){var i,r,o,a=null,s=0;n||(n={});var l=function(){s=!1===n.leading?0:$.now(),a=null,o=e.apply(i,r),a||(i=r=null)};return function(){var c=$.now();s||!1!==n.leading||(s=c);var u=t-(c-s);return i=this,r=arguments,u<=0||u>t?(a&&(clearTimeout(a),a=null),s=c,o=e.apply(i,r),a||(i=r=null)):a||!1===n.trailing||(a=setTimeout(l,u)),o}},$.debounce=function(e,t,n){var i,r,o,a,s,l=function(){var c=$.now()-a;c<t&&c>=0?i=setTimeout(l,t-c):(i=null,n||(s=e.apply(o,r),i||(o=r=null)))};return function(){o=this,r=arguments,a=$.now();var c=n&&!i;return i||(i=setTimeout(l,t)),c&&(s=e.apply(o,r),o=r=null),s}},$.wrap=function(e,t){return $.partial(t,e)},$.negate=function(e){return function(){return!e.apply(this,arguments)}},$.compose=function(){var e=arguments,t=e.length-1;return function(){for(var n=t,i=e[t].apply(this,arguments);n--;)i=e[n].call(this,i);return i}},$.after=function(e,t){return function(){if(--e<1)return t.apply(this,arguments)}},$.before=function(e,t){var n;return function(){return--e>0&&(n=t.apply(this,arguments)),e<=1&&(t=null),n}},$.once=$.partial($.before,2);var M=!{toString:null}.propertyIsEnumerable("toString"),O=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"];$.keys=function(e){if(!$.isObject(e))return[];if(h)return h(e);var t=[];for(var n in e)$.has(e,n)&&t.push(n);return M&&i(e,t),t},$.allKeys=function(e){if(!$.isObject(e))return[];var t=[];for(var n in e)t.push(n);return M&&i(e,t),t},$.values=function(e){for(var t=$.keys(e),n=t.length,i=Array(n),r=0;r<n;r++)i[r]=e[t[r]];return i},$.mapObject=function(e,t,n){t=b(t,n);for(var i,r=$.keys(e),o=r.length,a={},s=0;s<o;s++)i=r[s],a[i]=t(e[i],i,e);return a},$.pairs=function(e){for(var t=$.keys(e),n=t.length,i=Array(n),r=0;r<n;r++)i[r]=[t[r],e[t[r]]];return i},$.invert=function(e){for(var t={},n=$.keys(e),i=0,r=n.length;i<r;i++)t[e[n[i]]]=n[i];return t},$.functions=$.methods=function(e){var t=[];for(var n in e)$.isFunction(e[n])&&t.push(n);return t.sort()},$.extend=w($.allKeys),$.extendOwn=$.assign=w($.keys),$.findKey=function(e,t,n){t=b(t,n);for(var i,r=$.keys(e),o=0,a=r.length;o<a;o++)if(i=r[o],t(e[i],i,e))return i},$.pick=function(e,t,n){var i,r,o={},a=e;if(null==a)return o;$.isFunction(t)?(r=$.allKeys(a),i=y(t,n)):(r=D(arguments,!1,!1,1),i=function(e,t,n){return t in n},a=Object(a));for(var s=0,l=r.length;s<l;s++){var c=r[s],u=a[c];i(u,c,a)&&(o[c]=u)}return o},$.omit=function(e,t,n){if($.isFunction(t))t=$.negate(t);else{var i=$.map(D(arguments,!1,!1,1),String);t=function(e,t){return!$.contains(i,t)}}return $.pick(e,t,n)},$.defaults=w($.allKeys,!0),$.create=function(e,t){var n=x(e);return t&&$.extendOwn(n,t),n},$.clone=function(e){return $.isObject(e)?$.isArray(e)?e.slice():$.extend({},e):e},$.tap=function(e,t){return t(e),e},$.isMatch=function(e,t){var n=$.keys(t),i=n.length;if(null==e)return!i;for(var r=Object(e),o=0;o<i;o++){var a=n[o];if(t[a]!==r[a]||!(a in r))return!1}return!0};var I=function(e,t,n,i){if(e===t)return 0!==e||1/e==1/t;if(null==e||null==t)return e===t;e instanceof $&&(e=e._wrapped),t instanceof $&&(t=t._wrapped);var r=d.call(e);if(r!==d.call(t))return!1;switch(r){case"[object RegExp]":case"[object String]":return""+e==""+t;case"[object Number]":return+e!=+e?+t!=+t:0==+e?1/+e==1/t:+e==+t;case"[object Date]":case"[object Boolean]":return+e==+t}var o="[object Array]"===r;if(!o){
+if("object"!=typeof e||"object"!=typeof t)return!1;var a=e.constructor,s=t.constructor;if(a!==s&&!($.isFunction(a)&&a instanceof a&&$.isFunction(s)&&s instanceof s)&&"constructor"in e&&"constructor"in t)return!1}n=n||[],i=i||[];for(var l=n.length;l--;)if(n[l]===e)return i[l]===t;if(n.push(e),i.push(t),o){if((l=e.length)!==t.length)return!1;for(;l--;)if(!I(e[l],t[l],n,i))return!1}else{var c,u=$.keys(e);if(l=u.length,$.keys(t).length!==l)return!1;for(;l--;)if(c=u[l],!$.has(t,c)||!I(e[c],t[c],n,i))return!1}return n.pop(),i.pop(),!0};$.isEqual=function(e,t){return I(e,t)},$.isEmpty=function(e){return null==e||(E(e)&&($.isArray(e)||$.isString(e)||$.isArguments(e))?0===e.length:0===$.keys(e).length)},$.isElement=function(e){return!(!e||1!==e.nodeType)},$.isArray=p||function(e){return"[object Array]"===d.call(e)},$.isObject=function(e){var t=typeof e;return"function"===t||"object"===t&&!!e},$.each(["Arguments","Function","String","Number","Date","RegExp","Error"],function(e){$["is"+e]=function(t){return d.call(t)==="[object "+e+"]"}}),$.isArguments(arguments)||($.isArguments=function(e){return $.has(e,"callee")}),"function"!=typeof/./&&"object"!=typeof Int8Array&&($.isFunction=function(e){return"function"==typeof e||!1}),$.isFinite=function(e){return isFinite(e)&&!isNaN(parseFloat(e))},$.isNaN=function(e){return $.isNumber(e)&&e!==+e},$.isBoolean=function(e){return!0===e||!1===e||"[object Boolean]"===d.call(e)},$.isNull=function(e){return null===e},$.isUndefined=function(e){return void 0===e},$.has=function(e,t){return null!=e&&f.call(e,t)},$.noConflict=function(){return r._=o,this},$.identity=function(e){return e},$.constant=function(e){return function(){return e}},$.noop=function(){},$.property=C,$.propertyOf=function(e){return null==e?function(){}:function(t){return e[t]}},$.matcher=$.matches=function(e){return e=$.extendOwn({},e),function(t){return $.isMatch(t,e)}},$.times=function(e,t,n){var i=Array(Math.max(0,e));t=y(t,n,1);for(var r=0;r<e;r++)i[r]=t(r);return i},$.random=function(e,t){return null==t&&(t=e,e=0),e+Math.floor(Math.random()*(t-e+1))},$.now=Date.now||function(){return(new Date).getTime()};var P={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","`":"&#x60;"},N=$.invert(P),j=function(e){var t=function(t){return e[t]},n="(?:"+$.keys(e).join("|")+")",i=RegExp(n),r=RegExp(n,"g");return function(e){return e=null==e?"":""+e,i.test(e)?e.replace(r,t):e}};$.escape=j(P),$.unescape=j(N),$.result=function(e,t,n){var i=null==e?void 0:e[t];return void 0===i&&(i=n),$.isFunction(i)?i.call(e):i};var F=0;$.uniqueId=function(e){var t=++F+"";return e?e+t:t},$.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var L=/(.)^/,R={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},V=/\\|'|\r|\n|\u2028|\u2029/g,H=function(e){return"\\"+R[e]};$.template=function(e,t,n){!t&&n&&(t=n),t=$.defaults({},t,$.templateSettings);var i=RegExp([(t.escape||L).source,(t.interpolate||L).source,(t.evaluate||L).source].join("|")+"|$","g"),r=0,o="__p+='";e.replace(i,function(t,n,i,a,s){return o+=e.slice(r,s).replace(V,H),r=s+t.length,n?o+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'":i?o+="'+\n((__t=("+i+"))==null?'':__t)+\n'":a&&(o+="';\n"+a+"\n__p+='"),t}),o+="';\n",t.variable||(o="with(obj||{}){\n"+o+"}\n"),o="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+o+"return __p;\n";try{var a=new Function(t.variable||"obj","_",o)}catch(e){throw e.source=o,e}var s=function(e){return a.call(this,e,$)};return s.source="function("+(t.variable||"obj")+"){\n"+o+"}",s},$.chain=function(e){var t=$(e);return t._chain=!0,t};var q=function(e,t){return e._chain?$(t).chain():t};$.mixin=function(e){$.each($.functions(e),function(t){var n=$[t]=e[t];$.prototype[t]=function(){var e=[this._wrapped];return c.apply(e,arguments),q(this,n.apply($,e))}})},$.mixin($),$.each(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=a[e];$.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),"shift"!==e&&"splice"!==e||0!==n.length||delete n[0],q(this,n)}}),$.each(["concat","join","slice"],function(e){var t=a[e];$.prototype[e]=function(){return q(this,t.apply(this._wrapped,arguments))}}),$.prototype.value=function(){return this._wrapped},$.prototype.valueOf=$.prototype.toJSON=$.prototype.value,$.prototype.toString=function(){return""+this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return $})}.call(this),"undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(e){"use strict";function t(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var n in t)if(void 0!==e.style[n])return{end:t[n]};return!1}e.fn.emulateTransitionEnd=function(t){var n=!1,i=this;e(this).one("bsTransitionEnd",function(){n=!0});var r=function(){n||e(i).trigger(e.support.transition.end)};return setTimeout(r,t),this},e(function(){e.support.transition=t(),e.support.transition&&(e.event.special.bsTransitionEnd={bindType:e.support.transition.end,delegateType:e.support.transition.end,handle:function(t){if(e(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}})})}(jQuery),function(e){"use strict";function t(t){return this.each(function(){var n=e(this),r=n.data("bs.alert");r||n.data("bs.alert",r=new i(this)),"string"==typeof t&&r[t].call(n)})}var n='[data-dismiss="alert"]',i=function(t){e(t).on("click",n,this.close)};i.VERSION="3.2.0",i.prototype.close=function(t){function n(){o.detach().trigger("closed.bs.alert").remove()}var i=e(this),r=i.attr("data-target");r||(r=i.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));var o=e(r);t&&t.preventDefault(),o.length||(o=i.hasClass("alert")?i:i.parent()),o.trigger(t=e.Event("close.bs.alert")),t.isDefaultPrevented()||(o.removeClass("in"),e.support.transition&&o.hasClass("fade")?o.one("bsTransitionEnd",n).emulateTransitionEnd(150):n())};var r=e.fn.alert;e.fn.alert=t,e.fn.alert.Constructor=i,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.bs.alert.data-api",n,i.prototype.close)}(jQuery),function(e){"use strict";function t(t){return this.each(function(){var i=e(this),r=i.data("bs.button"),o="object"==typeof t&&t;r||i.data("bs.button",r=new n(this,o)),"toggle"==t?r.toggle():t&&r.setState(t)})}var n=function(t,i){this.$element=e(t),this.options=e.extend({},n.DEFAULTS,i),this.isLoading=!1};n.VERSION="3.2.0",n.DEFAULTS={loadingText:"loading..."},n.prototype.setState=function(t){var n="disabled",i=this.$element,r=i.is("input")?"val":"html",o=i.data();t+="Text",null==o.resetText&&i.data("resetText",i[r]()),i[r](null==o[t]?this.options[t]:o[t]),setTimeout(e.proxy(function(){"loadingText"==t?(this.isLoading=!0,i.addClass(n).attr(n,n)):this.isLoading&&(this.isLoading=!1,i.removeClass(n).removeAttr(n))},this),0)},n.prototype.toggle=function(){var e=!0,t=this.$element.closest('[data-toggle="buttons"]');if(t.length){var n=this.$element.find("input");"radio"==n.prop("type")&&(n.prop("checked")&&this.$element.hasClass("active")?e=!1:t.find(".active").removeClass("active")),e&&n.prop("checked",!this.$element.hasClass("active")).trigger("change")}e&&this.$element.toggleClass("active")};var i=e.fn.button;e.fn.button=t,e.fn.button.Constructor=n,e.fn.button.noConflict=function(){return e.fn.button=i,this},e(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(n){var i=e(n.target);i.hasClass("btn")||(i=i.closest(".btn")),t.call(i,"toggle"),n.preventDefault()})}(jQuery),function(e){"use strict";function t(t){return this.each(function(){var i=e(this),r=i.data("bs.carousel"),o=e.extend({},n.DEFAULTS,i.data(),"object"==typeof t&&t),a="string"==typeof t?t:o.slide;r||i.data("bs.carousel",r=new n(this,o)),"number"==typeof t?r.to(t):a?r[a]():o.interval&&r.pause().cycle()})}var n=function(t,n){this.$element=e(t).on("keydown.bs.carousel",e.proxy(this.keydown,this)),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter.bs.carousel",e.proxy(this.pause,this)).on("mouseleave.bs.carousel",e.proxy(this.cycle,this))};n.VERSION="3.2.0",n.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},n.prototype.keydown=function(e){switch(e.which){case 37:this.prev();break;case 39:this.next();break;default:return}e.preventDefault()},n.prototype.cycle=function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},n.prototype.getItemIndex=function(e){return this.$items=e.parent().children(".item"),this.$items.index(e||this.$active)},n.prototype.to=function(t){var n=this,i=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(t>this.$items.length-1||t<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){n.to(t)}):i==t?this.pause().cycle():this.slide(t>i?"next":"prev",e(this.$items[t]))},n.prototype.pause=function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition&&(this.$element.trigger(e.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},n.prototype.next=function(){if(!this.sliding)return this.slide("next")},n.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},n.prototype.slide=function(t,n){var i=this.$element.find(".item.active"),r=n||i[t](),o=this.interval,a="next"==t?"left":"right",s="next"==t?"first":"last",l=this;if(!r.length){if(!this.options.wrap)return;r=this.$element.find(".item")[s]()}if(r.hasClass("active"))return this.sliding=!1;var c=r[0],u=e.Event("slide.bs.carousel",{relatedTarget:c,direction:a});if(this.$element.trigger(u),!u.isDefaultPrevented()){if(this.sliding=!0,o&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var d=e(this.$indicators.children()[this.getItemIndex(r)]);d&&d.addClass("active")}var f=e.Event("slid.bs.carousel",{relatedTarget:c,direction:a});return e.support.transition&&this.$element.hasClass("slide")?(r.addClass(t),r[0].offsetWidth,i.addClass(a),r.addClass(a),i.one("bsTransitionEnd",function(){r.removeClass([t,a].join(" ")).addClass("active"),i.removeClass(["active",a].join(" ")),l.sliding=!1,setTimeout(function(){l.$element.trigger(f)},0)}).emulateTransitionEnd(1e3*i.css("transition-duration").slice(0,-1))):(i.removeClass("active"),r.addClass("active"),this.sliding=!1,this.$element.trigger(f)),o&&this.cycle(),this}};var i=e.fn.carousel;e.fn.carousel=t,e.fn.carousel.Constructor=n,e.fn.carousel.noConflict=function(){return e.fn.carousel=i,this},e(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(n){var i,r=e(this),o=e(r.attr("data-target")||(i=r.attr("href"))&&i.replace(/.*(?=#[^\s]+$)/,""));if(o.hasClass("carousel")){var a=e.extend({},o.data(),r.data()),s=r.attr("data-slide-to");s&&(a.interval=!1),t.call(o,a),s&&o.data("bs.carousel").to(s),n.preventDefault()}}),e(window).on("load",function(){e('[data-ride="carousel"]').each(function(){var n=e(this);t.call(n,n.data())})})}(jQuery),function(e){"use strict";function t(t){return this.each(function(){var i=e(this),r=i.data("bs.collapse"),o=e.extend({},n.DEFAULTS,i.data(),"object"==typeof t&&t);!r&&o.toggle&&"show"==t&&(t=!t),r||i.data("bs.collapse",r=new n(this,o)),"string"==typeof t&&r[t]()})}var n=function(t,i){this.$element=e(t),this.options=e.extend({},n.DEFAULTS,i),this.transitioning=null,this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};n.VERSION="3.2.0",n.DEFAULTS={toggle:!0},n.prototype.dimension=function(){return this.$element.hasClass("width")?"width":"height"},n.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var n=e.Event("show.bs.collapse");if(this.$element.trigger(n),!n.isDefaultPrevented()){var i=this.$parent&&this.$parent.find("> .panel > .in");if(i&&i.length){var r=i.data("bs.collapse");if(r&&r.transitioning)return;t.call(i,"hide"),r||i.data("bs.collapse",null)}var o=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[o](0),this.transitioning=1;var a=function(){this.$element.removeClass("collapsing").addClass("collapse in")[o](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!e.support.transition)return a.call(this);var s=e.camelCase(["scroll",o].join("-"));this.$element.one("bsTransitionEnd",e.proxy(a,this)).emulateTransitionEnd(350)[o](this.$element[0][s])}}},n.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var t=e.Event("hide.bs.collapse");if(this.$element.trigger(t),!t.isDefaultPrevented()){var n=this.dimension();this.$element[n](this.$element[n]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var i=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};if(!e.support.transition)return i.call(this);this.$element[n](0).one("bsTransitionEnd",e.proxy(i,this)).emulateTransitionEnd(350)}}},n.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var i=e.fn.collapse;e.fn.collapse=t,e.fn.collapse.Constructor=n,e.fn.collapse.noConflict=function(){return e.fn.collapse=i,this},e(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(n){var i,r=e(this),o=r.attr("data-target")||n.preventDefault()||(i=r.attr("href"))&&i.replace(/.*(?=#[^\s]+$)/,""),a=e(o),s=a.data("bs.collapse"),l=s?"toggle":r.data(),c=r.attr("data-parent"),u=c&&e(c);s&&s.transitioning||(u&&u.find('[data-toggle="collapse"][data-parent="'+c+'"]').not(r).addClass("collapsed"),r[a.hasClass("in")?"addClass":"removeClass"]("collapsed")),t.call(a,l)})}(jQuery),function(e){"use strict";function t(t){t&&3===t.which||(e(r).remove(),e(o).each(function(){var i=n(e(this)),r={relatedTarget:this};i.hasClass("open")&&(i.trigger(t=e.Event("hide.bs.dropdown",r)),t.isDefaultPrevented()||i.removeClass("open").trigger("hidden.bs.dropdown",r))}))}function n(t){var n=t.attr("data-target");n||(n=t.attr("href"),n=n&&/#[A-Za-z]/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,""));var i=n&&e(n);return i&&i.length?i:t.parent()}function i(t){return this.each(function(){var n=e(this),i=n.data("bs.dropdown");i||n.data("bs.dropdown",i=new a(this)),"string"==typeof t&&i[t].call(n)})}var r=".dropdown-backdrop",o='[data-toggle="dropdown"]',a=function(t){e(t).on("click.bs.dropdown",this.toggle)};a.VERSION="3.2.0",a.prototype.toggle=function(i){var r=e(this);if(!r.is(".disabled, :disabled")){var o=n(r),a=o.hasClass("open");if(t(),!a){"ontouchstart"in document.documentElement&&!o.closest(".navbar-nav").length&&e('<div class="dropdown-backdrop"/>').insertAfter(e(this)).on("click",t);var s={relatedTarget:this};if(o.trigger(i=e.Event("show.bs.dropdown",s)),i.isDefaultPrevented())return;r.trigger("focus"),o.toggleClass("open").trigger("shown.bs.dropdown",s)}return!1}},a.prototype.keydown=function(t){if(/(38|40|27)/.test(t.keyCode)){var i=e(this);if(t.preventDefault(),t.stopPropagation(),!i.is(".disabled, :disabled")){var r=n(i),a=r.hasClass("open");if(!a||a&&27==t.keyCode)return 27==t.which&&r.find(o).trigger("focus"),i.trigger("click");var s=" li:not(.divider):visible a",l=r.find('[role="menu"]'+s+', [role="listbox"]'+s);if(l.length){var c=l.index(l.filter(":focus"));38==t.keyCode&&c>0&&c--,40==t.keyCode&&c<l.length-1&&c++,~c||(c=0),l.eq(c).trigger("focus")}}}};var s=e.fn.dropdown;e.fn.dropdown=i,e.fn.dropdown.Constructor=a,e.fn.dropdown.noConflict=function(){return e.fn.dropdown=s,this},e(document).on("click.bs.dropdown.data-api",t).on("click.bs.dropdown.data-api",".dropdown form",function(e){e.stopPropagation()}).on("click.bs.dropdown.data-api",o,a.prototype.toggle).on("keydown.bs.dropdown.data-api",o+', [role="menu"], [role="listbox"]',a.prototype.keydown)}(jQuery),function(e){"use strict";function t(t,i){return this.each(function(){var r=e(this),o=r.data("bs.modal"),a=e.extend({},n.DEFAULTS,r.data(),"object"==typeof t&&t);o||r.data("bs.modal",o=new n(this,a)),"string"==typeof t?o[t](i):a.show&&o.show(i)})}var n=function(t,n){this.options=n,this.$body=e(document.body),this.$element=e(t),this.$backdrop=this.isShown=null,this.scrollbarWidth=0,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,e.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};n.VERSION="3.2.0",n.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},n.prototype.toggle=function(e){return this.isShown?this.hide():this.show(e)},n.prototype.show=function(t){var n=this,i=e.Event("show.bs.modal",{relatedTarget:t});this.$element.trigger(i),this.isShown||i.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.$body.addClass("modal-open"),this.setScrollbar(),this.escape(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',e.proxy(this.hide,this)),this.backdrop(function(){var i=e.support.transition&&n.$element.hasClass("fade");n.$element.parent().length||n.$element.appendTo(n.$body),n.$element.show().scrollTop(0),i&&n.$element[0].offsetWidth,n.$element.addClass("in").attr("aria-hidden",!1),n.enforceFocus();var r=e.Event("shown.bs.modal",{relatedTarget:t});i?n.$element.find(".modal-dialog").one("bsTransitionEnd",function(){n.$element.trigger("focus").trigger(r)}).emulateTransitionEnd(300):n.$element.trigger("focus").trigger(r)}))},n.prototype.hide=function(t){t&&t.preventDefault(),t=e.Event("hide.bs.modal"),this.$element.trigger(t),this.isShown&&!t.isDefaultPrevented()&&(this.isShown=!1,this.$body.removeClass("modal-open"),this.resetScrollbar(),this.escape(),e(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.bs.modal"),e.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",e.proxy(this.hideModal,this)).emulateTransitionEnd(300):this.hideModal())},n.prototype.enforceFocus=function(){e(document).off("focusin.bs.modal").on("focusin.bs.modal",e.proxy(function(e){this.$element[0]===e.target||this.$element.has(e.target).length||this.$element.trigger("focus")},this))},n.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.bs.modal",e.proxy(function(e){27==e.which&&this.hide()},this)):this.isShown||this.$element.off("keyup.dismiss.bs.modal")},n.prototype.hideModal=function(){var e=this;this.$element.hide(),this.backdrop(function(){e.$element.trigger("hidden.bs.modal")})},n.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},n.prototype.backdrop=function(t){var n=this,i=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var r=e.support.transition&&i;if(this.$backdrop=e('<div class="modal-backdrop '+i+'" />').appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",e.proxy(function(e){e.target===e.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),r&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!t)return;r?this.$backdrop.one("bsTransitionEnd",t).emulateTransitionEnd(150):t()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var o=function(){n.removeBackdrop(),t&&t()};e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",o).emulateTransitionEnd(150):o()}else t&&t()},n.prototype.checkScrollbar=function(){document.body.clientWidth>=window.innerWidth||(this.scrollbarWidth=this.scrollbarWidth||this.measureScrollbar())},n.prototype.setScrollbar=function(){var e=parseInt(this.$body.css("padding-right")||0,10);this.scrollbarWidth&&this.$body.css("padding-right",e+this.scrollbarWidth)},n.prototype.resetScrollbar=function(){this.$body.css("padding-right","")},n.prototype.measureScrollbar=function(){var e=document.createElement("div");e.className="modal-scrollbar-measure",this.$body.append(e);var t=e.offsetWidth-e.clientWidth;return this.$body[0].removeChild(e),t};var i=e.fn.modal;e.fn.modal=t,e.fn.modal.Constructor=n,e.fn.modal.noConflict=function(){return e.fn.modal=i,this},e(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(n){var i=e(this),r=i.attr("href"),o=e(i.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),a=o.data("bs.modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},o.data(),i.data());i.is("a")&&n.preventDefault(),o.one("show.bs.modal",function(e){e.isDefaultPrevented()||o.one("hidden.bs.modal",function(){i.is(":visible")&&i.trigger("focus")})}),t.call(o,a,this)})}(jQuery),function(e){"use strict";function t(t){return this.each(function(){var i=e(this),r=i.data("bs.tooltip"),o="object"==typeof t&&t;(r||"destroy"!=t)&&(r||i.data("bs.tooltip",r=new n(this,o)),"string"==typeof t&&r[t]())})}var n=function(e,t){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",e,t)};n.VERSION="3.2.0",n.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},n.prototype.init=function(t,n,i){this.enabled=!0,this.type=t,this.$element=e(n),this.options=this.getOptions(i),this.$viewport=this.options.viewport&&e(this.options.viewport.selector||this.options.viewport);for(var r=this.options.trigger.split(" "),o=r.length;o--;){var a=r[o];if("click"==a)this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this));else if("manual"!=a){var s="hover"==a?"mouseenter":"focusin",l="hover"==a?"mouseleave":"focusout";this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(l+"."+this.type,this.options.selector,e.proxy(this.leave,this))}}this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},n.prototype.getDefaults=function(){return n.DEFAULTS},n.prototype.getOptions=function(t){return t=e.extend({},this.getDefaults(),this.$element.data(),t),t.delay&&"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),t},n.prototype.getDelegateOptions=function(){var t={},n=this.getDefaults();return this._options&&e.each(this._options,function(e,i){n[e]!=i&&(t[e]=i)}),t},n.prototype.enter=function(t){var n=t instanceof this.constructor?t:e(t.currentTarget).data("bs."+this.type);if(n||(n=new this.constructor(t.currentTarget,this.getDelegateOptions()),e(t.currentTarget).data("bs."+this.type,n)),clearTimeout(n.timeout),n.hoverState="in",!n.options.delay||!n.options.delay.show)return n.show();n.timeout=setTimeout(function(){"in"==n.hoverState&&n.show()},n.options.delay.show)},n.prototype.leave=function(t){var n=t instanceof this.constructor?t:e(t.currentTarget).data("bs."+this.type);if(n||(n=new this.constructor(t.currentTarget,this.getDelegateOptions()),e(t.currentTarget).data("bs."+this.type,n)),clearTimeout(n.timeout),n.hoverState="out",!n.options.delay||!n.options.delay.hide)return n.hide();n.timeout=setTimeout(function(){"out"==n.hoverState&&n.hide()},n.options.delay.hide)},n.prototype.show=function(){var t=e.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(t);var n=e.contains(document.documentElement,this.$element[0]);if(t.isDefaultPrevented()||!n)return;var i=this,r=this.tip(),o=this.getUID(this.type);this.setContent(),r.attr("id",o),this.$element.attr("aria-describedby",o),this.options.animation&&r.addClass("fade");var a="function"==typeof this.options.placement?this.options.placement.call(this,r[0],this.$element[0]):this.options.placement,s=/\s?auto?\s?/i,l=s.test(a);l&&(a=a.replace(s,"")||"top"),r.detach().css({top:0,left:0,display:"block"}).addClass(a).data("bs."+this.type,this),this.options.container?r.appendTo(this.options.container):r.insertAfter(this.$element);var c=this.getPosition(),u=r[0].offsetWidth,d=r[0].offsetHeight;if(l){var f=a,p=this.$element.parent(),h=this.getPosition(p);a="bottom"==a&&c.top+c.height+d-h.scroll>h.height?"top":"top"==a&&c.top-h.scroll-d<0?"bottom":"right"==a&&c.right+u>h.width?"left":"left"==a&&c.left-u<h.left?"right":a,r.removeClass(f).addClass(a)}var g=this.getCalculatedOffset(a,c,u,d);this.applyPlacement(g,a);var m=function(){i.$element.trigger("shown.bs."+i.type),i.hoverState=null};e.support.transition&&this.$tip.hasClass("fade")?r.one("bsTransitionEnd",m).emulateTransitionEnd(150):m()}},n.prototype.applyPlacement=function(t,n){var i=this.tip(),r=i[0].offsetWidth,o=i[0].offsetHeight,a=parseInt(i.css("margin-top"),10),s=parseInt(i.css("margin-left"),10);isNaN(a)&&(a=0),isNaN(s)&&(s=0),t.top=t.top+a,t.left=t.left+s,e.offset.setOffset(i[0],e.extend({using:function(e){i.css({top:Math.round(e.top),left:Math.round(e.left)})}},t),0),i.addClass("in");var l=i[0].offsetWidth,c=i[0].offsetHeight;"top"==n&&c!=o&&(t.top=t.top+o-c);var u=this.getViewportAdjustedDelta(n,t,l,c);u.left?t.left+=u.left:t.top+=u.top;var d=u.left?2*u.left-r+l:2*u.top-o+c,f=u.left?"left":"top",p=u.left?"offsetWidth":"offsetHeight";i.offset(t),this.replaceArrow(d,i[0][p],f)},n.prototype.replaceArrow=function(e,t,n){this.arrow().css(n,e?50*(1-e/t)+"%":"")},n.prototype.setContent=function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},n.prototype.hide=function(){function t(){"in"!=n.hoverState&&i.detach(),n.$element.trigger("hidden.bs."+n.type)}var n=this,i=this.tip(),r=e.Event("hide.bs."+this.type);if(this.$element.removeAttr("aria-describedby"),this.$element.trigger(r),!r.isDefaultPrevented())return i.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?i.one("bsTransitionEnd",t).emulateTransitionEnd(150):t(),this.hoverState=null,this},n.prototype.fixTitle=function(){var e=this.$element;(e.attr("title")||"string"!=typeof e.attr("data-original-title"))&&e.attr("data-original-title",e.attr("title")||"").attr("title","")},n.prototype.hasContent=function(){return this.getTitle()},n.prototype.getPosition=function(t){t=t||this.$element;var n=t[0],i="BODY"==n.tagName;return e.extend({},"function"==typeof n.getBoundingClientRect?n.getBoundingClientRect():null,{scroll:i?document.documentElement.scrollTop||document.body.scrollTop:t.scrollTop(),width:i?e(window).width():t.outerWidth(),height:i?e(window).height():t.outerHeight()},i?{top:0,left:0}:t.offset())},n.prototype.getCalculatedOffset=function(e,t,n,i){return"bottom"==e?{top:t.top+t.height,left:t.left+t.width/2-n/2}:"top"==e?{top:t.top-i,left:t.left+t.width/2-n/2}:"left"==e?{top:t.top+t.height/2-i/2,left:t.left-n}:{top:t.top+t.height/2-i/2,left:t.left+t.width}},n.prototype.getViewportAdjustedDelta=function(e,t,n,i){var r={top:0,left:0};if(!this.$viewport)return r;var o=this.options.viewport&&this.options.viewport.padding||0,a=this.getPosition(this.$viewport);if(/right|left/.test(e)){var s=t.top-o-a.scroll,l=t.top+o-a.scroll+i;s<a.top?r.top=a.top-s:l>a.top+a.height&&(r.top=a.top+a.height-l)}else{var c=t.left-o,u=t.left+o+n;c<a.left?r.left=a.left-c:u>a.width&&(r.left=a.left+a.width-u)}return r},n.prototype.getTitle=function(){var e=this.$element,t=this.options;return e.attr("data-original-title")||("function"==typeof t.title?t.title.call(e[0]):t.title)},n.prototype.getUID=function(e){do{e+=~~(1e6*Math.random())}while(document.getElementById(e));return e},n.prototype.tip=function(){return this.$tip=this.$tip||e(this.options.template)},n.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},n.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},n.prototype.enable=function(){this.enabled=!0},n.prototype.disable=function(){this.enabled=!1},n.prototype.toggleEnabled=function(){this.enabled=!this.enabled},n.prototype.toggle=function(t){var n=this;t&&((n=e(t.currentTarget).data("bs."+this.type))||(n=new this.constructor(t.currentTarget,this.getDelegateOptions()),e(t.currentTarget).data("bs."+this.type,n))),n.tip().hasClass("in")?n.leave(n):n.enter(n)},n.prototype.destroy=function(){clearTimeout(this.timeout),this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var i=e.fn.tooltip;e.fn.tooltip=t,e.fn.tooltip.Constructor=n,e.fn.tooltip.noConflict=function(){return e.fn.tooltip=i,this}}(jQuery),function(e){"use strict";function t(t){return this.each(function(){var i=e(this),r=i.data("bs.popover"),o="object"==typeof t&&t;(r||"destroy"!=t)&&(r||i.data("bs.popover",r=new n(this,o)),"string"==typeof t&&r[t]())})}var n=function(e,t){this.init("popover",e,t)};if(!e.fn.tooltip)throw new Error("Popover requires tooltip.js");n.VERSION="3.2.0",n.DEFAULTS=e.extend({},e.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),n.prototype=e.extend({},e.fn.tooltip.Constructor.prototype),n.prototype.constructor=n,n.prototype.getDefaults=function(){return n.DEFAULTS},n.prototype.setContent=function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content").empty()[this.options.html?"string"==typeof n?"html":"append":"text"](n),e.removeClass("fade top bottom left right in"),e.find(".popover-title").html()||e.find(".popover-title").hide()},n.prototype.hasContent=function(){return this.getTitle()||this.getContent()},n.prototype.getContent=function(){var e=this.$element,t=this.options;return e.attr("data-content")||("function"==typeof t.content?t.content.call(e[0]):t.content)},n.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},n.prototype.tip=function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip};var i=e.fn.popover;e.fn.popover=t,e.fn.popover.Constructor=n,e.fn.popover.noConflict=function(){return e.fn.popover=i,this}}(jQuery),function(e){"use strict";function t(n,i){var r=e.proxy(this.process,this);this.$body=e("body"),this.$scrollElement=e(e(n).is("body")?window:n),this.options=e.extend({},t.DEFAULTS,i),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",r),this.refresh(),this.process()}function n(n){return this.each(function(){var i=e(this),r=i.data("bs.scrollspy"),o="object"==typeof n&&n;r||i.data("bs.scrollspy",r=new t(this,o)),"string"==typeof n&&r[n]()})}t.VERSION="3.2.0",t.DEFAULTS={offset:10},t.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},t.prototype.refresh=function(){var t="offset",n=0;e.isWindow(this.$scrollElement[0])||(t="position",n=this.$scrollElement.scrollTop()),this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight();var i=this;this.$body.find(this.selector).map(function(){var i=e(this),r=i.data("target")||i.attr("href"),o=/^#./.test(r)&&e(r);return o&&o.length&&o.is(":visible")&&[[o[t]().top+n,r]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){i.offsets.push(this[0]),i.targets.push(this[1])})},t.prototype.process=function(){var e,t=this.$scrollElement.scrollTop()+this.options.offset,n=this.getScrollHeight(),i=this.options.offset+n-this.$scrollElement.height(),r=this.offsets,o=this.targets,a=this.activeTarget;if(this.scrollHeight!=n&&this.refresh(),t>=i)return a!=(e=o[o.length-1])&&this.activate(e);if(a&&t<=r[0])return a!=(e=o[0])&&this.activate(e);for(e=r.length;e--;)a!=o[e]&&t>=r[e]&&(!r[e+1]||t<=r[e+1])&&this.activate(o[e])},
+t.prototype.activate=function(t){this.activeTarget=t,e(this.selector).parentsUntil(this.options.target,".active").removeClass("active");var n=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',i=e(n).parents("li").addClass("active");i.parent(".dropdown-menu").length&&(i=i.closest("li.dropdown").addClass("active")),i.trigger("activate.bs.scrollspy")};var i=e.fn.scrollspy;e.fn.scrollspy=n,e.fn.scrollspy.Constructor=t,e.fn.scrollspy.noConflict=function(){return e.fn.scrollspy=i,this},e(window).on("load.bs.scrollspy.data-api",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);n.call(t,t.data())})})}(jQuery),function(e){"use strict";function t(t){return this.each(function(){var i=e(this),r=i.data("bs.tab");r||i.data("bs.tab",r=new n(this)),"string"==typeof t&&r[t]()})}var n=function(t){this.element=e(t)};n.VERSION="3.2.0",n.prototype.show=function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),i=t.data("target");if(i||(i=t.attr("href"),i=i&&i.replace(/.*(?=#[^\s]*$)/,"")),!t.parent("li").hasClass("active")){var r=n.find(".active:last a")[0],o=e.Event("show.bs.tab",{relatedTarget:r});if(t.trigger(o),!o.isDefaultPrevented()){var a=e(i);this.activate(t.closest("li"),n),this.activate(a,a.parent(),function(){t.trigger({type:"shown.bs.tab",relatedTarget:r})})}}},n.prototype.activate=function(t,n,i){function r(){o.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),a?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),i&&i()}var o=n.find("> .active"),a=i&&e.support.transition&&o.hasClass("fade");a?o.one("bsTransitionEnd",r).emulateTransitionEnd(150):r(),o.removeClass("in")};var i=e.fn.tab;e.fn.tab=t,e.fn.tab.Constructor=n,e.fn.tab.noConflict=function(){return e.fn.tab=i,this},e(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(n){n.preventDefault(),t.call(e(this),"show")})}(jQuery),function(e){"use strict";function t(t){return this.each(function(){var i=e(this),r=i.data("bs.affix"),o="object"==typeof t&&t;r||i.data("bs.affix",r=new n(this,o)),"string"==typeof t&&r[t]()})}var n=function(t,i){this.options=e.extend({},n.DEFAULTS,i),this.$target=e(this.options.target).on("scroll.bs.affix.data-api",e.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",e.proxy(this.checkPositionWithEventLoop,this)),this.$element=e(t),this.affixed=this.unpin=this.pinnedOffset=null,this.checkPosition()};n.VERSION="3.2.0",n.RESET="affix affix-top affix-bottom",n.DEFAULTS={offset:0,target:window},n.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(n.RESET).addClass("affix");var e=this.$target.scrollTop(),t=this.$element.offset();return this.pinnedOffset=t.top-e},n.prototype.checkPositionWithEventLoop=function(){setTimeout(e.proxy(this.checkPosition,this),1)},n.prototype.checkPosition=function(){if(this.$element.is(":visible")){var t=e(document).height(),i=this.$target.scrollTop(),r=this.$element.offset(),o=this.options.offset,a=o.top,s=o.bottom;"object"!=typeof o&&(s=a=o),"function"==typeof a&&(a=o.top(this.$element)),"function"==typeof s&&(s=o.bottom(this.$element));var l=!(null!=this.unpin&&i+this.unpin<=r.top)&&(null!=s&&r.top+this.$element.height()>=t-s?"bottom":null!=a&&i<=a&&"top");if(this.affixed!==l){null!=this.unpin&&this.$element.css("top","");var c="affix"+(l?"-"+l:""),u=e.Event(c+".bs.affix");this.$element.trigger(u),u.isDefaultPrevented()||(this.affixed=l,this.unpin="bottom"==l?this.getPinnedOffset():null,this.$element.removeClass(n.RESET).addClass(c).trigger(e.Event(c.replace("affix","affixed"))),"bottom"==l&&this.$element.offset({top:t-this.$element.height()-s}))}}};var i=e.fn.affix;e.fn.affix=t,e.fn.affix.Constructor=n,e.fn.affix.noConflict=function(){return e.fn.affix=i,this},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var n=e(this),i=n.data();i.offset=i.offset||{},i.offsetBottom&&(i.offset.bottom=i.offsetBottom),i.offsetTop&&(i.offset.top=i.offsetTop),t.call(n,i)})})}(jQuery),function(e,t,n){"use strict";function i(e,t){return t=t||Error,function(){var n,i,r=arguments[0],o="["+(e?e+":":"")+r+"] ",a=arguments[1],s=arguments;for(n=o+a.replace(/\{\d+\}/g,function(e){var t,n=+e.slice(1,-1);return n+2<s.length?(t=s[n+2],"function"==typeof t?t.toString().replace(/ ?\{[\s\S]*$/,""):void 0===t?"undefined":"string"!=typeof t?U(t):t):e}),n=n+"\nhttp://errors.angularjs.org/1.3.0/"+(e?e+"/":"")+r,i=2;i<arguments.length;i++)n=n+(2==i?"?":"&")+"p"+(i-2)+"="+encodeURIComponent(function(e){return"function"==typeof e?e.toString().replace(/ \{[\s\S]*$/,""):void 0===e?"undefined":"string"!=typeof e?JSON.stringify(e):e}(arguments[i]));return new t(n)}}function r(e){if(null==e||S(e))return!1;var t=e.length;return!(e.nodeType!==ii||!t)||(b(e)||Zn(e)||0===t||"number"==typeof t&&t>0&&t-1 in e)}function o(e,t,n){var i,a;if(e)if(C(e))for(i in e)"prototype"==i||"length"==i||"name"==i||e.hasOwnProperty&&!e.hasOwnProperty(i)||t.call(n,e[i],i,e);else if(Zn(e)||r(e)){var s="object"!=typeof e;for(i=0,a=e.length;i<a;i++)(s||i in e)&&t.call(n,e[i],i,e)}else if(e.forEach&&e.forEach!==o)e.forEach(t,n,e);else for(i in e)e.hasOwnProperty(i)&&t.call(n,e[i],i,e);return e}function a(e){var t=[];for(var n in e)e.hasOwnProperty(n)&&t.push(n);return t.sort()}function s(e,t,n){for(var i=a(e),r=0;r<i.length;r++)t.call(n,e[i[r]],i[r]);return i}function l(e){return function(t,n){e(n,t)}}function c(){return++Gn}function u(e,t){t?e.$$hashKey=t:delete e.$$hashKey}function d(e){for(var t=e.$$hashKey,n=1,i=arguments.length;n<i;n++){var r=arguments[n];if(r)for(var o=Object.keys(r),a=0,s=o.length;a<s;a++){var l=o[a];e[l]=r[l]}}return u(e,t),e}function f(e){return parseInt(e,10)}function p(e,t){return d(new(d(function(){},{prototype:e})),t)}function h(){}function g(e){return e}function m(e){return function(){return e}}function v(e){return void 0===e}function $(e){return void 0!==e}function y(e){return null!==e&&"object"==typeof e}function b(e){return"string"==typeof e}function w(e){return"number"==typeof e}function x(e){return"[object Date]"===zn.call(e)}function C(e){return"function"==typeof e}function k(e){return"[object RegExp]"===zn.call(e)}function S(e){return e&&e.window===e}function E(e){return e&&e.$evalAsync&&e.$watch}function T(e){return"[object File]"===zn.call(e)}function D(e){return"[object Blob]"===zn.call(e)}function A(e){return"boolean"==typeof e}function M(e){return e&&C(e.then)}function O(e){return!(!e||!(e.nodeName||e.prop&&e.attr&&e.find))}function I(e){var t,n={},i=e.split(",");for(t=0;t<i.length;t++)n[i[t]]=!0;return n}function P(e){return Nn(e.nodeName||e[0].nodeName)}function N(e,t){var n=e.indexOf(t);return n>=0&&e.splice(n,1),t}function j(e,t,n,i){if(S(e)||E(e))throw Yn("cpws","Can't copy! Making copies of Window or Scope instances is not supported.");if(t){if(e===t)throw Yn("cpi","Can't copy! Source and destination are identical.");if(n=n||[],i=i||[],y(e)){var r=n.indexOf(e);if(-1!==r)return i[r];n.push(e),i.push(t)}var a;if(Zn(e)){t.length=0;for(var s=0;s<e.length;s++)a=j(e[s],null,n,i),y(e[s])&&(n.push(e[s]),i.push(a)),t.push(a)}else{var l=t.$$hashKey;Zn(t)?t.length=0:o(t,function(e,n){delete t[n]});for(var c in e)e.hasOwnProperty(c)&&(a=j(e[c],null,n,i),y(e[c])&&(n.push(e[c]),i.push(a)),t[c]=a);u(t,l)}}else if(t=e,e)if(Zn(e))t=j(e,[],n,i);else if(x(e))t=new Date(e.getTime());else if(k(e))t=new RegExp(e.source,e.toString().match(/[^\/]*$/)[0]),t.lastIndex=e.lastIndex;else if(y(e)){var d=Object.create(Object.getPrototypeOf(e));t=j(e,d,n,i)}return t}function F(e,t){if(Zn(e)){t=t||[];for(var n=0,i=e.length;n<i;n++)t[n]=e[n]}else if(y(e)){t=t||{};for(var r in e)"$"===r.charAt(0)&&"$"===r.charAt(1)||(t[r]=e[r])}return t||e}function L(e,t){if(e===t)return!0;if(null===e||null===t)return!1;if(e!==e&&t!==t)return!0;var i,r,o,a=typeof e,s=typeof t;if(a==s&&"object"==a){if(!Zn(e)){if(x(e))return!!x(t)&&L(e.getTime(),t.getTime());if(k(e)&&k(t))return e.toString()==t.toString();if(E(e)||E(t)||S(e)||S(t)||Zn(t))return!1;o={};for(r in e)if("$"!==r.charAt(0)&&!C(e[r])){if(!L(e[r],t[r]))return!1;o[r]=!0}for(r in t)if(!o.hasOwnProperty(r)&&"$"!==r.charAt(0)&&t[r]!==n&&!C(t[r]))return!1;return!0}if(!Zn(t))return!1;if((i=e.length)==t.length){for(r=0;r<i;r++)if(!L(e[r],t[r]))return!1;return!0}}return!1}function R(e,t,n){return e.concat(_n.call(t,n))}function V(e,t){return _n.call(e,t||0)}function H(e,t){var n=arguments.length>2?V(arguments,2):[];return!C(t)||t instanceof RegExp?t:n.length?function(){return arguments.length?t.apply(e,n.concat(_n.call(arguments,0))):t.apply(e,n)}:function(){return arguments.length?t.apply(e,arguments):t.call(e)}}function q(e,i){var r=i;return"string"==typeof e&&"$"===e.charAt(0)&&"$"===e.charAt(1)?r=n:S(i)?r="$WINDOW":i&&t===i?r="$DOCUMENT":E(i)&&(r="$SCOPE"),r}function U(e,t){return void 0===e?n:JSON.stringify(e,q,t?" ":null)}function _(e){return b(e)?JSON.parse(e):e}function B(e){e=Hn(e).clone();try{e.empty()}catch(e){}var t=Hn("<div>").append(e).html();try{return e[0].nodeType===ri?Nn(t):t.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(e,t){return"<"+Nn(t)})}catch(e){return Nn(t)}}function W(e){try{return decodeURIComponent(e)}catch(e){}}function z(e){var t,n,i={};return o((e||"").split("&"),function(e){if(e&&(t=e.replace(/\+/g,"%20").split("="),n=W(t[0]),$(n))){var r=!$(t[1])||W(t[1]);jn.call(i,n)?Zn(i[n])?i[n].push(r):i[n]=[i[n],r]:i[n]=r}}),i}function Y(e){var t=[];return o(e,function(e,n){Zn(e)?o(e,function(e){t.push(G(n,!0)+(!0===e?"":"="+G(e,!0)))}):t.push(G(n,!0)+(!0===e?"":"="+G(e,!0)))}),t.length?t.join("&"):""}function K(e){return G(e,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function G(e,t){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%3B/gi,";").replace(/%20/g,t?"%20":"+")}function X(e,t){var n,i,r=ei.length;for(e=Hn(e),i=0;i<r;++i)if(n=ei[i]+t,b(n=e.attr(n)))return n;return null}function Z(e,t){var n,i,r={};o(ei,function(t){var r=t+"app";!n&&e.hasAttribute&&e.hasAttribute(r)&&(n=e,i=e.getAttribute(r))}),o(ei,function(t){var r,o=t+"app";!n&&(r=e.querySelector("["+o.replace(":","\\:")+"]"))&&(n=r,i=r.getAttribute(o))}),n&&(r.strictDi=null!==X(n,"strict-di"),t(n,i?[i]:[],r))}function J(n,i,r){y(r)||(r={}),r=d({strictDi:!1},r);var a=function(){if(n=Hn(n),n.injector()){var e=n[0]===t?"document":B(n);throw Yn("btstrpd","App Already Bootstrapped with this Element '{0}'",e.replace(/</,"&lt;").replace(/>/,"&gt;"))}i=i||[],i.unshift(["$provide",function(e){e.value("$rootElement",n)}]),r.debugInfoEnabled&&i.push(["$compileProvider",function(e){e.debugInfoEnabled(!0)}]),i.unshift("ng");var o=Re(i,r.strictDi);return o.invoke(["$rootScope","$rootElement","$compile","$injector",function(e,t,n,i){e.$apply(function(){t.data("$injector",i),n(t)(e)})}]),o},s=/^NG_ENABLE_DEBUG_INFO!/,l=/^NG_DEFER_BOOTSTRAP!/;if(e&&s.test(e.name)&&(r.debugInfoEnabled=!0,e.name=e.name.replace(s,"")),e&&!l.test(e.name))return a();e.name=e.name.replace(l,""),Kn.resumeBootstrap=function(e){o(e,function(e){i.push(e)}),a()}}function Q(){e.name="NG_ENABLE_DEBUG_INFO!"+e.name,e.location.reload()}function ee(e){return Kn.element(e).injector().get("$$testability")}function te(e,t){return t=t||"_",e.replace(ti,function(e,n){return(n?t:"")+e.toLowerCase()})}function ne(e,t,n){if(!e)throw Yn("areq","Argument '{0}' is {1}",t||"?",n||"required");return e}function ie(e,t,n){return n&&Zn(e)&&(e=e[e.length-1]),ne(C(e),t,"not a function, got "+(e&&"object"==typeof e?e.constructor.name||"Object":typeof e)),e}function re(e,t){if("hasOwnProperty"===e)throw Yn("badname","hasOwnProperty is not a valid {0} name",t)}function oe(e,t,n){if(!t)return e;for(var i,r=t.split("."),o=e,a=r.length,s=0;s<a;s++)i=r[s],e&&(e=(o=e)[i]);return!n&&C(e)?H(o,e):e}function ae(e){var t=e[0],n=e[e.length-1],i=[t];do{if(!(t=t.nextSibling))break;i.push(t)}while(t!==n);return Hn(i)}function se(){return Object.create(null)}function le(e){function t(e,t,n){return e[t]||(e[t]=n())}var n=i("$injector"),r=i("ng"),o=t(e,"angular",Object);return o.$$minErr=o.$$minErr||i,t(o,"module",function(){var e={};return function(i,o,a){return function(e,t){if("hasOwnProperty"===e)throw r("badname","hasOwnProperty is not a valid {0} name",t)}(i,"module"),o&&e.hasOwnProperty(i)&&(e[i]=null),t(e,i,function(){function e(e,n,i,r){return r||(r=t),function(){return r[i||"push"]([e,n,arguments]),c}}if(!o)throw n("nomod","Module '{0}' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.",i);var t=[],r=[],s=[],l=e("$injector","invoke","push",r),c={_invokeQueue:t,_configBlocks:r,_runBlocks:s,requires:o,name:i,provider:e("$provide","provider"),factory:e("$provide","factory"),service:e("$provide","service"),value:e("$provide","value"),constant:e("$provide","constant","unshift"),animation:e("$animateProvider","register"),filter:e("$filterProvider","register"),controller:e("$controllerProvider","register"),directive:e("$compileProvider","directive"),config:l,run:function(e){return s.push(e),this}};return a&&l(a),c})}})}function ce(){return++ui}function ue(e){return e.replace(pi,function(e,t,n,i){return i?n.toUpperCase():n}).replace(hi,"Moz$1")}function de(e){return!$i.test(e)}function fe(e){var t=e.nodeType;return t===ii||!t||t===ai}function pe(e,t){var n,i,r,a,s=t.createDocumentFragment(),l=[];if(de(e))l.push(t.createTextNode(e));else{for(n=n||s.appendChild(t.createElement("div")),i=(yi.exec(e)||["",""])[1].toLowerCase(),r=wi[i]||wi._default,n.innerHTML=r[1]+e.replace(bi,"<$1></$2>")+r[2],a=r[0];a--;)n=n.lastChild;l=R(l,n.childNodes),n=s.firstChild,n.textContent=""}return s.textContent="",s.innerHTML="",o(l,function(e){s.appendChild(e)}),s}function he(e,n){n=n||t;var i;return(i=vi.exec(e))?[n.createElement(i[1])]:(i=pe(e,n))?i.childNodes:[]}function ge(e){if(e instanceof ge)return e;var t;if(b(e)&&(e=Jn(e),t=!0),!(this instanceof ge)){if(t&&"<"!=e.charAt(0))throw mi("nosel","Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element");return new ge(e)}t?Se(this,he(e)):Se(this,e)}function me(e){return e.cloneNode(!0)}function ve(e,t){if(t||ye(e),e.querySelectorAll)for(var n=e.querySelectorAll("*"),i=0,r=n.length;i<r;i++)ye(n[i])}function $e(e,t,n,i){if($(i))throw mi("offargs","jqLite#off() does not support the `selector` argument");var r=be(e),a=r&&r.events,s=r&&r.handle;if(s)if(t)o(t.split(" "),function(t){if($(n)){var i=a[t];if(N(i||[],n),i&&i.length>0)return}fi(e,t,s),delete a[t]});else for(t in a)"$destroy"!==t&&fi(e,t,s),delete a[t]}function ye(e,t){var i=e.ng339,r=i&&ci[i];if(r){if(t)return void delete r.data[t];r.handle&&(r.events.$destroy&&r.handle({},"$destroy"),$e(e)),delete ci[i],e.ng339=n}}function be(e,t){var i=e.ng339,r=i&&ci[i];return t&&!r&&(e.ng339=i=ce(),r=ci[i]={events:{},data:{},handle:n}),r}function we(e,t,n){if(fe(e)){var i=$(n),r=!i&&t&&!y(t),o=!t,a=be(e,!r),s=a&&a.data;if(i)s[t]=n;else{if(o)return s;if(r)return s&&s[t];d(s,t)}}}function xe(e,t){return!!e.getAttribute&&(" "+(e.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ").indexOf(" "+t+" ")>-1}function Ce(e,t){t&&e.setAttribute&&o(t.split(" "),function(t){e.setAttribute("class",Jn((" "+(e.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ").replace(" "+Jn(t)+" "," ")))})}function ke(e,t){if(t&&e.setAttribute){var n=(" "+(e.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ");o(t.split(" "),function(e){e=Jn(e),-1===n.indexOf(" "+e+" ")&&(n+=e+" ")}),e.setAttribute("class",Jn(n))}}function Se(e,t){if(t)if(t.nodeType)e[e.length++]=t;else{var n=t.length;if("number"==typeof n&&t.window!==t){if(n)for(var i=0;i<n;i++)e[e.length++]=t[i]}else e[e.length++]=t}}function Ee(e,t){return Te(e,"$"+(t||"ngController")+"Controller")}function Te(e,t,i){e.nodeType==ai&&(e=e.documentElement);for(var r=Zn(t)?t:[t];e;){for(var o=0,a=r.length;o<a;o++)if((i=Hn.data(e,r[o]))!==n)return i;e=e.parentNode||e.nodeType===si&&e.host}}function De(e){for(ve(e,!0);e.firstChild;)e.removeChild(e.firstChild)}function Ae(e,t){t||ve(e);var n=e.parentNode;n&&n.removeChild(e)}function Me(t,n){n=n||e,"complete"===n.document.readyState?n.setTimeout(t):Hn(n).on("load",t)}function Oe(e,t){var n=Ci[t.toLowerCase()];return n&&ki[P(e)]&&n}function Ie(e,t){var n=e.nodeName;return("INPUT"===n||"TEXTAREA"===n)&&Si[t]}function Pe(e,t){var n=function(n,i){n.isDefaultPrevented=function(){return n.defaultPrevented};var r=t[i||n.type],o=r?r.length:0;if(o){if(v(n.immediatePropagationStopped)){var a=n.stopImmediatePropagation;n.stopImmediatePropagation=function(){n.immediatePropagationStopped=!0,n.stopPropagation&&n.stopPropagation(),a&&a.call(n)}}n.isImmediatePropagationStopped=function(){return!0===n.immediatePropagationStopped},o>1&&(r=F(r));for(var s=0;s<o;s++)n.isImmediatePropagationStopped()||r[s].call(e,n)}};return n.elem=e,n}function Ne(e,t){var n=e&&e.$$hashKey;if(n)return"function"==typeof n&&(n=e.$$hashKey()),n;var i=typeof e;return n="function"==i||"object"==i&&null!==e?e.$$hashKey=i+":"+(t||c)():i+":"+e}function je(e,t){if(t){var n=0;this.nextUid=function(){return++n}}o(e,this.put,this)}function Fe(e){var t=e.toString().replace(Ai,""),n=t.match(Ei);return n?"function("+(n[1]||"").replace(/[\s\r\n]+/," ")+")":"fn"}function Le(e,t,n){var i,r,a,s;if("function"==typeof e){if(!(i=e.$inject)){if(i=[],e.length){if(t)throw b(n)&&n||(n=e.name||Fe(e)),Mi("strictdi","{0} is not using explicit annotation and cannot be invoked in strict mode",n);r=e.toString().replace(Ai,""),a=r.match(Ei),o(a[1].split(Ti),function(e){e.replace(Di,function(e,t,n){i.push(n)})})}e.$inject=i}}else Zn(e)?(s=e.length-1,ie(e[s],"fn"),i=e.slice(0,s)):ie(e,"fn",!0);return i}function Re(e,t){function i(e){return function(t,n){if(!y(t))return e(t,n);o(t,l(e))}}function r(e,t){if(re(e,"service"),(C(t)||Zn(t))&&(t=E.instantiate(t)),!t.$get)throw Mi("pget","Provider '{0}' must define $get factory method.",e);return S[e+w]=t}function a(e,t){return function(){var i=D.invoke(t,this,n,e);if(v(i))throw Mi("undef","Provider '{0}' must return a value from $get factory method.",e);return i}}function s(e,t,n){return r(e,{$get:!1!==n?a(e,t):t})}function c(e,t){return s(e,["$injector",function(e){return e.instantiate(t)}])}function u(e,t){return s(e,m(t),!1)}function d(e,t){re(e,"constant"),S[e]=t,T[e]=t}function f(e,t){var n=E.get(e+w),i=n.$get;n.$get=function(){var e=D.invoke(i,n);return D.invoke(t,null,{$delegate:e})}}function p(e){var t,n=[];return o(e,function(e){function i(e){var t,n;for(t=0,n=e.length;t<n;t++){var i=e[t],r=E.get(i[0]);r[i[1]].apply(r,i[2])}}if(!k.get(e)){k.put(e,!0);try{b(e)?(t=Un(e),n=n.concat(p(t.requires)).concat(t._runBlocks),i(t._invokeQueue),i(t._configBlocks)):C(e)?n.push(E.invoke(e)):Zn(e)?n.push(E.invoke(e)):ie(e,"module")}catch(t){throw Zn(e)&&(e=e[e.length-1]),t.message&&t.stack&&-1==t.stack.indexOf(t.message)&&(t=t.message+"\n"+t.stack),Mi("modulerr","Failed to instantiate module {0} due to:\n{1}",e,t.stack||t.message||t)}}}),n}function g(e,n){function i(t){if(e.hasOwnProperty(t)){if(e[t]===$)throw Mi("cdep","Circular dependency found: {0}",t+" <- "+x.join(" <- "));return e[t]}try{return x.unshift(t),e[t]=$,e[t]=n(t)}catch(n){throw e[t]===$&&delete e[t],n}finally{x.shift()}}function r(e,n,r,o){"string"==typeof r&&(o=r,r=null);var a,s,l,c=[],u=Le(e,t,o);for(s=0,a=u.length;s<a;s++){if("string"!=typeof(l=u[s]))throw Mi("itkn","Incorrect injection token! Expected service name as string, got {0}",l);c.push(r&&r.hasOwnProperty(l)?r[l]:i(l))}return Zn(e)&&(e=e[a]),e.apply(n,c)}function o(e,t,n){var i,o,a=function(){};return a.prototype=(Zn(e)?e[e.length-1]:e).prototype,i=new a,o=r(e,i,t,n),y(o)||C(o)?o:i}return{invoke:r,instantiate:o,get:i,annotate:Le,has:function(t){return S.hasOwnProperty(t+w)||e.hasOwnProperty(t)}}}t=!0===t;var $={},w="Provider",x=[],k=new je([],!0),S={$provide:{provider:i(r),factory:i(s),service:i(c),value:i(u),constant:i(d),decorator:f}},E=S.$injector=g(S,function(){throw Mi("unpr","Unknown provider: {0}",x.join(" <- "))}),T={},D=T.$injector=g(T,function(e){var t=E.get(e+w);return D.invoke(t.$get,t,n,e)});return o(p(e),function(e){D.invoke(e||h)}),D}function Ve(){var e=!0;this.disableAutoScrolling=function(){e=!1},this.$get=["$window","$location","$rootScope",function(t,n,i){function r(e){var t=null;return Array.prototype.some.call(e,function(e){if("a"===P(e))return t=e,!0}),t}function o(){var e=s.yOffset;if(C(e))e=e();else if(O(e)){var n=e[0],i=t.getComputedStyle(n);e="fixed"!==i.position?0:n.getBoundingClientRect().bottom}else w(e)||(e=0);return e}function a(e){if(e){e.scrollIntoView();var n=o();if(n){var i=e.getBoundingClientRect().top;t.scrollBy(0,i-n)}}else t.scrollTo(0,0)}function s(){var e,t=n.hash();t?(e=l.getElementById(t))?a(e):(e=r(l.getElementsByName(t)))?a(e):"top"===t&&a(null):a(null)}var l=t.document;return e&&i.$watch(function(){return n.hash()},function(e,t){e===t&&""===e||Me(function(){i.$evalAsync(s)})}),s}]}function He(){this.$get=["$$rAF","$timeout",function(e,t){return e.supported?function(t){return e(t)}:function(e){return t(e,0,!1)}}]}function qe(e,t,i,r){function a(e){try{e.apply(null,V(arguments,1))}finally{if(0===--x)for(;C.length;)try{C.pop()()}catch(e){i.error(e)}}}function s(e,t){!function n(){o(S,function(e){e()}),k=t(n,e)}()}function l(){c(),u()}function c(){E=e.history.state,E=v(E)?null:E,L(E,P)&&(E=P),P=E}function u(){D===f.url()&&T===E||(D=f.url(),T=E,o(O,function(e){e(f.url(),E)}))}function d(e){try{return decodeURIComponent(e)}catch(t){return e}}var f=this,p=t[0],g=e.location,m=e.history,$=e.setTimeout,y=e.clearTimeout,w={};f.isMock=!1;var x=0,C=[];f.$$completeOutstandingRequest=a,f.$$incOutstandingRequestCount=function(){x++},f.notifyWhenNoOutstandingRequests=function(e){o(S,function(e){e()}),0===x?e():C.push(e)};var k,S=[];f.addPollFn=function(e){return v(k)&&s(100,$),S.push(e),e};var E,T,D=g.href,A=t.find("base"),M=null;c(),T=E,f.url=function(t,n,i){if(v(i)&&(i=null),g!==e.location&&(g=e.location),m!==e.history&&(m=e.history),t){var o=T===i;if(D===t&&(!r.history||o))return;var a=D&&pt(D)===pt(t);return D=t,T=i,!r.history||a&&o?(a||(M=t),n?g.replace(t):g.href=t):(m[n?"replaceState":"pushState"](i,"",t),c(),T=E),f}return M||g.href.replace(/%27/g,"'")},f.state=function(){return E};var O=[],I=!1,P=null;f.onUrlChange=function(t){return I||(r.history&&Hn(e).on("popstate",l),Hn(e).on("hashchange",l),I=!0),O.push(t),t},f.$$checkUrlChange=u,f.baseHref=function(){var e=A.attr("href");return e?e.replace(/^(https?\:)?\/\/[^\/]*/,""):""};var N={},j="",F=f.baseHref();f.cookies=function(e,t){var r,o,a,s,l;if(!e){if(p.cookie!==j)for(j=p.cookie,o=j.split("; "),N={},s=0;s<o.length;s++)a=o[s],(l=a.indexOf("="))>0&&(e=d(a.substring(0,l)),N[e]===n&&(N[e]=d(a.substring(l+1))));return N}t===n?p.cookie=encodeURIComponent(e)+"=;path="+F+";expires=Thu, 01 Jan 1970 00:00:00 GMT":b(t)&&(r=(p.cookie=encodeURIComponent(e)+"="+encodeURIComponent(t)+";path="+F).length+1)>4096&&i.warn("Cookie '"+e+"' possibly not set or overflowed because it was too large ("+r+" > 4096 bytes)!")},f.defer=function(e,t){var n;return x++,n=$(function(){delete w[n],a(e)},t||0),w[n]=!0,n},f.defer.cancel=function(e){return!!w[e]&&(delete w[e],y(e),a(h),!0)}}function Ue(){this.$get=["$window","$log","$sniffer","$document",function(e,t,n,i){return new qe(e,i,t,n)}]}function _e(){this.$get=function(){function e(e,n){function r(e){e!=f&&(p?p==e&&(p=e.n):p=e,o(e.n,e.p),o(e,f),f=e,f.n=null)}function o(e,t){e!=t&&(e&&(e.p=t),t&&(t.n=e))}if(e in t)throw i("$cacheFactory")("iid","CacheId '{0}' is already taken!",e);var a=0,s=d({},n,{id:e}),l={},c=n&&n.capacity||Number.MAX_VALUE,u={},f=null,p=null;return t[e]={put:function(e,t){if(c<Number.MAX_VALUE){r(u[e]||(u[e]={key:e}))}if(!v(t))return e in l||a++,l[e]=t,a>c&&this.remove(p.key),t},get:function(e){if(c<Number.MAX_VALUE){var t=u[e];if(!t)return;r(t)}return l[e]},remove:function(e){if(c<Number.MAX_VALUE){var t=u[e];if(!t)return;t==f&&(f=t.p),t==p&&(p=t.n),o(t.n,t.p),delete u[e]}delete l[e],a--},removeAll:function(){l={},a=0,u={},f=p=null},destroy:function(){l=null,s=null,u=null,delete t[e]},info:function(){return d({},s,{size:a})}}}var t={};return e.info=function(){var e={};return o(t,function(t,n){e[n]=t.info()}),e},e.get=function(e){return t[e]},e}}function Be(){this.$get=["$cacheFactory",function(e){return e("templates")}]}function We(e,i){function r(e,t){var n=/^\s*([@=&])(\??)\s*(\w*)\s*$/,i={};return o(e,function(e,r){var o=e.match(n);if(!o)throw Pi("iscp","Invalid isolate scope definition for directive '{0}'. Definition: {... {1}: '{2}' ...}",t,r,e);i[r]={attrName:o[3]||r,mode:o[1],optional:"?"===o[2]}}),i}var a={},s="Directive",c=/^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,u=/(([\d\w_\-]+)(?:\:([^;]+))?;?)/,f=I("ngSrc,ngSrcset,src,srcset"),v=/^(?:(\^\^?)?(\?)?(\^\^?)?)?/,w=/^(on[a-z]+|formaction)$/;this.directive=function t(n,i){return re(n,"directive"),b(n)?(ne(i,"directiveFactory"),a.hasOwnProperty(n)||(a[n]=[],e.factory(n+s,["$injector","$exceptionHandler",function(e,t){var i=[];return o(a[n],function(o,a){try{var s=e.invoke(o);C(s)?s={compile:m(s)}:!s.compile&&s.link&&(s.compile=m(s.link)),s.priority=s.priority||0,s.index=a,s.name=s.name||n,s.require=s.require||s.controller&&s.name,s.restrict=s.restrict||"EA",y(s.scope)&&(s.$$isolateBindings=r(s.scope,s.name)),i.push(s)}catch(e){t(e)}}),i}])),a[n].push(i)):o(n,l(t)),this},this.aHrefSanitizationWhitelist=function(e){return $(e)?(i.aHrefSanitizationWhitelist(e),this):i.aHrefSanitizationWhitelist()},this.imgSrcSanitizationWhitelist=function(e){return $(e)?(i.imgSrcSanitizationWhitelist(e),this):i.imgSrcSanitizationWhitelist()};var x=!0;this.debugInfoEnabled=function(e){return $(e)?(x=e,this):x},this.$get=["$injector","$interpolate","$exceptionHandler","$templateRequest","$parse","$controller","$rootScope","$document","$sce","$animate","$$sanitizeUri",function(e,i,r,l,m,$,k,S,T,D,A){function M(e,t){try{e.addClass(t)}catch(e){}}function O(e,t,n,i,r){e instanceof Hn||(e=Hn(e)),o(e,function(t,n){t.nodeType==ri&&t.nodeValue.match(/\S+/)&&(e[n]=Hn(t).wrap("<span></span>").parent()[0])});var a=j(e,t,e,n,i,r);O.$$addScopeClass(e);var s=null;return function(t,n,i,r,o){ne(t,"scope"),s||(s=I(o));var l;if(l="html"!==s?Hn(J(s,Hn("<div>").append(e).html())):n?xi.clone.call(e):e,i)for(var c in i)l.data("$"+c+"Controller",i[c].instance);return O.$$addScopeInfo(l,t),n&&n(l,t),a&&a(t,l,l,r),l}}function I(e){var t=e&&e[0];return t&&"foreignobject"!==P(t)&&t.toString().match(/SVG/)?"svg":"html"}function j(e,t,i,r,o,a){function s(e,i,r,o){var a,s,l,c,u,d,f,p,m;if(h){var v=i.length;for(m=new Array(v),u=0;u<g.length;u+=3)f=g[u],m[f]=i[f]}else m=i;for(u=0,d=g.length;u<d;)l=m[g[u++]],a=g[u++],s=g[u++],a?(a.scope?(c=e.$new(),O.$$addScopeInfo(Hn(l),c)):c=e,p=a.transcludeOnThisElement?F(e,a.transclude,o,a.elementTranscludeOnThisElement):!a.templateOnThisElement&&o?o:!o&&t?F(e,t):null,a(s,c,l,r,p)):s&&s(e,l.childNodes,n,o)}for(var l,c,u,d,f,p,h,g=[],m=0;m<e.length;m++)l=new ae,c=R(e[m],[],l,0===m?r:n,o),u=c.length?U(c,e[m],l,t,i,null,[],[],a):null,u&&u.scope&&O.$$addScopeClass(l.$$element),f=u&&u.terminal||!(d=e[m].childNodes)||!d.length?null:j(d,u?(u.transcludeOnThisElement||!u.templateOnThisElement)&&u.transclude:t),(u||f)&&(g.push(m,u,f),p=!0,h=h||u),a=null;return p?s:null}function F(e,t,n,i){return function(i,r,o,a,s){return i||(i=e.$new(!1,s),i.$$transcluded=!0),t(i,r,o,n,a)}}function R(e,t,n,i,r){var o,a,s=e.nodeType,l=n.$attr;switch(s){case ii:W(t,ze(P(e)),"E",i,r);for(var d,f,p,h,g,m,v=e.attributes,$=0,y=v&&v.length;$<y;$++){var w=!1,x=!1;d=v[$],f=d.name,g=Jn(d.value),h=ze(f),(m=fe.test(h))&&(f=te(h.substr(6),"-"));var C=h.replace(/(Start|End)$/,"");z(C)&&h===C+"Start"&&(w=f,x=f.substr(0,f.length-5)+"end",f=f.substr(0,f.length-6)),p=ze(f.toLowerCase()),l[p]=f,!m&&n.hasOwnProperty(p)||(n[p]=g,Oe(e,p)&&(n[p]=!0)),ee(e,t,g,p,m),W(t,p,"A",i,r,w,x)}if(a=e.className,b(a)&&""!==a)for(;o=u.exec(a);)p=ze(o[2]),W(t,p,"C",i,r)&&(n[p]=Jn(o[3])),a=a.substr(o.index+o[0].length);break;case ri:Z(t,e.nodeValue);break;case oi:try{o=c.exec(e.nodeValue),o&&(p=ze(o[1]),W(t,p,"M",i,r)&&(n[p]=Jn(o[2])))}catch(e){}}return t.sort(G),t}function H(e,t,n){var i=[],r=0;if(t&&e.hasAttribute&&e.hasAttribute(t)){do{if(!e)throw Pi("uterdir","Unterminated attribute, found '{0}' but no matching '{1}' found.",t,n);e.nodeType==ii&&(e.hasAttribute(t)&&r++,e.hasAttribute(n)&&r--),i.push(e),e=e.nextSibling}while(r>0)}else i.push(e);return Hn(i)}function q(e,t,n){return function(i,r,o,a,s){return r=H(r[0],t,n),e(i,r,o,a,s)}}function U(e,a,s,l,c,u,d,f,p){function h(e,t,n,i){e&&(n&&(e=q(e,n,i)),e.require=S.require,e.directiveName=T,(N===S||S.$$isolateScope)&&(e=re(e,{isolateScope:!0})),d.push(e)),t&&(n&&(t=q(t,n,i)),t.require=S.require,t.directiveName=T,(N===S||S.$$isolateScope)&&(t=re(t,{isolateScope:!0})),f.push(t))}function g(e,t,n,i){var r,a,s="data",l=!1,c=n;if(b(t)){if(a=t.match(v),t=t.substring(a[0].length),a[3]&&(a[1]?a[3]=null:a[1]=a[3]),"^"===a[1]?s="inheritedData":"^^"===a[1]&&(s="inheritedData",c=n.parent()),"?"===a[2]&&(l=!0),r=null,i&&"data"===s&&(r=i[t])&&(r=r.instance),!(r=r||c[s]("$"+t+"Controller"))&&!l)throw Pi("ctreq","Controller '{0}', required by directive '{1}', can't be found!",t,e);return r}return Zn(t)&&(r=[],o(t,function(t){r.push(g(e,t,n,i))})),r}function w(e,t,r,l,c){function u(e,t,i){var r;return E(e)||(i=t,t=e,e=n),z&&(r=w),i||(i=z?C.parent():C),c(e,t,r,i,A)}var p,h,v,y,b,w,x,C,S;if(a===r?(S=s,C=s.$$element):(C=Hn(r),S=new ae(C,s)),N&&(b=t.$new(!0)),x=c&&u,P&&(k={},w={},o(P,function(e){var n,i={$scope:e===N||e.$$isolateScope?b:t,$element:C,$attrs:S,$transclude:x};y=e.controller,"@"==y&&(y=S[e.name]),n=$(y,i,!0,e.controllerAs),w[e.name]=n,z||C.data("$"+e.name+"Controller",n.instance),k[e.name]=n})),N){O.$$addScopeInfo(C,b,!0,!(j&&(j===N||j===N.$$originalDirective))),O.$$addScopeClass(C,!0);var T=k&&k[N.name],D=b;T&&T.identifier&&!0===N.bindToController&&(D=T.instance),o(b.$$isolateBindings=N.$$isolateBindings,function(e,n){var r,o,a,s,l=e.attrName,c=e.optional,u=e.mode;switch(u){case"@":S.$observe(l,function(e){D[n]=e}),S.$$observers[l].$$scope=t,S[l]&&(D[n]=i(S[l])(t));break;case"=":if(c&&!S[l])return;o=m(S[l]),s=o.literal?L:function(e,t){return e===t||e!==e&&t!==t},a=o.assign||function(){throw r=D[n]=o(t),Pi("nonassign","Expression '{0}' used with directive '{1}' is non-assignable!",S[l],N.name)},r=D[n]=o(t);var d=function(e){return s(e,D[n])||(s(e,r)?a(t,e=D[n]):D[n]=e),r=e};d.$stateful=!0;var f=t.$watch(m(S[l],d),null,o.literal);b.$on("$destroy",f);break;case"&":o=m(S[l]),D[n]=function(e){return o(t,e)}}})}for(k&&(o(k,function(e){e()}),k=null),p=0,h=d.length;p<h;p++)v=d[p],oe(v,v.isolateScope?b:t,C,S,v.require&&g(v.directiveName,v.require,C,w),x);var A=t;for(N&&(N.template||null===N.templateUrl)&&(A=b),e&&e(A,r.childNodes,n,c),p=f.length-1;p>=0;p--)v=f[p],oe(v,v.isolateScope?b:t,C,S,v.require&&g(v.directiveName,v.require,C,w),x)}p=p||{};for(var x,k,S,T,D,A,M,I=-Number.MAX_VALUE,P=p.controllerDirectives,N=p.newIsolateScopeDirective,j=p.templateDirective,F=p.nonTlbTranscludeDirective,U=!1,W=!1,z=p.hasElementTranscludeDirective,G=s.$$element=Hn(a),Z=u,Q=l,ee=0,te=e.length;ee<te;ee++){S=e[ee];var ne=S.$$start,se=S.$$end;if(ne&&(G=H(a,ne,se)),D=n,I>S.priority)break;if((M=S.scope)&&(S.templateUrl||(y(M)?(X("new/isolated scope",N||x,S,G),N=S):X("new/isolated scope",N,S,G)),x=x||S),T=S.name,!S.templateUrl&&S.controller&&(M=S.controller,P=P||{},X("'"+T+"' controller",P[T],S,G),P[T]=S),(M=S.transclude)&&(U=!0,S.$$tlb||(X("transclusion",F,S,G),F=S),"element"==M?(z=!0,I=S.priority,D=G,G=s.$$element=Hn(t.createComment(" "+T+": "+s[T]+" ")),a=G[0],ie(c,V(D),a),Q=O(D,l,I,Z&&Z.name,{nonTlbTranscludeDirective:F})):(D=Hn(me(a)).contents(),G.empty(),Q=O(D,l))),S.template)if(W=!0,X("template",j,S,G),j=S,M=C(S.template)?S.template(G,s):S.template,M=ue(M),S.replace){if(Z=S,
+D=de(M)?[]:Ke(J(S.templateNamespace,Jn(M))),a=D[0],1!=D.length||a.nodeType!==ii)throw Pi("tplrt","Template for directive '{0}' must have exactly one root element. {1}",T,"");ie(c,G,a);var le={$attr:{}},ce=R(a,[],le),fe=e.splice(ee+1,e.length-(ee+1));N&&_(ce),e=e.concat(ce).concat(fe),Y(s,le),te=e.length}else G.html(M);if(S.templateUrl)W=!0,X("template",j,S,G),j=S,S.replace&&(Z=S),w=K(e.splice(ee,e.length-ee),G,s,c,U&&Q,d,f,{controllerDirectives:P,newIsolateScopeDirective:N,templateDirective:j,nonTlbTranscludeDirective:F}),te=e.length;else if(S.compile)try{A=S.compile(G,s,Q),C(A)?h(null,A,ne,se):A&&h(A.pre,A.post,ne,se)}catch(e){r(e,B(G))}S.terminal&&(w.terminal=!0,I=Math.max(I,S.priority))}return w.scope=x&&!0===x.scope,w.transcludeOnThisElement=U,w.elementTranscludeOnThisElement=z,w.templateOnThisElement=W,w.transclude=Q,p.hasElementTranscludeDirective=z,w}function _(e){for(var t=0,n=e.length;t<n;t++)e[t]=p(e[t],{$$isolateScope:!0})}function W(t,i,o,l,c,u,d){if(i===c)return null;var f=null;if(a.hasOwnProperty(i))for(var h,g=e.get(i+s),m=0,v=g.length;m<v;m++)try{h=g[m],(l===n||l>h.priority)&&-1!=h.restrict.indexOf(o)&&(u&&(h=p(h,{$$start:u,$$end:d})),t.push(h),f=h)}catch(e){r(e)}return f}function z(t){if(a.hasOwnProperty(t))for(var n,i=e.get(t+s),r=0,o=i.length;r<o;r++)if(n=i[r],n.multiElement)return!0;return!1}function Y(e,t){var n=t.$attr,i=e.$attr,r=e.$$element;o(e,function(i,r){"$"!=r.charAt(0)&&(t[r]&&t[r]!==i&&(i+=("style"===r?";":" ")+t[r]),e.$set(r,i,!0,n[r]))}),o(t,function(t,o){"class"==o?(M(r,t),e.class=(e.class?e.class+" ":"")+t):"style"==o?(r.attr("style",r.attr("style")+";"+t),e.style=(e.style?e.style+";":"")+t):"$"==o.charAt(0)||e.hasOwnProperty(o)||(e[o]=t,i[o]=n[o])})}function K(e,t,n,i,r,a,s,c){var u,f,p=[],h=t[0],g=e.shift(),m=d({},g,{templateUrl:null,transclude:null,replace:null,$$originalDirective:g}),v=C(g.templateUrl)?g.templateUrl(t,n):g.templateUrl,$=g.templateNamespace;return t.empty(),l(T.getTrustedResourceUrl(v)).then(function(l){var d,b,w,x;if(l=ue(l),g.replace){if(w=de(l)?[]:Ke(J($,Jn(l))),d=w[0],1!=w.length||d.nodeType!==ii)throw Pi("tplrt","Template for directive '{0}' must have exactly one root element. {1}",g.name,v);b={$attr:{}},ie(i,t,d);var C=R(d,[],b);y(g.scope)&&_(C),e=C.concat(e),Y(n,b)}else d=h,t.html(l);for(e.unshift(m),u=U(e,d,n,r,t,g,a,s,c),o(i,function(e,n){e==d&&(i[n]=t[0])}),f=j(t[0].childNodes,r);p.length;){var k=p.shift(),S=p.shift(),E=p.shift(),T=p.shift(),D=t[0];if(!k.$$destroyed){if(S!==h){var A=S.className;c.hasElementTranscludeDirective&&g.replace||(D=me(d)),ie(E,Hn(S),D),M(Hn(D),A)}x=u.transcludeOnThisElement?F(k,u.transclude,T):T,u(f,k,D,i,x)}}p=null}),function(e,t,n,i,r){var o=r;t.$$destroyed||(p?(p.push(t),p.push(n),p.push(i),p.push(o)):(u.transcludeOnThisElement&&(o=F(t,u.transclude,r)),u(f,t,n,i,o)))}}function G(e,t){var n=t.priority-e.priority;return 0!==n?n:e.name!==t.name?e.name<t.name?-1:1:e.index-t.index}function X(e,t,n,i){if(t)throw Pi("multidir","Multiple directives [{0}, {1}] asking for {2} on: {3}",t.name,n.name,e,B(i))}function Z(e,t){var n=i(t,!0);n&&e.push({priority:0,compile:function(e){var t=e.parent(),i=!!t.length;return i&&O.$$addBindingClass(t),function(e,t){var r=t.parent();i||O.$$addBindingClass(r),O.$$addBindingInfo(r,n.expressions),e.$watch(n,function(e){t[0].nodeValue=e})}}})}function J(e,n){switch(e=Nn(e||"html")){case"svg":case"math":var i=t.createElement("div");return i.innerHTML="<"+e+">"+n+"</"+e+">",i.childNodes[0].childNodes;default:return n}}function Q(e,t){if("srcdoc"==t)return T.HTML;var n=P(e);return"xlinkHref"==t||"form"==n&&"action"==t||"img"!=n&&("src"==t||"ngSrc"==t)?T.RESOURCE_URL:void 0}function ee(e,t,n,r,o){var a=i(n,!0);if(a){if("multiple"===r&&"select"===P(e))throw Pi("selmulti","Binding to the 'multiple' attribute is not supported. Element: {0}",B(e));t.push({priority:100,compile:function(){return{pre:function(t,n,s){var l=s.$$observers||(s.$$observers={});if(w.test(r))throw Pi("nodomevents","Interpolations for HTML DOM event attributes are disallowed. Please use the ng- versions (such as ng-click instead of onclick) instead.");s[r]&&(a=i(s[r],!0,Q(e,r),f[r]||o))&&(s[r]=a(t),(l[r]||(l[r]=[])).$$inter=!0,(s.$$observers&&s.$$observers[r].$$scope||t).$watch(a,function(e,t){"class"===r&&e!=t?s.$updateClass(e,t):s.$set(r,e)}))}}}})}}function ie(e,n,i){var r,o,a=n[0],s=n.length,l=a.parentNode;if(e)for(r=0,o=e.length;r<o;r++)if(e[r]==a){e[r++]=i;for(var c=r,u=c+s-1,d=e.length;c<d;c++,u++)u<d?e[c]=e[u]:delete e[c];e.length-=s-1,e.context===a&&(e.context=i);break}l&&l.replaceChild(i,a);var f=t.createDocumentFragment();f.appendChild(a),Hn(i).data(Hn(a).data()),qn?(Xn=!0,qn.cleanData([a])):delete Hn.cache[a[Hn.expando]];for(var p=1,h=n.length;p<h;p++){var g=n[p];Hn(g).remove(),f.appendChild(g),delete n[p]}n[0]=i,n.length=1}function re(e,t){return d(function(){return e.apply(null,arguments)},e,t)}function oe(e,t,n,i,o,a){try{e(t,n,i,o,a)}catch(e){r(e,B(n))}}var ae=function(e,t){if(t){var n,i,r,o=Object.keys(t);for(n=0,i=o.length;n<i;n++)r=o[n],this[r]=t[r]}else this.$attr={};this.$$element=e};ae.prototype={$normalize:ze,$addClass:function(e){e&&e.length>0&&D.addClass(this.$$element,e)},$removeClass:function(e){e&&e.length>0&&D.removeClass(this.$$element,e)},$updateClass:function(e,t){var n=Ye(e,t);n&&n.length&&D.addClass(this.$$element,n);var i=Ye(t,e);i&&i.length&&D.removeClass(this.$$element,i)},$set:function(e,t,i,a){var s,l=this.$$element[0],c=Oe(l,e),u=Ie(l,e),d=e;if(c?(this.$$element.prop(e,t),a=c):u&&(this[u]=t,d=u),this[e]=t,a?this.$attr[e]=a:(a=this.$attr[e])||(this.$attr[e]=a=te(e,"-")),"a"===(s=P(this.$$element))&&"href"===e||"img"===s&&"src"===e)this[e]=t=A(t,"src"===e);else if("img"===s&&"srcset"===e){for(var f="",p=Jn(t),h=/(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/,g=/\s/.test(p)?h:/(,)/,m=p.split(g),v=Math.floor(m.length/2),$=0;$<v;$++){var y=2*$;f+=A(Jn(m[y]),!0),f+=" "+Jn(m[y+1])}var b=Jn(m[2*$]).split(/\s/);f+=A(Jn(b[0]),!0),2===b.length&&(f+=" "+Jn(b[1])),this[e]=t=f}!1!==i&&(null===t||t===n?this.$$element.removeAttr(a):this.$$element.attr(a,t));var w=this.$$observers;w&&o(w[d],function(e){try{e(t)}catch(e){r(e)}})},$observe:function(e,t){var n=this,i=n.$$observers||(n.$$observers=se()),r=i[e]||(i[e]=[]);return r.push(t),k.$evalAsync(function(){r.$$inter||t(n[e])}),function(){N(r,t)}}};var le=i.startSymbol(),ce=i.endSymbol(),ue="{{"==le||"}}"==ce?g:function(e){return e.replace(/\{\{/g,le).replace(/}}/g,ce)},fe=/^ngAttr[A-Z]/;return O.$$addBindingInfo=x?function(e,t){var n=e.data("$binding")||[];Zn(t)?n=n.concat(t):n.push(t),e.data("$binding",n)}:h,O.$$addBindingClass=x?function(e){M(e,"ng-binding")}:h,O.$$addScopeInfo=x?function(e,t,n,i){var r=n?i?"$isolateScopeNoTemplate":"$isolateScope":"$scope";e.data(r,t)}:h,O.$$addScopeClass=x?function(e,t){M(e,t?"ng-isolate-scope":"ng-scope")}:h,O}]}function ze(e){return ue(e.replace(Ni,""))}function Ye(e,t){var n="",i=e.split(/\s+/),r=t.split(/\s+/);e:for(var o=0;o<i.length;o++){for(var a=i[o],s=0;s<r.length;s++)if(a==r[s])continue e;n+=(n.length>0?" ":"")+a}return n}function Ke(e){e=Hn(e);var t=e.length;if(t<=1)return e;for(;t--;){e[t].nodeType===oi&&Bn.call(e,t,1)}return e}function Ge(){var e={},t=!1,r=/^(\S+)(\s+as\s+(\w+))?$/;this.register=function(t,n){re(t,"controller"),y(t)?d(e,t):e[t]=n},this.allowGlobals=function(){t=!0},this.$get=["$injector","$window",function(o,a){function s(e,t,n,r){if(!e||!y(e.$scope))throw i("$controller")("noscp","Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",r,t);e.$scope[t]=n}return function(i,l,c,u){var f,p,h,g;if(c=!0===c,u&&b(u)&&(g=u),b(i)&&(p=i.match(r),h=p[1],g=g||p[3],i=e.hasOwnProperty(h)?e[h]:oe(l.$scope,h,!0)||(t?oe(a,h,!0):n),ie(i,h,!0)),c){var m=function(){};return m.prototype=(Zn(i)?i[i.length-1]:i).prototype,f=new m,g&&s(l,g,f,h||i.name),d(function(){return o.invoke(i,f,l,h),f},{instance:f,identifier:g})}return f=o.instantiate(i,l,h),g&&s(l,g,f,h||i.name),f}}]}function Xe(){this.$get=["$window",function(e){return Hn(e.document)}]}function Ze(){this.$get=["$log",function(e){return function(t,n){e.error.apply(e,arguments)}}]}function Je(e){var t,n,i,r={};return e?(o(e.split("\n"),function(e){i=e.indexOf(":"),t=Nn(Jn(e.substr(0,i))),n=Jn(e.substr(i+1)),t&&(r[t]=r[t]?r[t]+", "+n:n)}),r):r}function Qe(e){var t=y(e)?e:n;return function(n){return t||(t=Je(e)),n?t[Nn(n)]||null:t}}function et(e,t,n){return C(n)?n(e,t):(o(n,function(n){e=n(e,t)}),e)}function tt(e){return 200<=e&&e<300}function nt(){var e=/^\s*(\[|\{[^\{])/,t=/[\}\]]\s*$/,i=/^\)\]\}',?\n/,r={"Content-Type":"application/json;charset=utf-8"},a=this.defaults={transformResponse:[function(n,r){if(b(n)){n=n.replace(i,"");var o=r("Content-Type");(o&&0===o.indexOf("application/json")||e.test(n)&&t.test(n))&&(n=_(n))}return n}],transformRequest:[function(e){return!y(e)||T(e)||D(e)?e:U(e)}],headers:{common:{Accept:"application/json, text/plain, */*"},post:F(r),put:F(r),patch:F(r)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN"},l=!1;this.useApplyAsync=function(e){return $(e)?(l=!!e,this):l};var c=this.interceptors=[];this.$get=["$httpBackend","$browser","$cacheFactory","$rootScope","$q","$injector",function(e,t,i,r,u,f){function p(e){function t(e){var t=d({},e);return e.data?t.data=et(e.data,e.headers,i.transformResponse):t.data=e.data,tt(e.status)?t:u.reject(t)}var i={method:"get",transformRequest:a.transformRequest,transformResponse:a.transformResponse},r=function(e){var t,n,i,r=a.headers,s=d({},e.headers);r=d({},r.common,r[Nn(e.method)]);e:for(t in r){n=Nn(t);for(i in s)if(Nn(i)===n)continue e;s[t]=r[t]}return function(e){var t;o(e,function(n,i){C(n)&&(t=n(),null!=t?e[i]=t:delete e[i])})}(s),s}(e);d(i,e),i.headers=r,i.method=Fn(i.method);var s=function(e){r=e.headers;var n=et(e.data,Qe(r),e.transformRequest);return v(n)&&o(r,function(e,t){"content-type"===Nn(t)&&delete r[t]}),v(e.withCredentials)&&!v(a.withCredentials)&&(e.withCredentials=a.withCredentials),h(e,n,r).then(t,t)},l=[s,n],c=u.when(i);for(o(w,function(e){(e.request||e.requestError)&&l.unshift(e.request,e.requestError),(e.response||e.responseError)&&l.push(e.response,e.responseError)});l.length;){var f=l.shift(),p=l.shift();c=c.then(f,p)}return c.success=function(e){return c.then(function(t){e(t.data,t.status,t.headers,i)}),c},c.error=function(e){return c.then(null,function(t){e(t.data,t.status,t.headers,i)}),c},c}function h(i,o,s){function c(e,t,n,i){function o(){d(t,e,n,i)}h&&(tt(e)?h.put(C,[e,t,Je(n),i]):h.remove(C)),l?r.$applyAsync(o):(o(),r.$$phase||r.$apply())}function d(e,t,n,r){t=Math.max(t,0),(tt(t)?w.resolve:w.reject)({data:e,status:t,headers:Qe(n),config:i,statusText:r})}function f(){var e=p.pendingRequests.indexOf(i);-1!==e&&p.pendingRequests.splice(e,1)}var h,b,w=u.defer(),x=w.promise,C=g(i.url,i.params);if(p.pendingRequests.push(i),x.then(f,f),!i.cache&&!a.cache||!1===i.cache||"GET"!==i.method&&"JSONP"!==i.method||(h=y(i.cache)?i.cache:y(a.cache)?a.cache:m),h)if(b=h.get(C),$(b)){if(M(b))return b.then(f,f),b;Zn(b)?d(b[1],b[0],F(b[2]),b[3]):d(b,200,{},"OK")}else h.put(C,x);if(v(b)){var k=Yt(i.url)?t.cookies()[i.xsrfCookieName||a.xsrfCookieName]:n;k&&(s[i.xsrfHeaderName||a.xsrfHeaderName]=k),e(i.method,C,o,c,s,i.timeout,i.withCredentials,i.responseType)}return x}function g(e,t){if(!t)return e;var n=[];return s(t,function(e,t){null===e||v(e)||(Zn(e)||(e=[e]),o(e,function(e){y(e)&&(e=x(e)?e.toISOString():U(e)),n.push(G(t)+"="+G(e))}))}),n.length>0&&(e+=(-1==e.indexOf("?")?"?":"&")+n.join("&")),e}var m=i("$http"),w=[];return o(c,function(e){w.unshift(b(e)?f.get(e):f.invoke(e))}),p.pendingRequests=[],function(e){o(arguments,function(e){p[e]=function(t,n){return p(d(n||{},{method:e,url:t}))}})}("get","delete","head","jsonp"),function(e){o(arguments,function(e){p[e]=function(t,n,i){return p(d(i||{},{method:e,url:t,data:n}))}})}("post","put","patch"),p.defaults=a,p}]}function it(){return new e.XMLHttpRequest}function rt(){this.$get=["$browser","$window","$document",function(e,t,n){return ot(e,it,e.defer,t.angular.callbacks,n[0])}]}function ot(e,t,n,i,r){function a(e,t,n){var o=r.createElement("script"),a=null;return o.type="text/javascript",o.src=e,o.async=!0,a=function(e){fi(o,"load",a),fi(o,"error",a),r.body.removeChild(o),o=null;var s=-1,l="unknown";e&&("load"!==e.type||i[t].called||(e={type:"error"}),l=e.type,s="error"===e.type?404:200),n&&n(s,l)},di(o,"load",a),di(o,"error",a),r.body.appendChild(o),a}return function(r,s,l,c,u,d,f,p){function g(){y&&y(),b&&b.abort()}function m(t,i,r,o,a){x&&n.cancel(x),y=b=null,t(i,r,o,a),e.$$completeOutstandingRequest(h)}if(e.$$incOutstandingRequestCount(),s=s||e.url(),"jsonp"==Nn(r)){var v="_"+(i.counter++).toString(36);i[v]=function(e){i[v].data=e,i[v].called=!0};var y=a(s.replace("JSON_CALLBACK","angular.callbacks."+v),v,function(e,t){m(c,e,i[v].data,"",t),i[v]=h})}else{var b=t();b.open(r,s,!0),o(u,function(e,t){$(e)&&b.setRequestHeader(t,e)}),b.onload=function(){var e=b.statusText||"",t="response"in b?b.response:b.responseText,n=1223===b.status?204:b.status;0===n&&(n=t?200:"file"==zt(s).protocol?404:0),m(c,n,t,b.getAllResponseHeaders(),e)};var w=function(){m(c,-1,null,null,"")};if(b.onerror=w,b.onabort=w,f&&(b.withCredentials=!0),p)try{b.responseType=p}catch(e){if("json"!==p)throw e}b.send(l||null)}if(d>0)var x=n(g,d);else M(d)&&d.then(g)}}function at(){var e="{{",t="}}";this.startSymbol=function(t){return t?(e=t,this):e},this.endSymbol=function(e){return e?(t=e,this):t},this.$get=["$parse","$exceptionHandler","$sce",function(n,i,r){function o(e){return"\\\\\\"+e}function a(o,a,f,p){function h(n){return n.replace(c,e).replace(u,t)}function g(e){try{return A(D(e))}catch(e){var t=ji("interr","Can't interpolate: {0}\n{1}",o,e.toString());i(t)}}p=!!p;for(var m,$,y,b=0,w=[],x=[],k=o.length,S=[],E=[];b<k;){if(-1==(m=o.indexOf(e,b))||-1==($=o.indexOf(t,m+s))){b!==k&&S.push(h(o.substring(b)));break}b!==m&&S.push(h(o.substring(b,m))),y=o.substring(m+s,$),w.push(y),x.push(n(y,g)),b=$+l,E.push(S.length),S.push("")}if(f&&S.length>1)throw ji("noconcat","Error while interpolating: {0}\nStrict Contextual Escaping disallows interpolations that concatenate multiple expressions when a trusted value is required. See http://docs.angularjs.org/api/ng.$sce",o);if(!a||w.length){var T=function(e){for(var t=0,n=w.length;t<n;t++){if(p&&v(e[t]))return;S[E[t]]=e[t]}return S.join("")},D=function(e){return f?r.getTrusted(f,e):r.valueOf(e)},A=function(e){if(null==e)return"";switch(typeof e){case"string":break;case"number":e=""+e;break;default:e=U(e)}return e};return d(function(e){var t=0,n=w.length,r=new Array(n);try{for(;t<n;t++)r[t]=x[t](e);return T(r)}catch(e){var a=ji("interr","Can't interpolate: {0}\n{1}",o,e.toString());i(a)}},{exp:o,expressions:w,$$watchDelegate:function(e,t,n){var i;return e.$watchGroup(x,function(n,r){var o=T(n);C(t)&&t.call(this,o,n!==r?i:o,e),i=o},n)}})}}var s=e.length,l=t.length,c=new RegExp(e.replace(/./g,o),"g"),u=new RegExp(t.replace(/./g,o),"g");return a.startSymbol=function(){return e},a.endSymbol=function(){return t},a}]}function st(){this.$get=["$rootScope","$window","$q","$$q",function(e,t,n,i){function r(r,a,s,l){var c=t.setInterval,u=t.clearInterval,d=0,f=$(l)&&!l,p=(f?i:n).defer(),h=p.promise;return s=$(s)?s:0,h.then(null,null,r),h.$$intervalId=c(function(){p.notify(d++),s>0&&d>=s&&(p.resolve(d),u(h.$$intervalId),delete o[h.$$intervalId]),f||e.$apply()},a),o[h.$$intervalId]=p,h}var o={};return r.cancel=function(e){return!!(e&&e.$$intervalId in o)&&(o[e.$$intervalId].reject("canceled"),t.clearInterval(e.$$intervalId),delete o[e.$$intervalId],!0)},r}]}function lt(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"¤",posSuf:"",negPre:"(¤",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January,February,March,April,May,June,July,August,September,October,November,December".split(","),SHORTMONTH:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(","),DAY:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(","),SHORTDAY:"Sun,Mon,Tue,Wed,Thu,Fri,Sat".split(","),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a",short:"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(e){return 1===e?"one":"other"}}}}function ct(e){for(var t=e.split("/"),n=t.length;n--;)t[n]=K(t[n]);return t.join("/")}function ut(e,t,n){var i=zt(e,n);t.$$protocol=i.protocol,t.$$host=i.hostname,t.$$port=f(i.port)||Li[i.protocol]||null}function dt(e,t,n){var i="/"!==e.charAt(0);i&&(e="/"+e);var r=zt(e,n);t.$$path=decodeURIComponent(i&&"/"===r.pathname.charAt(0)?r.pathname.substring(1):r.pathname),t.$$search=z(r.search),t.$$hash=decodeURIComponent(r.hash),t.$$path&&"/"!=t.$$path.charAt(0)&&(t.$$path="/"+t.$$path)}function ft(e,t){if(0===t.indexOf(e))return t.substr(e.length)}function pt(e){var t=e.indexOf("#");return-1==t?e:e.substr(0,t)}function ht(e){return e.substr(0,pt(e).lastIndexOf("/")+1)}function gt(e){return e.substring(0,e.indexOf("/",e.indexOf("//")+2))}function mt(e,t){this.$$html5=!0,t=t||"";var i=ht(e);ut(e,this,e),this.$$parse=function(t){var n=ft(i,t);if(!b(n))throw Ri("ipthprfx",'Invalid url "{0}", missing path prefix "{1}".',t,i);dt(n,this,e),this.$$path||(this.$$path="/"),this.$$compose()},this.$$compose=function(){var e=Y(this.$$search),t=this.$$hash?"#"+K(this.$$hash):"";this.$$url=ct(this.$$path)+(e?"?"+e:"")+t,this.$$absUrl=i+this.$$url.substr(1)},this.$$parseLinkUrl=function(r,o){if(o&&"#"===o[0])return this.hash(o.slice(1)),!0;var a,s,l;return(a=ft(e,r))!==n?(s=a,l=(a=ft(t,a))!==n?i+(ft("/",a)||a):e+s):(a=ft(i,r))!==n?l=i+a:i==r+"/"&&(l=i),l&&this.$$parse(l),!!l}}function vt(e,t){var n=ht(e);ut(e,this,e),this.$$parse=function(i){var r=ft(e,i)||ft(n,i),o="#"==r.charAt(0)?ft(t,r):this.$$html5?r:"";if(!b(o))throw Ri("ihshprfx",'Invalid url "{0}", missing hash prefix "{1}".',i,t);dt(o,this,e),this.$$path=function(e,t,n){var i,r=/^\/[A-Z]:(\/.*)/;return 0===t.indexOf(n)&&(t=t.replace(n,"")),r.exec(t)?e:(i=r.exec(e),i?i[1]:e)}(this.$$path,o,e),this.$$compose()},this.$$compose=function(){var n=Y(this.$$search),i=this.$$hash?"#"+K(this.$$hash):"";this.$$url=ct(this.$$path)+(n?"?"+n:"")+i,this.$$absUrl=e+(this.$$url?t+this.$$url:"")},this.$$parseLinkUrl=function(t,n){return pt(e)==pt(t)&&(this.$$parse(t),!0)}}function $t(e,t){this.$$html5=!0,vt.apply(this,arguments);var n=ht(e);this.$$parseLinkUrl=function(i,r){if(r&&"#"===r[0])return this.hash(r.slice(1)),!0;var o,a;return e==pt(i)?o=i:(a=ft(n,i))?o=e+t+a:n===i+"/"&&(o=n),o&&this.$$parse(o),!!o},this.$$compose=function(){var n=Y(this.$$search),i=this.$$hash?"#"+K(this.$$hash):"";this.$$url=ct(this.$$path)+(n?"?"+n:"")+i,this.$$absUrl=e+t+this.$$url}}function yt(e){return function(){return this[e]}}function bt(e,t){return function(n){return v(n)?this[e]:(this[e]=t(n),this.$$compose(),this)}}function wt(){var t="",n={enabled:!1,requireBase:!0,rewriteLinks:!0};this.hashPrefix=function(e){return $(e)?(t=e,this):t},this.html5Mode=function(e){return A(e)?(n.enabled=e,this):y(e)?(A(e.enabled)&&(n.enabled=e.enabled),A(e.requireBase)&&(n.requireBase=e.requireBase),A(e.rewriteLinks)&&(n.rewriteLinks=e.rewriteLinks),this):n},this.$get=["$rootScope","$browser","$sniffer","$rootElement",function(i,r,o,a){function s(e,t,n){var i=c.url(),o=c.$$state;try{r.url(e,t,n),c.$$state=r.state()}catch(e){throw c.url(i),c.$$state=o,e}}function l(e,t){i.$broadcast("$locationChangeSuccess",c.absUrl(),e,c.$$state,t)}var c,u,d,f=r.baseHref(),p=r.url();if(n.enabled){if(!f&&n.requireBase)throw Ri("nobase","$location in HTML5 mode requires a <base> tag to be present!");d=gt(p)+(f||"/"),u=o.history?mt:$t}else d=pt(p),u=vt;c=new u(d,"#"+t),c.$$parseLinkUrl(p,p),c.$$state=r.state();var h=/^\s*(javascript|mailto):/i;a.on("click",function(t){if(n.rewriteLinks&&!t.ctrlKey&&!t.metaKey&&2!=t.which){for(var o=Hn(t.target);"a"!==P(o[0]);)if(o[0]===a[0]||!(o=o.parent())[0])return;var s=o.prop("href"),l=o.attr("href")||o.attr("xlink:href");y(s)&&"[object SVGAnimatedString]"===s.toString()&&(s=zt(s.animVal).href),h.test(s)||!s||o.attr("target")||t.isDefaultPrevented()||c.$$parseLinkUrl(s,l)&&(t.preventDefault(),c.absUrl()!=r.url()&&(i.$apply(),e.angular["ff-684208-preventDefault"]=!0))}}),c.absUrl()!=p&&r.url(c.absUrl(),!0);var g=!0;return r.onUrlChange(function(e,t){i.$evalAsync(function(){var n=c.absUrl(),r=c.$$state;c.$$parse(e),c.$$state=t,i.$broadcast("$locationChangeStart",e,n,t,r).defaultPrevented?(c.$$parse(n),c.$$state=r,s(n,!1,r)):(g=!1,l(n,r))}),i.$$phase||i.$digest()}),i.$watch(function(){var e=r.url(),t=r.state(),n=c.$$replace,a=e!==c.absUrl()||c.$$html5&&o.history&&t!==c.$$state;(g||a)&&(g=!1,i.$evalAsync(function(){i.$broadcast("$locationChangeStart",c.absUrl(),e,c.$$state,t).defaultPrevented?(c.$$parse(e),c.$$state=t):(a&&s(c.absUrl(),n,t===c.$$state?null:c.$$state),l(e,t))})),c.$$replace=!1}),c}]}function xt(){var e=!0,t=this;this.debugEnabled=function(t){return $(t)?(e=t,this):e},this.$get=["$window",function(n){function i(e){return e instanceof Error&&(e.stack?e=e.message&&-1===e.stack.indexOf(e.message)?"Error: "+e.message+"\n"+e.stack:e.stack:e.sourceURL&&(e=e.message+"\n"+e.sourceURL+":"+e.line)),e}function r(e){var t=n.console||{},r=t[e]||t.log||h,a=!1;try{a=!!r.apply}catch(e){}return a?function(){var e=[];return o(arguments,function(t){e.push(i(t))}),r.apply(t,e)}:function(e,t){r(e,null==t?"":t)}}return{log:r("log"),info:r("info"),warn:r("warn"),error:r("error"),debug:function(){var n=r("debug");return function(){e&&n.apply(t,arguments)}}()}}]}function Ct(e,t){if("__defineGetter__"===e||"__defineSetter__"===e||"__lookupGetter__"===e||"__lookupSetter__"===e||"__proto__"===e)throw Hi("isecfld","Attempting to access a disallowed field in Angular expressions! Expression: {0}",t);return e}function kt(e,t){if(e){if(e.constructor===e)throw Hi("isecfn","Referencing Function in Angular expressions is disallowed! Expression: {0}",t);if(e.window===e)throw Hi("isecwindow","Referencing the Window in Angular expressions is disallowed! Expression: {0}",t);if(e.children&&(e.nodeName||e.prop&&e.attr&&e.find))throw Hi("isecdom","Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}",t);if(e===Object)throw Hi("isecobj","Referencing Object in Angular expressions is disallowed! Expression: {0}",t)}return e}function St(e,t){if(e){if(e.constructor===e)throw Hi("isecfn","Referencing Function in Angular expressions is disallowed! Expression: {0}",t);if(e===qi||e===Ui||e===_i)throw Hi("isecff","Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}",t)}}function Et(e){return e.constant}function Tt(e,t,n,i){kt(e,i);for(var r,o=t.split("."),a=0;o.length>1;a++){r=Ct(o.shift(),i);var s=kt(e[r],i);s||(s={},e[r]=s),e=s}return r=Ct(o.shift(),i),kt(e[r],i),e[r]=n,n}function Dt(e,t,i,r,o,a){return Ct(e,a),Ct(t,a),Ct(i,a),Ct(r,a),Ct(o,a),function(a,s){var l=s&&s.hasOwnProperty(e)?s:a;return null==l?l:(l=l[e],t?null==l?n:(l=l[t],i?null==l?n:(l=l[i],r?null==l?n:(l=l[r],o?null==l?n:l=l[o]:l):l):l):l)}}function At(e,t,i){var r=Gi[e];if(r)return r;var a=e.split("."),s=a.length;if(t.csp)r=s<6?Dt(a[0],a[1],a[2],a[3],a[4],i):function(e,t){var r,o=0;do{r=Dt(a[o++],a[o++],a[o++],a[o++],a[o++],i)(e,t),t=n,e=r}while(o<s);return r};else{var l="";o(a,function(e,t){Ct(e,i),l+="if(s == null) return undefined;\ns="+(t?"s":'((l&&l.hasOwnProperty("'+e+'"))?l:s)')+"."+e+";\n"}),l+="return s;";var c=new Function("s","l",l);c.toString=m(l),r=c}return r.sharedGetter=!0,r.assign=function(t,n){return Tt(t,e,n,e)},Gi[e]=r,r}function Mt(){var e=se(),t={csp:!1};this.$get=["$filter","$sniffer",function(n,i){function r(e){var t=e;return e.sharedGetter&&(t=function(t,n){return e(t,n)},t.literal=e.literal,t.constant=e.constant,t.assign=e.assign),t}function a(e,t){for(var n=0,i=e.length;n<i;n++){var r=e[n];r.constant||(r.inputs?a(r.inputs,t):-1===t.indexOf(r)&&t.push(r))}return t}function s(e,t){return null==e||null==t?e===t:("object"!=typeof e||"object"!=typeof(e=e.valueOf()))&&(e===t||e!==e&&t!==t)}function l(e,t,n,i){var r,o=i.$$inputs||(i.$$inputs=a(i.inputs,[]));if(1===o.length){var l=s;return o=o[0],e.$watch(function(e){var t=o(e);return s(t,l)||(r=i(e),l=t&&t.valueOf()),r},t,n)}for(var c=[],u=0,d=o.length;u<d;u++)c[u]=s;return e.$watch(function(e){for(var t=!1,n=0,a=o.length;n<a;n++){var l=o[n](e);(t||(t=!s(l,c[n])))&&(c[n]=l&&l.valueOf())}return t&&(r=i(e)),r},t,n)}function c(e,t,n,i){var r,o;return r=e.$watch(function(e){return i(e)},function(e,n,i){o=e,C(t)&&t.apply(this,arguments),$(e)&&i.$$postDigest(function(){$(o)&&r()})},n)}function u(e,t,n,i){function r(e){var t=!0;return o(e,function(e){$(e)||(t=!1)}),t}var a,s;return a=e.$watch(function(e){return i(e)},function(e,n,i){s=e,C(t)&&t.call(this,e,n,i),r(e)&&i.$$postDigest(function(){r(s)&&a()})},n)}function d(e,t,n,i){var r;return r=e.$watch(function(e){return i(e)},function(e,n,i){C(t)&&t.apply(this,arguments),r()},n)}function f(e,t){if(!t)return e;var n=function(n,i){var r=e(n,i),o=t(r,n,i);return $(r)?o:r};return e.$$watchDelegate&&e.$$watchDelegate!==l?n.$$watchDelegate=e.$$watchDelegate:t.$stateful||(n.$$watchDelegate=l,n.inputs=[e]),n}return t.csp=i.csp,function(i,o){var a,s,p;switch(typeof i){case"string":if(p=i=i.trim(),!(a=e[p])){":"===i.charAt(0)&&":"===i.charAt(1)&&(s=!0,i=i.substring(2));var g=new Yi(t);a=new Ki(g,n,t).parse(i),a.constant?a.$$watchDelegate=d:s?(a=r(a),a.$$watchDelegate=a.literal?u:c):a.inputs&&(a.$$watchDelegate=l),e[p]=a}return f(a,o);case"function":return f(i,o);default:return f(h,o)}}}]}function Ot(){this.$get=["$rootScope","$exceptionHandler",function(e,t){return Pt(function(t){e.$evalAsync(t)},t)}]}function It(){this.$get=["$browser","$exceptionHandler",function(e,t){return Pt(function(t){e.defer(t)},t)}]}function Pt(e,t){function r(e,t,n){function i(t){return function(n){r||(r=!0,t.call(e,n))}}var r=!1;return[i(t),i(n)]}function a(){this.$$state={status:0}}function s(e,t){return function(n){t.call(e,n)}}function l(e){var i,r,o;o=e.pending,e.processScheduled=!1,e.pending=n;for(var a=0,s=o.length;a<s;++a){r=o[a][0],i=o[a][e.status];try{C(i)?r.resolve(i(e.value)):1===e.status?r.resolve(e.value):r.reject(e.value)}catch(e){r.reject(e),t(e)}}}function c(t){!t.processScheduled&&t.pending&&(t.processScheduled=!0,e(function(){l(t)}))}function u(){this.promise=new a,this.resolve=s(this,this.resolve),this.reject=s(this,this.reject),this.notify=s(this,this.notify)}function d(e){var t=new u,n=0,i=Zn(e)?[]:{};return o(e,function(e,r){n++,v(e).then(function(e){i.hasOwnProperty(r)||(i[r]=e,--n||t.resolve(i))},function(e){i.hasOwnProperty(r)||t.reject(e)})}),0===n&&t.resolve(i),t.promise}var f=i("$q",TypeError),p=function(){return new u};a.prototype={then:function(e,t,n){var i=new u;return this.$$state.pending=this.$$state.pending||[],this.$$state.pending.push([i,e,t,n]),this.$$state.status>0&&c(this.$$state),i.promise},catch:function(e){return this.then(null,e)},finally:function(e,t){return this.then(function(t){return m(t,!0,e)},function(t){return m(t,!1,e)},t)}},u.prototype={resolve:function(e){this.promise.$$state.status||(e===this.promise?this.$$reject(f("qcycle","Expected promise to be resolved with value other than itself '{0}'",e)):this.$$resolve(e))},$$resolve:function(e){var n,i;i=r(this,this.$$resolve,this.$$reject);try{(y(e)||C(e))&&(n=e&&e.then),C(n)?(this.promise.$$state.status=-1,n.call(e,i[0],i[1],this.notify)):(this.promise.$$state.value=e,this.promise.$$state.status=1,c(this.promise.$$state))}catch(e){i[1](e),t(e)}},reject:function(e){this.promise.$$state.status||this.$$reject(e)},$$reject:function(e){this.promise.$$state.value=e,this.promise.$$state.status=2,c(this.promise.$$state)},notify:function(n){var i=this.promise.$$state.pending;this.promise.$$state.status<=0&&i&&i.length&&e(function(){for(var e,r,o=0,a=i.length;o<a;o++){r=i[o][0],e=i[o][3];try{r.notify(C(e)?e(n):n)}catch(e){t(e)}}})}};var h=function(e){var t=new u;return t.reject(e),t.promise},g=function(e,t){var n=new u;return t?n.resolve(e):n.reject(e),n.promise},m=function(e,t,n){var i=null;try{C(n)&&(i=n())}catch(e){return g(e,!1)}return M(i)?i.then(function(){return g(e,t)},function(e){return g(e,!1)}):g(e,t)},v=function(e,t,n,i){var r=new u;return r.resolve(e),r.promise.then(t,n,i)},$=function e(t){function n(e){r.resolve(e)}function i(e){r.reject(e)}if(!C(t))throw f("norslvr","Expected resolverFn, got '{0}'",t);if(!(this instanceof e))return new e(t);var r=new u;return t(n,i),r.promise};return $.defer=p,$.reject=h,$.when=v,$.all=d,$}function Nt(){this.$get=["$window","$timeout",function(e,t){var n=e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame,i=e.cancelAnimationFrame||e.webkitCancelAnimationFrame||e.mozCancelAnimationFrame||e.webkitCancelRequestAnimationFrame,r=!!n,o=r?function(e){var t=n(e);return function(){i(t)}}:function(e){var n=t(e,16.66,!1);return function(){t.cancel(n)}};return o.supported=r,o}]}function jt(){var e=10,t=i("$rootScope"),n=null,a=null;this.digestTtl=function(t){return arguments.length&&(e=t),e},this.$get=["$injector","$exceptionHandler","$parse","$browser",function(i,s,l,u){function d(){this.$id=c(),this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null,this.$root=this,this.$$destroyed=!1,this.$$listeners={},this.$$listenerCount={},this.$$isolateBindings=null}function f(e){if(b.$$phase)throw t("inprog","{0} already in progress",b.$$phase);b.$$phase=e}function p(){b.$$phase=null}function g(e,t,n){do{e.$$listenerCount[n]-=t,0===e.$$listenerCount[n]&&delete e.$$listenerCount[n]}while(e=e.$parent)}function m(){}function v(){for(;k.length;)try{k.shift()()}catch(e){s(e)}a=null}function $(){null===a&&(a=u.defer(function(){b.$apply(v)}))}d.prototype={constructor:d,$new:function(e,t){function n(){i.$$destroyed=!0}var i;return t=t||this,e?(i=new d,i.$root=this.$root):(this.$$ChildScope||(this.$$ChildScope=function(){this.$$watchers=this.$$nextSibling=this.$$childHead=this.$$childTail=null,this.$$listeners={},this.$$listenerCount={},this.$id=c(),this.$$ChildScope=null},this.$$ChildScope.prototype=this),i=new this.$$ChildScope),i.$parent=t,i.$$prevSibling=t.$$childTail,t.$$childHead?(t.$$childTail.$$nextSibling=i,t.$$childTail=i):t.$$childHead=t.$$childTail=i,(e||t!=this)&&i.$on("$destroy",n),i},$watch:function(e,t,i){var r=l(e);if(r.$$watchDelegate)return r.$$watchDelegate(this,t,i,r);var o=this,a=o.$$watchers,s={fn:t,last:m,get:r,exp:e,eq:!!i};return n=null,C(t)||(s.fn=h),a||(a=o.$$watchers=[]),a.unshift(s),function(){N(a,s),n=null}},$watchGroup:function(e,t){function n(){l=!1,c?(c=!1,t(r,r,s)):t(r,i,s)}var i=new Array(e.length),r=new Array(e.length),a=[],s=this,l=!1,c=!0;if(!e.length){var u=!0;return s.$evalAsync(function(){u&&t(r,r,s)}),function(){u=!1}}return 1===e.length?this.$watch(e[0],function(e,n,o){r[0]=e,i[0]=n,t(r,e===n?r:i,o)}):(o(e,function(e,t){var o=s.$watch(e,function(e,o){r[t]=e,i[t]=o,l||(l=!0,s.$evalAsync(n))});a.push(o)}),function(){for(;a.length;)a.shift()()})},$watchCollection:function(e,t){function n(e){o=e;var t,n,i,s;if(y(o))if(r(o)){a!==p&&(a=p,m=a.length=0,d++),t=o.length,m!==t&&(d++,a.length=m=t);for(var l=0;l<t;l++)s=a[l],i=o[l],s!==s&&i!==i||s===i||(d++,a[l]=i)}else{a!==h&&(a=h={},m=0,d++),t=0;for(n in o)o.hasOwnProperty(n)&&(t++,i=o[n],s=a[n],n in a?s!==s&&i!==i||s===i||(d++,a[n]=i):(m++,a[n]=i,d++));if(m>t){d++;for(n in a)o.hasOwnProperty(n)||(m--,delete a[n])}}else a!==o&&(a=o,d++);return d}function i(){if(g?(g=!1,t(o,o,c)):t(o,s,c),u)if(y(o))if(r(o)){s=new Array(o.length);for(var e=0;e<o.length;e++)s[e]=o[e]}else{s={};for(var n in o)jn.call(o,n)&&(s[n]=o[n])}else s=o}n.$stateful=!0;var o,a,s,c=this,u=t.length>1,d=0,f=l(e,n),p=[],h={},g=!0,m=0;return this.$watch(f,i)},$digest:function(){var i,r,o,l,c,d,h,g,$,y,k,S=e,E=this,T=[];f("$digest"),
+u.$$checkUrlChange(),this===b&&null!==a&&(u.defer.cancel(a),v()),n=null;do{for(d=!1,g=E;w.length;){try{k=w.shift(),k.scope.$eval(k.expression)}catch(e){s(e)}n=null}e:do{if(l=g.$$watchers)for(c=l.length;c--;)try{if(i=l[c])if((r=i.get(g))===(o=i.last)||(i.eq?L(r,o):"number"==typeof r&&"number"==typeof o&&isNaN(r)&&isNaN(o))){if(i===n){d=!1;break e}}else d=!0,n=i,i.last=i.eq?j(r,null):r,i.fn(r,o===m?r:o,g),S<5&&($=4-S,T[$]||(T[$]=[]),y=C(i.exp)?"fn: "+(i.exp.name||i.exp.toString()):i.exp,y+="; newVal: "+U(r)+"; oldVal: "+U(o),T[$].push(y))}catch(e){s(e)}if(!(h=g.$$childHead||g!==E&&g.$$nextSibling))for(;g!==E&&!(h=g.$$nextSibling);)g=g.$parent}while(g=h);if((d||w.length)&&!S--)throw p(),t("infdig","{0} $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: {1}",e,U(T))}while(d||w.length);for(p();x.length;)try{x.shift()()}catch(e){s(e)}},$destroy:function(){if(!this.$$destroyed){var e=this.$parent;if(this.$broadcast("$destroy"),this.$$destroyed=!0,this!==b){for(var t in this.$$listenerCount)g(this,this.$$listenerCount[t],t);e.$$childHead==this&&(e.$$childHead=this.$$nextSibling),e.$$childTail==this&&(e.$$childTail=this.$$prevSibling),this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling),this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=this.$$prevSibling),this.$destroy=this.$digest=this.$apply=this.$evalAsync=this.$applyAsync=h,this.$on=this.$watch=this.$watchGroup=function(){return h},this.$$listeners={},this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=this.$root=this.$$watchers=null}}},$eval:function(e,t){return l(e)(this,t)},$evalAsync:function(e){b.$$phase||w.length||u.defer(function(){w.length&&b.$digest()}),w.push({scope:this,expression:e})},$$postDigest:function(e){x.push(e)},$apply:function(e){try{return f("$apply"),this.$eval(e)}catch(e){s(e)}finally{p();try{b.$digest()}catch(e){throw s(e),e}}},$applyAsync:function(e){function t(){n.$eval(e)}var n=this;e&&k.push(t),$()},$on:function(e,t){var n=this.$$listeners[e];n||(this.$$listeners[e]=n=[]),n.push(t);var i=this;do{i.$$listenerCount[e]||(i.$$listenerCount[e]=0),i.$$listenerCount[e]++}while(i=i.$parent);var r=this;return function(){n[n.indexOf(t)]=null,g(r,1,e)}},$emit:function(e,t){var n,i,r,o=[],a=this,l=!1,c={name:e,targetScope:a,stopPropagation:function(){l=!0},preventDefault:function(){c.defaultPrevented=!0},defaultPrevented:!1},u=R([c],arguments,1);do{for(n=a.$$listeners[e]||o,c.currentScope=a,i=0,r=n.length;i<r;i++)if(n[i])try{n[i].apply(null,u)}catch(e){s(e)}else n.splice(i,1),i--,r--;if(l)return c.currentScope=null,c;a=a.$parent}while(a);return c.currentScope=null,c},$broadcast:function(e,t){var n=this,i=n,r=n,o={name:e,targetScope:n,preventDefault:function(){o.defaultPrevented=!0},defaultPrevented:!1};if(!n.$$listenerCount[e])return o;for(var a,l,c,u=R([o],arguments,1);i=r;){for(o.currentScope=i,a=i.$$listeners[e]||[],l=0,c=a.length;l<c;l++)if(a[l])try{a[l].apply(null,u)}catch(e){s(e)}else a.splice(l,1),l--,c--;if(!(r=i.$$listenerCount[e]&&i.$$childHead||i!==n&&i.$$nextSibling))for(;i!==n&&!(r=i.$$nextSibling);)i=i.$parent}return o.currentScope=null,o}};var b=new d,w=b.$$asyncQueue=[],x=b.$$postDigestQueue=[],k=b.$$applyAsyncQueue=[];return b}]}function Ft(){var e=/^\s*(https?|ftp|mailto|tel|file):/,t=/^\s*((https?|ftp|file|blob):|data:image\/)/;this.aHrefSanitizationWhitelist=function(t){return $(t)?(e=t,this):e},this.imgSrcSanitizationWhitelist=function(e){return $(e)?(t=e,this):t},this.$get=function(){return function(n,i){var r,o=i?t:e;return r=zt(n).href,""===r||r.match(o)?n:"unsafe:"+r}}}function Lt(e){return e.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g,"\\$1").replace(/\x08/g,"\\x08")}function Rt(e){if("self"===e)return e;if(b(e)){if(e.indexOf("***")>-1)throw Xi("iwcard","Illegal sequence *** in string matcher. String: {0}",e);return e=Lt(e).replace("\\*\\*",".*").replace("\\*","[^:/.?&;]*"),new RegExp("^"+e+"$")}if(k(e))return new RegExp("^"+e.source+"$");throw Xi("imatcher",'Matchers may only be "self", string patterns or RegExp objects')}function Vt(e){var t=[];return $(e)&&o(e,function(e){t.push(Rt(e))}),t}function Ht(){this.SCE_CONTEXTS=Zi;var e=["self"],t=[];this.resourceUrlWhitelist=function(t){return arguments.length&&(e=Vt(t)),e},this.resourceUrlBlacklist=function(e){return arguments.length&&(t=Vt(e)),t},this.$get=["$injector",function(i){function r(e,t){return"self"===e?Yt(t):!!e.exec(t.href)}function o(n){var i,o,a=zt(n.toString()),s=!1;for(i=0,o=e.length;i<o;i++)if(r(e[i],a)){s=!0;break}if(s)for(i=0,o=t.length;i<o;i++)if(r(t[i],a)){s=!1;break}return s}function a(e){var t=function(e){this.$$unwrapTrustedValue=function(){return e}};return e&&(t.prototype=new e),t.prototype.valueOf=function(){return this.$$unwrapTrustedValue()},t.prototype.toString=function(){return this.$$unwrapTrustedValue().toString()},t}function s(e,t){var i=f.hasOwnProperty(e)?f[e]:null;if(!i)throw Xi("icontext","Attempted to trust a value in invalid context. Context: {0}; Value: {1}",e,t);if(null===t||t===n||""===t)return t;if("string"!=typeof t)throw Xi("itype","Attempted to trust a non-string value in a content requiring a string: Context: {0}",e);return new i(t)}function l(e){return e instanceof d?e.$$unwrapTrustedValue():e}function c(e,t){if(null===t||t===n||""===t)return t;var i=f.hasOwnProperty(e)?f[e]:null;if(i&&t instanceof i)return t.$$unwrapTrustedValue();if(e===Zi.RESOURCE_URL){if(o(t))return t;throw Xi("insecurl","Blocked loading resource from url not allowed by $sceDelegate policy. URL: {0}",t.toString())}if(e===Zi.HTML)return u(t);throw Xi("unsafe","Attempting to use an unsafe value in a safe context.")}var u=function(e){throw Xi("unsafe","Attempting to use an unsafe value in a safe context.")};i.has("$sanitize")&&(u=i.get("$sanitize"));var d=a(),f={};return f[Zi.HTML]=a(d),f[Zi.CSS]=a(d),f[Zi.URL]=a(d),f[Zi.JS]=a(d),f[Zi.RESOURCE_URL]=a(f[Zi.URL]),{trustAs:s,getTrusted:c,valueOf:l}}]}function qt(){var e=!0;this.enabled=function(t){return arguments.length&&(e=!!t),e},this.$get=["$document","$parse","$sceDelegate",function(t,n,i){if(e&&t[0].documentMode<8)throw Xi("iequirks","Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks mode. You can fix this by adding the text <!doctype html> to the top of your HTML document. See http://docs.angularjs.org/api/ng.$sce for more information.");var r=F(Zi);r.isEnabled=function(){return e},r.trustAs=i.trustAs,r.getTrusted=i.getTrusted,r.valueOf=i.valueOf,e||(r.trustAs=r.getTrusted=function(e,t){return t},r.valueOf=g),r.parseAs=function(e,t){var i=n(t);return i.literal&&i.constant?i:n(t,function(t){return r.getTrusted(e,t)})};var a=r.parseAs,s=r.getTrusted,l=r.trustAs;return o(Zi,function(e,t){var n=Nn(t);r[ue("parse_as_"+n)]=function(t){return a(e,t)},r[ue("get_trusted_"+n)]=function(t){return s(e,t)},r[ue("trust_as_"+n)]=function(t){return l(e,t)}}),r}]}function Ut(){this.$get=["$window","$document",function(e,t){var n,i,r={},o=f((/android (\d+)/.exec(Nn((e.navigator||{}).userAgent))||[])[1]),a=/Boxee/i.test((e.navigator||{}).userAgent),s=t[0]||{},l=/^(Moz|webkit|O|ms)(?=[A-Z])/,c=s.body&&s.body.style,u=!1,d=!1;if(c){for(var p in c)if(i=l.exec(p)){n=i[0],n=n.substr(0,1).toUpperCase()+n.substr(1);break}n||(n="WebkitOpacity"in c&&"webkit"),u=!!("transition"in c||n+"Transition"in c),d=!!("animation"in c||n+"Animation"in c),!o||u&&d||(u=b(s.body.style.webkitTransition),d=b(s.body.style.webkitAnimation))}return{history:!(!e.history||!e.history.pushState||o<4||a),hasEvent:function(e){if("input"==e&&9==Vn)return!1;if(v(r[e])){var t=s.createElement("div");r[e]="on"+e in t}return r[e]},csp:Qn(),vendorPrefix:n,transitions:u,animations:d,android:o}}]}function _t(){this.$get=["$templateCache","$http","$q",function(e,t,n){function i(r,o){function a(){if(s.totalPendingRequests--,!o)throw Pi("tpload","Failed to load template: {0}",r);return n.reject()}var s=i;return s.totalPendingRequests++,t.get(r,{cache:e}).then(function(t){var n=t.data;return n&&0!==n.length?(s.totalPendingRequests--,e.put(r,n),n):a()},a)}return i.totalPendingRequests=0,i}]}function Bt(){this.$get=["$rootScope","$browser","$location",function(e,t,n){var i={};return i.findBindings=function(e,t,n){var i=e.getElementsByClassName("ng-binding"),r=[];return o(i,function(e){var i=Kn.element(e).data("$binding");i&&o(i,function(i){if(n){new RegExp("(^|\\s)"+t+"(\\s|\\||$)").test(i)&&r.push(e)}else-1!=i.indexOf(t)&&r.push(e)})}),r},i.findModels=function(e,t,n){for(var i=["ng-","data-ng-","ng\\:"],r=0;r<i.length;++r){var o=n?"=":"*=",a="["+i[r]+"model"+o+'"'+t+'"]',s=e.querySelectorAll(a);if(s.length)return s}},i.getLocation=function(){return n.url()},i.setLocation=function(t){t!==n.url()&&(n.url(t),e.$digest())},i.whenStable=function(e){t.notifyWhenNoOutstandingRequests(e)},i}]}function Wt(){this.$get=["$rootScope","$browser","$q","$$q","$exceptionHandler",function(e,t,n,i,r){function o(o,s,l){var c,u=$(l)&&!l,d=(u?i:n).defer(),f=d.promise;return c=t.defer(function(){try{d.resolve(o())}catch(e){d.reject(e),r(e)}finally{delete a[f.$$timeoutId]}u||e.$apply()},s),f.$$timeoutId=c,a[c]=d,f}var a={};return o.cancel=function(e){return!!(e&&e.$$timeoutId in a)&&(a[e.$$timeoutId].reject("canceled"),delete a[e.$$timeoutId],t.defer.cancel(e.$$timeoutId))},o}]}function zt(e,t){var n=e;return Vn&&(Ji.setAttribute("href",n),n=Ji.href),Ji.setAttribute("href",n),{href:Ji.href,protocol:Ji.protocol?Ji.protocol.replace(/:$/,""):"",host:Ji.host,search:Ji.search?Ji.search.replace(/^\?/,""):"",hash:Ji.hash?Ji.hash.replace(/^#/,""):"",hostname:Ji.hostname,port:Ji.port,pathname:"/"===Ji.pathname.charAt(0)?Ji.pathname:"/"+Ji.pathname}}function Yt(e){var t=b(e)?zt(e):e;return t.protocol===Qi.protocol&&t.host===Qi.host}function Kt(){this.$get=m(e)}function Gt(e){function t(i,r){if(y(i)){var a={};return o(i,function(e,n){a[n]=t(n,e)}),a}return e.factory(i+n,r)}var n="Filter";this.register=t,this.$get=["$injector",function(e){return function(t){return e.get(t+n)}}],t("currency",Zt),t("date",cn),t("filter",Xt),t("json",un),t("limitTo",dn),t("lowercase",rr),t("number",Jt),t("orderBy",fn),t("uppercase",or)}function Xt(){return function(e,t,n){if(!Zn(e))return e;var i=typeof n,r=[];r.check=function(e,t){for(var n=0;n<r.length;n++)if(!r[n](e,t))return!1;return!0},"function"!==i&&(n="boolean"===i&&n?function(e,t){return Kn.equals(e,t)}:function(e,t){if(e&&t&&"object"==typeof e&&"object"==typeof t){for(var i in e)if("$"!==i.charAt(0)&&jn.call(e,i)&&n(e[i],t[i]))return!0;return!1}return t=(""+t).toLowerCase(),(""+e).toLowerCase().indexOf(t)>-1});var o=function(e,t){if("string"==typeof t&&"!"===t.charAt(0))return!o(e,t.substr(1));switch(typeof e){case"boolean":case"number":case"string":return n(e,t);case"object":switch(typeof t){case"object":return n(e,t);default:for(var i in e)if("$"!==i.charAt(0)&&o(e[i],t))return!0}return!1;case"array":for(var r=0;r<e.length;r++)if(o(e[r],t))return!0;return!1;default:return!1}};switch(typeof t){case"boolean":case"number":case"string":t={$:t};case"object":for(var a in t)!function(e){void 0!==t[e]&&r.push(function(n){return o("$"==e?n:n&&n[e],t[e])})}(a);break;case"function":r.push(t);break;default:return e}for(var s=[],l=0;l<e.length;l++){var c=e[l];r.check(c,l)&&s.push(c)}return s}}function Zt(e){var t=e.NUMBER_FORMATS;return function(e,n,i){return v(n)&&(n=t.CURRENCY_SYM),v(i)&&(i=2),null==e?e:Qt(e,t.PATTERNS[1],t.GROUP_SEP,t.DECIMAL_SEP,i).replace(/\u00A4/g,n)}}function Jt(e){var t=e.NUMBER_FORMATS;return function(e,n){return null==e?e:Qt(e,t.PATTERNS[0],t.GROUP_SEP,t.DECIMAL_SEP,n)}}function Qt(e,t,n,i,r){if(!isFinite(e)||y(e))return"";var o=e<0;e=Math.abs(e);var a=e+"",s="",l=[],c=!1;if(-1!==a.indexOf("e")){var u=a.match(/([\d\.]+)e(-?)(\d+)/);u&&"-"==u[2]&&u[3]>r+1?(a="0",e=0):(s=a,c=!0)}if(c)r>0&&e>-1&&e<1&&(s=e.toFixed(r));else{var d=(a.split(er)[1]||"").length;v(r)&&(r=Math.min(Math.max(t.minFrac,d),t.maxFrac)),e=+(Math.round(+(e.toString()+"e"+r)).toString()+"e"+-r),0===e&&(o=!1);var f=(""+e).split(er),p=f[0];f=f[1]||"";var h,g=0,m=t.lgSize,$=t.gSize;if(p.length>=m+$)for(g=p.length-m,h=0;h<g;h++)(g-h)%$==0&&0!==h&&(s+=n),s+=p.charAt(h);for(h=g;h<p.length;h++)(p.length-h)%m==0&&0!==h&&(s+=n),s+=p.charAt(h);for(;f.length<r;)f+="0";r&&"0"!==r&&(s+=i+f.substr(0,r))}return l.push(o?t.negPre:t.posPre),l.push(s),l.push(o?t.negSuf:t.posSuf),l.join("")}function en(e,t,n){var i="";for(e<0&&(i="-",e=-e),e=""+e;e.length<t;)e="0"+e;return n&&(e=e.substr(e.length-t)),i+e}function tn(e,t,n,i){return n=n||0,function(r){var o=r["get"+e]();return(n>0||o>-n)&&(o+=n),0===o&&-12==n&&(o=12),en(o,t,i)}}function nn(e,t){return function(n,i){var r=n["get"+e]();return i[Fn(t?"SHORT"+e:e)][r]}}function rn(e){var t=-1*e.getTimezoneOffset(),n=t>=0?"+":"";return n+=en(Math[t>0?"floor":"ceil"](t/60),2)+en(Math.abs(t%60),2)}function on(e){var t=new Date(e,0,1).getDay();return new Date(e,0,(t<=4?5:12)-t)}function an(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate()+(4-e.getDay()))}function sn(e){return function(t){var n=on(t.getFullYear()),i=an(t),r=+i-+n;return en(1+Math.round(r/6048e5),e)}}function ln(e,t){return e.getHours()<12?t.AMPMS[0]:t.AMPMS[1]}function cn(e){function t(e){var t;if(t=e.match(n)){var i=new Date(0),r=0,o=0,a=t[8]?i.setUTCFullYear:i.setFullYear,s=t[8]?i.setUTCHours:i.setHours;t[9]&&(r=f(t[9]+t[10]),o=f(t[9]+t[11])),a.call(i,f(t[1]),f(t[2])-1,f(t[3]));var l=f(t[4]||0)-r,c=f(t[5]||0)-o,u=f(t[6]||0),d=Math.round(1e3*parseFloat("0."+(t[7]||0)));return s.call(i,l,c,u,d),i}return e}var n=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(n,i,r){var a,s,l="",c=[];if(i=i||"mediumDate",i=e.DATETIME_FORMATS[i]||i,b(n)&&(n=ir.test(n)?f(n):t(n)),w(n)&&(n=new Date(n)),!x(n))return n;for(;i;)s=nr.exec(i),s?(c=R(c,s,1),i=c.pop()):(c.push(i),i=null);return r&&"UTC"===r&&(n=new Date(n.getTime()),n.setMinutes(n.getMinutes()+n.getTimezoneOffset())),o(c,function(t){a=tr[t],l+=a?a(n,e.DATETIME_FORMATS):t.replace(/(^'|'$)/g,"").replace(/''/g,"'")}),l}}function un(){return function(e){return U(e,!0)}}function dn(){return function(e,t){if(w(e)&&(e=e.toString()),!Zn(e)&&!b(e))return e;if(t=Math.abs(Number(t))===1/0?Number(t):f(t),b(e))return t?t>=0?e.slice(0,t):e.slice(t,e.length):"";var n,i,r=[];for(t>e.length?t=e.length:t<-e.length&&(t=-e.length),t>0?(n=0,i=t):(n=e.length+t,i=e.length);n<i;n++)r.push(e[n]);return r}}function fn(e){return function(t,n,i){function o(e,t){for(var i=0;i<n.length;i++){var r=n[i](e,t);if(0!==r)return r}return 0}function a(e,t){return t?function(t,n){return e(n,t)}:e}function s(e,t){var n=typeof e,i=typeof t;return n==i?(x(e)&&x(t)&&(e=e.valueOf(),t=t.valueOf()),"string"==n&&(e=e.toLowerCase(),t=t.toLowerCase()),e===t?0:e<t?-1:1):n<i?-1:1}if(!r(t))return t;n=Zn(n)?n:[n],0===n.length&&(n=["+"]),n=n.map(function(t){var n=!1,i=t||g;if(b(t)){if("+"!=t.charAt(0)&&"-"!=t.charAt(0)||(n="-"==t.charAt(0),t=t.substring(1)),""===t)return a(function(e,t){return s(e,t)},n);if(i=e(t),i.constant){var r=i();return a(function(e,t){return s(e[r],t[r])},n)}}return a(function(e,t){return s(i(e),i(t))},n)});for(var l=[],c=0;c<t.length;c++)l.push(t[c]);return l.sort(a(o,i))}}function pn(e){return C(e)&&(e={link:e}),e.restrict=e.restrict||"AC",m(e)}function hn(e,t){e.$name=t}function gn(e,t,i,r,a){var s=this,l=[],c=s.$$parentForm=e.parent().controller("form")||lr;s.$error={},s.$$success={},s.$pending=n,s.$name=a(t.name||t.ngForm||"")(i),s.$dirty=!1,s.$pristine=!0,s.$valid=!0,s.$invalid=!1,s.$submitted=!1,c.$addControl(s),s.$rollbackViewValue=function(){o(l,function(e){e.$rollbackViewValue()})},s.$commitViewValue=function(){o(l,function(e){e.$commitViewValue()})},s.$addControl=function(e){re(e.$name,"input"),l.push(e),e.$name&&(s[e.$name]=e)},s.$$renameControl=function(e,t){var n=e.$name;s[n]===e&&delete s[n],s[t]=e,e.$name=t},s.$removeControl=function(e){e.$name&&s[e.$name]===e&&delete s[e.$name],o(s.$pending,function(t,n){s.$setValidity(n,null,e)}),o(s.$error,function(t,n){s.$setValidity(n,null,e)}),N(l,e)},An({ctrl:this,$element:e,set:function(e,t,n){var i=e[t];if(i){-1===i.indexOf(n)&&i.push(n)}else e[t]=[n]},unset:function(e,t,n){var i=e[t];i&&(N(i,n),0===i.length&&delete e[t])},parentForm:c,$animate:r}),s.$setDirty=function(){r.removeClass(e,Dr),r.addClass(e,Ar),s.$dirty=!0,s.$pristine=!1,c.$setDirty()},s.$setPristine=function(){r.setClass(e,Dr,Ar+" "+cr),s.$dirty=!1,s.$pristine=!0,s.$submitted=!1,o(l,function(e){e.$setPristine()})},s.$setUntouched=function(){o(l,function(e){e.$setUntouched()})},s.$setSubmitted=function(){r.addClass(e,cr),s.$submitted=!0,c.$setSubmitted()}}function mn(e){e.$formatters.push(function(t){return e.$isEmpty(t)?t:t.toString()})}function vn(e,t,n,i,r,o){$n(e,t,n,i,r,o),mn(i)}function $n(e,t,n,i,r,o){var a=(t.prop(Pn),t[0].placeholder),s={},l=Nn(t[0].type);if(!r.android){var c=!1;t.on("compositionstart",function(e){c=!0}),t.on("compositionend",function(){c=!1,u()})}var u=function(e){if(!c){var r=t.val(),o=e&&e.type;if(Vn&&"input"===(e||s).type&&t[0].placeholder!==a)return void(a=t[0].placeholder);"password"===l||n.ngTrim&&"false"===n.ngTrim||(r=Jn(r)),(i.$viewValue!==r||""===r&&i.$$hasNativeValidators)&&i.$setViewValue(r,o)}};if(r.hasEvent("input"))t.on("input",u);else{var d,f=function(e){d||(d=o.defer(function(){u(e),d=null}))};t.on("keydown",function(e){var t=e.keyCode;91===t||15<t&&t<19||37<=t&&t<=40||f(e)}),r.hasEvent("paste")&&t.on("paste cut",f)}t.on("change",u),i.$render=function(){t.val(i.$isEmpty(i.$modelValue)?"":i.$viewValue)}}function yn(e,t){if(x(e))return e;if(b(e)){yr.lastIndex=0;var n=yr.exec(e);if(n){var i=+n[1],r=+n[2],o=0,a=0,s=0,l=0,c=on(i),u=7*(r-1);return t&&(o=t.getHours(),a=t.getMinutes(),s=t.getSeconds(),l=t.getMilliseconds()),new Date(i,0,c.getDate()+u,o,a,s,l)}}return NaN}function bn(e,t){return function(n,i){var r,a;if(x(n))return n;if(b(n)){if('"'==n.charAt(0)&&'"'==n.charAt(n.length-1)&&(n=n.substring(1,n.length-1)),pr.test(n))return new Date(n);if(e.lastIndex=0,r=e.exec(n))return r.shift(),a=i?{yyyy:i.getFullYear(),MM:i.getMonth()+1,dd:i.getDate(),HH:i.getHours(),mm:i.getMinutes(),ss:i.getSeconds(),sss:i.getMilliseconds()/1e3}:{yyyy:1970,MM:1,dd:1,HH:0,mm:0,ss:0,sss:0},o(r,function(e,n){n<t.length&&(a[t[n]]=+e)}),new Date(a.yyyy,a.MM-1,a.dd,a.HH,a.mm,a.ss||0,1e3*a.sss||0)}return NaN}}function wn(e,t,i,r){return function(o,a,s,l,c,u,d){function f(e){return $(e)?x(e)?e:i(e):n}xn(o,a,s,l),$n(o,a,s,l,c,u);var p,h=l&&l.$options&&l.$options.timezone;if(l.$$parserName=e,l.$parsers.push(function(e){if(l.$isEmpty(e))return null;if(t.test(e)){var r=i(e,p);return"UTC"===h&&r.setMinutes(r.getMinutes()-r.getTimezoneOffset()),r}return n}),l.$formatters.push(function(e){if(!l.$isEmpty(e)){if(!x(e))throw Cr("datefmt","Expected `{0}` to be a date",e);if((p=e)&&"UTC"===h){var t=6e4*p.getTimezoneOffset();p=new Date(p.getTime()+t)}return d("date")(e,r,h)}return p=null,""}),$(s.min)||s.ngMin){var g;l.$validators.min=function(e){return l.$isEmpty(e)||v(g)||i(e)>=g},s.$observe("min",function(e){g=f(e),l.$validate()})}if($(s.max)||s.ngMax){var m;l.$validators.max=function(e){return l.$isEmpty(e)||v(m)||i(e)<=m},s.$observe("max",function(e){m=f(e),l.$validate()})}l.$isEmpty=function(e){return!e||e.getTime&&e.getTime()!==e.getTime()}}}function xn(e,t,i,r){var o=t[0];(r.$$hasNativeValidators=y(o.validity))&&r.$parsers.push(function(e){var i=t.prop(Pn)||{};return i.badInput&&!i.typeMismatch?n:e})}function Cn(e,t,i,r,o,a){if(xn(e,t,i,r),$n(e,t,i,r,o,a),r.$$parserName="number",r.$parsers.push(function(e){return r.$isEmpty(e)?null:mr.test(e)?parseFloat(e):n}),r.$formatters.push(function(e){if(!r.$isEmpty(e)){if(!w(e))throw Cr("numfmt","Expected `{0}` to be a number",e);e=e.toString()}return e}),i.min||i.ngMin){var s;r.$validators.min=function(e){return r.$isEmpty(e)||v(s)||e>=s},i.$observe("min",function(e){$(e)&&!w(e)&&(e=parseFloat(e,10)),s=w(e)&&!isNaN(e)?e:n,r.$validate()})}if(i.max||i.ngMax){var l;r.$validators.max=function(e){return r.$isEmpty(e)||v(l)||e<=l},i.$observe("max",function(e){$(e)&&!w(e)&&(e=parseFloat(e,10)),l=w(e)&&!isNaN(e)?e:n,r.$validate()})}}function kn(e,t,n,i,r,o){$n(e,t,n,i,r,o),mn(i),i.$$parserName="url",i.$validators.url=function(e){return i.$isEmpty(e)||hr.test(e)}}function Sn(e,t,n,i,r,o){$n(e,t,n,i,r,o),mn(i),i.$$parserName="email",i.$validators.email=function(e){return i.$isEmpty(e)||gr.test(e)}}function En(e,t,n,i){v(n.name)&&t.attr("name",c());var r=function(e){t[0].checked&&i.$setViewValue(n.value,e&&e.type)};t.on("click",r),i.$render=function(){var e=n.value;t[0].checked=e==i.$viewValue},n.$observe("value",i.$render)}function Tn(e,t,n,r,o){var a;if($(r)){if(a=e(r),!a.constant)throw i("ngModel")("constexpr","Expected constant expression for `{0}`, but saw `{1}`.",n,r);return a(t)}return o}function Dn(e,t,n,i,r,o,a,s){var l=Tn(s,e,"ngTrueValue",n.ngTrueValue,!0),c=Tn(s,e,"ngFalseValue",n.ngFalseValue,!1),u=function(e){i.$setViewValue(t[0].checked,e&&e.type)};t.on("click",u),i.$render=function(){t[0].checked=i.$viewValue},i.$isEmpty=function(e){return e!==l},i.$formatters.push(function(e){return L(e,l)}),i.$parsers.push(function(e){return e?l:c})}function An(e){function t(e,t,l){t===n?i("$pending",e,l):r("$pending",e,l),A(t)?t?(d(s.$error,e,l),u(s.$$success,e,l)):(u(s.$error,e,l),d(s.$$success,e,l)):(d(s.$error,e,l),d(s.$$success,e,l)),s.$pending?(o(Mr,!0),s.$valid=s.$invalid=n,a("",null)):(o(Mr,!1),s.$valid=Mn(s.$error),s.$invalid=!s.$valid,a("",s.$valid));var c;c=s.$pending&&s.$pending[e]?n:!s.$error[e]&&(!!s.$$success[e]||null),a(e,c),f.$setValidity(e,c,s)}function i(e,t,n){s[e]||(s[e]={}),u(s[e],t,n)}function r(e,t,i){s[e]&&d(s[e],t,i),Mn(s[e])&&(s[e]=n)}function o(e,t){t&&!c[e]?(p.addClass(l,e),c[e]=!0):!t&&c[e]&&(p.removeClass(l,e),c[e]=!1)}function a(e,t){e=e?"-"+te(e,"-"):"",o(Er+e,!0===t),o(Tr+e,!1===t)}var s=e.ctrl,l=e.$element,c={},u=e.set,d=e.unset,f=e.parentForm,p=e.$animate;c[Tr]=!(c[Er]=l.hasClass(Er)),s.$setValidity=t}function Mn(e){if(e)for(var t in e)return!1;return!0}function On(e,t){return e="ngClass"+e,["$animate",function(n){function i(e,t){var n=[];e:for(var i=0;i<e.length;i++){for(var r=e[i],o=0;o<t.length;o++)if(r==t[o])continue e;n.push(r)}return n}function r(e){if(Zn(e))return e;if(b(e))return e.split(" ");if(y(e)){var t=[];return o(e,function(e,n){e&&(t=t.concat(n.split(" ")))}),t}return e}return{restrict:"AC",link:function(a,s,l){function c(e){var t=d(e,1);l.$addClass(t)}function u(e){var t=d(e,-1);l.$removeClass(t)}function d(e,t){var n=s.data("$classCounts")||{},i=[];return o(e,function(e){(t>0||n[e])&&(n[e]=(n[e]||0)+t,n[e]===+(t>0)&&i.push(e))}),s.data("$classCounts",n),i.join(" ")}function f(e,t){var r=i(t,e),o=i(e,t);r=d(r,1),o=d(o,-1),r&&r.length&&n.addClass(s,r),o&&o.length&&n.removeClass(s,o)}function p(e){if(!0===t||a.$index%2===t){var n=r(e||[]);if(h){if(!L(e,h)){var i=r(h);f(i,n)}}else c(n)}h=F(e)}var h;a.$watch(l[e],p,!0),l.$observe("class",function(t){p(a.$eval(l[e]))}),"ngClass"!==e&&a.$watch("$index",function(n,i){var o=1&n;if(o!==(1&i)){var s=r(a.$eval(l[e]));o===t?c(s):u(s)}})}}}]}var In=/^\/(.+)\/([a-z]*)$/,Pn="validity",Nn=function(e){return b(e)?e.toLowerCase():e},jn=Object.prototype.hasOwnProperty,Fn=function(e){return b(e)?e.toUpperCase():e},Ln=function(e){return b(e)?e.replace(/[A-Z]/g,function(e){return String.fromCharCode(32|e.charCodeAt(0))}):e},Rn=function(e){return b(e)?e.replace(/[a-z]/g,function(e){return String.fromCharCode(-33&e.charCodeAt(0))}):e};"i"!=="I".toLowerCase()&&(Nn=Ln,Fn=Rn);var Vn,Hn,qn,Un,_n=[].slice,Bn=[].splice,Wn=[].push,zn=Object.prototype.toString,Yn=i("ng"),Kn=e.angular||(e.angular={}),Gn=0;Vn=t.documentMode,h.$inject=[],g.$inject=[];var Xn,Zn=Array.isArray,Jn=function(e){return b(e)?e.trim():e},Qn=function(){if($(Qn.isActive_))return Qn.isActive_;var e=!(!t.querySelector("[ng-csp]")&&!t.querySelector("[data-ng-csp]"));if(!e)try{new Function("")}catch(t){e=!0}return Qn.isActive_=e},ei=["ng-","data-ng-","ng:","x-ng-"],ti=/[A-Z]/g,ni=!1,ii=1,ri=3,oi=8,ai=9,si=11,li={full:"1.3.0",major:1,minor:3,dot:0,codeName:"superluminal-nudge"};ge.expando="ng339";var ci=ge.cache={},ui=1,di=function(e,t,n){e.addEventListener(t,n,!1)},fi=function(e,t,n){e.removeEventListener(t,n,!1)};ge._data=function(e){return this.cache[e[this.expando]]||{}};var pi=/([\:\-\_]+(.))/g,hi=/^moz([A-Z])/,gi={mouseleave:"mouseout",mouseenter:"mouseover"},mi=i("jqLite"),vi=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,$i=/<|&#?\w+;/,yi=/<([\w:]+)/,bi=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,wi={option:[1,'<select multiple="multiple">',"</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};wi.optgroup=wi.option,wi.tbody=wi.tfoot=wi.colgroup=wi.caption=wi.thead,wi.th=wi.td;var xi=ge.prototype={ready:function(n){function i(){r||(r=!0,n())}var r=!1;"complete"===t.readyState?setTimeout(i):(this.on("DOMContentLoaded",i),ge(e).on("load",i),this.on("DOMContentLoaded",i))},toString:function(){var e=[];return o(this,function(t){e.push(""+t)}),"["+e.join(", ")+"]"},eq:function(e){return Hn(e>=0?this[e]:this[this.length+e])},length:0,push:Wn,sort:[].sort,splice:[].splice},Ci={};o("multiple,selected,checked,disabled,readOnly,required,open".split(","),function(e){Ci[Nn(e)]=e});var ki={};o("input,select,option,textarea,button,form,details".split(","),function(e){ki[e]=!0});var Si={ngMinlength:"minlength",ngMaxlength:"maxlength",ngMin:"min",ngMax:"max",ngPattern:"pattern"};o({data:we,removeData:ye},function(e,t){ge[t]=e}),o({data:we,inheritedData:Te,scope:function(e){return Hn.data(e,"$scope")||Te(e.parentNode||e,["$isolateScope","$scope"])},isolateScope:function(e){return Hn.data(e,"$isolateScope")||Hn.data(e,"$isolateScopeNoTemplate")},controller:Ee,injector:function(e){return Te(e,"$injector")},removeAttr:function(e,t){e.removeAttribute(t)},hasClass:xe,css:function(e,t,n){if(t=ue(t),!$(n))return e.style[t];e.style[t]=n},attr:function(e,t,i){var r=Nn(t);if(Ci[r]){if(!$(i))return e[t]||(e.attributes.getNamedItem(t)||h).specified?r:n;i?(e[t]=!0,e.setAttribute(t,r)):(e[t]=!1,e.removeAttribute(r))}else if($(i))e.setAttribute(t,i);else if(e.getAttribute){var o=e.getAttribute(t,2);return null===o?n:o}},prop:function(e,t,n){if(!$(n))return e[t];e[t]=n},text:function(){function e(e,t){if(v(t)){var n=e.nodeType;return n===ii||n===ri?e.textContent:""}e.textContent=t}return e.$dv="",e}(),val:function(e,t){if(v(t)){if(e.multiple&&"select"===P(e)){var n=[];return o(e.options,function(e){e.selected&&n.push(e.value||e.text)}),0===n.length?null:n}return e.value}e.value=t},html:function(e,t){if(v(t))return e.innerHTML;ve(e,!0),e.innerHTML=t},empty:De},function(e,t){ge.prototype[t]=function(t,i){var r,o,a=this.length;if(e!==De&&(2==e.length&&e!==xe&&e!==Ee?t:i)===n){if(y(t)){for(r=0;r<a;r++)if(e===we)e(this[r],t);else for(o in t)e(this[r],o,t[o]);return this}for(var s=e.$dv,l=s===n?Math.min(a,1):a,c=0;c<l;c++){var u=e(this[c],t,i);s=s?s+u:u}return s}for(r=0;r<a;r++)e(this[r],t,i);return this}}),o({removeData:ye,on:function e(t,n,i,r){if($(r))throw mi("onargs","jqLite#on() does not support the `selector` or `eventData` parameters");if(fe(t)){var o=be(t,!0),a=o.events,s=o.handle;s||(s=o.handle=Pe(t,a));for(var l=n.indexOf(" ")>=0?n.split(" "):[n],c=l.length;c--;){n=l[c];var u=a[n];u||(a[n]=[],"mouseenter"===n||"mouseleave"===n?e(t,gi[n],function(e){var t=this,i=e.relatedTarget;i&&(i===t||t.contains(i))||s(e,n)}):"$destroy"!==n&&di(t,n,s),u=a[n]),u.push(i)}}},off:$e,one:function(e,t,n){e=Hn(e),e.on(t,function i(){e.off(t,n),e.off(t,i)}),e.on(t,n)},replaceWith:function(e,t){var n,i=e.parentNode;ve(e),o(new ge(t),function(t){n?i.insertBefore(t,n.nextSibling):i.replaceChild(t,e),n=t})},children:function(e){var t=[];return o(e.childNodes,function(e){e.nodeType===ii&&t.push(e)}),t},contents:function(e){return e.contentDocument||e.childNodes||[]},append:function(e,t){var n=e.nodeType;if(n===ii||n===si){t=new ge(t);for(var i=0,r=t.length;i<r;i++){var o=t[i];e.appendChild(o)}}},prepend:function(e,t){if(e.nodeType===ii){var n=e.firstChild;o(new ge(t),function(t){e.insertBefore(t,n)})}},wrap:function(e,t){t=Hn(t).eq(0).clone()[0];var n=e.parentNode;n&&n.replaceChild(t,e),t.appendChild(e)},remove:Ae,detach:function(e){Ae(e,!0)},after:function(e,t){var n=e,i=e.parentNode;t=new ge(t);for(var r=0,o=t.length;r<o;r++){var a=t[r];i.insertBefore(a,n.nextSibling),n=a}},addClass:ke,removeClass:Ce,toggleClass:function(e,t,n){t&&o(t.split(" "),function(t){var i=n;v(i)&&(i=!xe(e,t)),(i?ke:Ce)(e,t)})},parent:function(e){var t=e.parentNode;return t&&t.nodeType!==si?t:null},next:function(e){return e.nextElementSibling},find:function(e,t){return e.getElementsByTagName?e.getElementsByTagName(t):[]},clone:me,triggerHandler:function(e,t,n){var i,r,a,s=t.type||t,l=be(e),c=l&&l.events,u=c&&c[s];u&&(i={preventDefault:function(){this.defaultPrevented=!0},isDefaultPrevented:function(){return!0===this.defaultPrevented},stopImmediatePropagation:function(){this.immediatePropagationStopped=!0},isImmediatePropagationStopped:function(){return!0===this.immediatePropagationStopped},stopPropagation:h,type:s,target:e},t.type&&(i=d(i,t)),r=F(u),a=n?[i].concat(n):[i],o(r,function(t){i.isImmediatePropagationStopped()||t.apply(e,a)}))}},function(e,t){ge.prototype[t]=function(t,n,i){for(var r,o=0,a=this.length;o<a;o++)v(r)?(r=e(this[o],t,n,i),$(r)&&(r=Hn(r))):Se(r,e(this[o],t,n,i));return $(r)?r:this},ge.prototype.bind=ge.prototype.on,ge.prototype.unbind=ge.prototype.off}),je.prototype={put:function(e,t){this[Ne(e,this.nextUid)]=t},get:function(e){return this[Ne(e,this.nextUid)]},remove:function(e){var t=this[e=Ne(e,this.nextUid)];return delete this[e],t}};var Ei=/^function\s*[^\(]*\(\s*([^\)]*)\)/m,Ti=/,/,Di=/^\s*(_?)(\S+?)\1\s*$/,Ai=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm,Mi=i("$injector");Re.$$annotate=Le;var Oi=i("$animate"),Ii=["$provide",function(e){this.$$selectors={},this.register=function(t,n){var i=t+"-animation";if(t&&"."!=t.charAt(0))throw Oi("notcsel","Expecting class selector starting with '.' got '{0}'.",t);this.$$selectors[t.substr(1)]=i,e.factory(i,n)},this.classNameFilter=function(e){return 1===arguments.length&&(this.$$classNameFilter=e instanceof RegExp?e:null),this.$$classNameFilter},this.$get=["$$q","$$asyncCallback","$rootScope",function(e,t,n){function i(t){var i,r=e.defer();return r.promise.$$cancelFn=function(){i&&i()},n.$$postDigest(function(){i=t(function(){r.resolve()})}),r.promise}function r(e,t){var n=[],i=[],r=se();return o((e.attr("class")||"").split(/\s+/),function(e){r[e]=!0}),o(t,function(e,t){var o=r[t];!1===e&&o?i.push(t):!0!==e||o||n.push(t)}),n.length+i.length>0&&[n.length?n:null,i.length?i:null]}function a(e,t,n){for(var i=0,r=t.length;i<r;++i){e[t[i]]=n}}function s(){return c||(c=e.defer(),t(function(){c.resolve(),c=null})),c.promise}function l(e,t){if(Kn.isObject(t)){var n=d(t.from||{},t.to||{});e.css(n)}}var c;return{animate:function(e,t,n){return l(e,{from:t,to:n}),s()},enter:function(e,t,n,i){return l(e,i),n?n.after(e):t.prepend(e),s()},leave:function(e,t){return e.remove(),s()},move:function(e,t,n,i){return this.enter(e,t,n,i)},addClass:function(e,t,n){return this.setClass(e,t,[],n)},$$addClassImmediately:function(e,t,n){return e=Hn(e),t=b(t)?t:Zn(t)?t.join(" "):"",o(e,function(e){ke(e,t)}),l(e,n),s()},removeClass:function(e,t,n){return this.setClass(e,[],t,n)},$$removeClassImmediately:function(e,t,n){return e=Hn(e),t=b(t)?t:Zn(t)?t.join(" "):"",o(e,function(e){Ce(e,t)}),l(e,n),s()},setClass:function(e,t,n,o){var s=this,l=!1;e=Hn(e);var c=e.data("$$animateClasses");c?o&&c.options&&(c.options=Kn.extend(c.options||{},o)):(c={classes:{},options:o},l=!0);var u=c.classes;return t=Zn(t)?t:t.split(" "),n=Zn(n)?n:n.split(" "),a(u,t,!0),a(u,n,!1),l&&(c.promise=i(function(t){var n=e.data("$$animateClasses");if(e.removeData("$$animateClasses"),n){var i=r(e,n.classes);i&&s.$$setClassImmediately(e,i[0],i[1],n.options)}t()}),
+e.data("$$animateClasses",c)),c.promise},$$setClassImmediately:function(e,t,n,i){return t&&this.$$addClassImmediately(e,t),n&&this.$$removeClassImmediately(e,n),l(e,i),s()},enabled:h,cancel:h}}]}],Pi=i("$compile");We.$inject=["$provide","$$sanitizeUriProvider"];var Ni=/^(x[\:\-_]|data[\:\-_])/i,ji=i("$interpolate"),Fi=/^([^\?#]*)(\?([^#]*))?(#(.*))?$/,Li={http:80,https:443,ftp:21},Ri=i("$location"),Vi={$$html5:!1,$$replace:!1,absUrl:yt("$$absUrl"),url:function(e){if(v(e))return this.$$url;var t=Fi.exec(e);return t[1]&&this.path(decodeURIComponent(t[1])),(t[2]||t[1])&&this.search(t[3]||""),this.hash(t[5]||""),this},protocol:yt("$$protocol"),host:yt("$$host"),port:yt("$$port"),path:bt("$$path",function(e){return e=null!==e?e.toString():"","/"==e.charAt(0)?e:"/"+e}),search:function(e,t){switch(arguments.length){case 0:return this.$$search;case 1:if(b(e)||w(e))e=e.toString(),this.$$search=z(e);else{if(!y(e))throw Ri("isrcharg","The first argument of the `$location#search()` call must be a string or an object.");e=j(e,{}),o(e,function(t,n){null==t&&delete e[n]}),this.$$search=e}break;default:v(t)||null===t?delete this.$$search[e]:this.$$search[e]=t}return this.$$compose(),this},hash:bt("$$hash",function(e){return null!==e?e.toString():""}),replace:function(){return this.$$replace=!0,this}};o([$t,vt,mt],function(e){e.prototype=Object.create(Vi),e.prototype.state=function(t){if(!arguments.length)return this.$$state;if(e!==mt||!this.$$html5)throw Ri("nostate","History API state support is available only in HTML5 mode and only in browsers supporting HTML5 History API");return this.$$state=v(t)?null:t,this}});var Hi=i("$parse"),qi=Function.prototype.call,Ui=Function.prototype.apply,_i=Function.prototype.bind,Bi=se();o({null:function(){return null},true:function(){return!0},false:function(){return!1},undefined:function(){}},function(e,t){e.constant=e.literal=e.sharedGetter=!0,Bi[t]=e}),Bi.this=function(e){return e},Bi.this.sharedGetter=!0;var Wi=d(se(),{"+":function(e,t,i,r){return i=i(e,t),r=r(e,t),$(i)?$(r)?i+r:i:$(r)?r:n},"-":function(e,t,n,i){return n=n(e,t),i=i(e,t),($(n)?n:0)-($(i)?i:0)},"*":function(e,t,n,i){return n(e,t)*i(e,t)},"/":function(e,t,n,i){return n(e,t)/i(e,t)},"%":function(e,t,n,i){return n(e,t)%i(e,t)},"===":function(e,t,n,i){return n(e,t)===i(e,t)},"!==":function(e,t,n,i){return n(e,t)!==i(e,t)},"==":function(e,t,n,i){return n(e,t)==i(e,t)},"!=":function(e,t,n,i){return n(e,t)!=i(e,t)},"<":function(e,t,n,i){return n(e,t)<i(e,t)},">":function(e,t,n,i){return n(e,t)>i(e,t)},"<=":function(e,t,n,i){return n(e,t)<=i(e,t)},">=":function(e,t,n,i){return n(e,t)>=i(e,t)},"&&":function(e,t,n,i){return n(e,t)&&i(e,t)},"||":function(e,t,n,i){return n(e,t)||i(e,t)},"!":function(e,t,n){return!n(e,t)},"=":!0,"|":!0}),zi={n:"\n",f:"\f",r:"\r",t:"\t",v:"\v","'":"'",'"':'"'},Yi=function(e){this.options=e};Yi.prototype={constructor:Yi,lex:function(e){for(this.text=e,this.index=0,this.ch=n,this.tokens=[];this.index<this.text.length;)if(this.ch=this.text.charAt(this.index),this.is("\"'"))this.readString(this.ch);else if(this.isNumber(this.ch)||this.is(".")&&this.isNumber(this.peek()))this.readNumber();else if(this.isIdent(this.ch))this.readIdent();else if(this.is("(){}[].,;:?"))this.tokens.push({index:this.index,text:this.ch}),this.index++;else if(this.isWhitespace(this.ch))this.index++;else{var t=this.ch+this.peek(),i=t+this.peek(2),r=Wi[this.ch],o=Wi[t],a=Wi[i];a?(this.tokens.push({index:this.index,text:i,fn:a}),this.index+=3):o?(this.tokens.push({index:this.index,text:t,fn:o}),this.index+=2):r?(this.tokens.push({index:this.index,text:this.ch,fn:r}),this.index+=1):this.throwError("Unexpected next character ",this.index,this.index+1)}return this.tokens},is:function(e){return-1!==e.indexOf(this.ch)},peek:function(e){var t=e||1;return this.index+t<this.text.length&&this.text.charAt(this.index+t)},isNumber:function(e){return"0"<=e&&e<="9"},isWhitespace:function(e){return" "===e||"\r"===e||"\t"===e||"\n"===e||"\v"===e||" "===e},isIdent:function(e){return"a"<=e&&e<="z"||"A"<=e&&e<="Z"||"_"===e||"$"===e},isExpOperator:function(e){return"-"===e||"+"===e||this.isNumber(e)},throwError:function(e,t,n){n=n||this.index;var i=$(t)?"s "+t+"-"+this.index+" ["+this.text.substring(t,n)+"]":" "+n;throw Hi("lexerr","Lexer Error: {0} at column{1} in expression [{2}].",e,i,this.text)},readNumber:function(){for(var e="",t=this.index;this.index<this.text.length;){var n=Nn(this.text.charAt(this.index));if("."==n||this.isNumber(n))e+=n;else{var i=this.peek();if("e"==n&&this.isExpOperator(i))e+=n;else if(this.isExpOperator(n)&&i&&this.isNumber(i)&&"e"==e.charAt(e.length-1))e+=n;else{if(!this.isExpOperator(n)||i&&this.isNumber(i)||"e"!=e.charAt(e.length-1))break;this.throwError("Invalid exponent")}}this.index++}e*=1,this.tokens.push({index:t,text:e,constant:!0,fn:function(){return e}})},readIdent:function(){for(var e,t,i,r,o=this.text,a="",s=this.index;this.index<this.text.length&&("."===(r=this.text.charAt(this.index))||this.isIdent(r)||this.isNumber(r));)"."===r&&(e=this.index),a+=r,this.index++;if(e&&"."===a[a.length-1]&&(this.index--,a=a.slice(0,-1),-1===(e=a.lastIndexOf("."))&&(e=n)),e)for(t=this.index;t<this.text.length;){if("("===(r=this.text.charAt(t))){i=a.substr(e-s+1),a=a.substr(0,e-s),this.index=t;break}if(!this.isWhitespace(r))break;t++}this.tokens.push({index:s,text:a,fn:Bi[a]||At(a,this.options,o)}),i&&(this.tokens.push({index:e,text:"."}),this.tokens.push({index:e+1,text:i}))},readString:function(e){var t=this.index;this.index++;for(var n="",i=e,r=!1;this.index<this.text.length;){var o=this.text.charAt(this.index);if(i+=o,r){if("u"===o){var a=this.text.substring(this.index+1,this.index+5);a.match(/[\da-f]{4}/i)||this.throwError("Invalid unicode escape [\\u"+a+"]"),this.index+=4,n+=String.fromCharCode(parseInt(a,16))}else{n+=zi[o]||o}r=!1}else if("\\"===o)r=!0;else{if(o===e)return this.index++,void this.tokens.push({index:t,text:i,string:n,constant:!0,fn:function(){return n}});n+=o}this.index++}this.throwError("Unterminated quote",t)}};var Ki=function(e,t,n){this.lexer=e,this.$filter=t,this.options=n};Ki.ZERO=d(function(){return 0},{sharedGetter:!0,constant:!0}),Ki.prototype={constructor:Ki,parse:function(e){this.text=e,this.tokens=this.lexer.lex(e);var t=this.statements();return 0!==this.tokens.length&&this.throwError("is an unexpected token",this.tokens[0]),t.literal=!!t.literal,t.constant=!!t.constant,t},primary:function(){var e;if(this.expect("("))e=this.filterChain(),this.consume(")");else if(this.expect("["))e=this.arrayDeclaration();else if(this.expect("{"))e=this.object();else{var t=this.expect();e=t.fn,e||this.throwError("not a primary expression",t),t.constant&&(e.constant=!0,e.literal=!0)}for(var n,i;n=this.expect("(","[",".");)"("===n.text?(e=this.functionCall(e,i),i=null):"["===n.text?(i=e,e=this.objectIndex(e)):"."===n.text?(i=e,e=this.fieldAccess(e)):this.throwError("IMPOSSIBLE");return e},throwError:function(e,t){throw Hi("syntax","Syntax Error: Token '{0}' {1} at column {2} of the expression [{3}] starting at [{4}].",t.text,e,t.index+1,this.text,this.text.substring(t.index))},peekToken:function(){if(0===this.tokens.length)throw Hi("ueoe","Unexpected end of expression: {0}",this.text);return this.tokens[0]},peek:function(e,t,n,i){if(this.tokens.length>0){var r=this.tokens[0],o=r.text;if(o===e||o===t||o===n||o===i||!e&&!t&&!n&&!i)return r}return!1},expect:function(e,t,n,i){var r=this.peek(e,t,n,i);return!!r&&(this.tokens.shift(),r)},consume:function(e){this.expect(e)||this.throwError("is unexpected, expecting ["+e+"]",this.peek())},unaryFn:function(e,t){return d(function(n,i){return e(n,i,t)},{constant:t.constant,inputs:[t]})},binaryFn:function(e,t,n,i){return d(function(i,r){return t(i,r,e,n)},{constant:e.constant&&n.constant,inputs:!i&&[e,n]})},statements:function(){for(var e=[];;)if(this.tokens.length>0&&!this.peek("}",")",";","]")&&e.push(this.filterChain()),!this.expect(";"))return 1===e.length?e[0]:function(t,n){for(var i,r=0,o=e.length;r<o;r++)i=e[r](t,n);return i}},filterChain:function(){for(var e=this.expression();this.expect("|");)e=this.filter(e);return e},filter:function(e){var t,i,r=this.expect(),o=this.$filter(r.text);if(this.peek(":"))for(t=[],i=[];this.expect(":");)t.push(this.expression());var a=[e].concat(t||[]);return d(function(r,a){var s=e(r,a);if(i){i[0]=s;for(var l=t.length;l--;)i[l+1]=t[l](r,a);return o.apply(n,i)}return o(s)},{constant:!o.$stateful&&a.every(Et),inputs:!o.$stateful&&a})},expression:function(){return this.assignment()},assignment:function(){var e,t,n=this.ternary();return(t=this.expect("="))?(n.assign||this.throwError("implies assignment but ["+this.text.substring(0,t.index)+"] can not be assigned to",t),e=this.ternary(),d(function(t,i){return n.assign(t,e(t,i),i)},{inputs:[n,e]})):n},ternary:function(){var e,t,n=this.logicalOR();if(t=this.expect("?")){if(e=this.assignment(),t=this.expect(":")){var i=this.assignment();return d(function(t,r){return n(t,r)?e(t,r):i(t,r)},{constant:n.constant&&e.constant&&i.constant})}this.throwError("expected :",t)}return n},logicalOR:function(){for(var e,t=this.logicalAND();e=this.expect("||");)t=this.binaryFn(t,e.fn,this.logicalAND(),!0);return t},logicalAND:function(){var e,t=this.equality();return(e=this.expect("&&"))&&(t=this.binaryFn(t,e.fn,this.logicalAND(),!0)),t},equality:function(){var e,t=this.relational();return(e=this.expect("==","!=","===","!=="))&&(t=this.binaryFn(t,e.fn,this.equality())),t},relational:function(){var e,t=this.additive();return(e=this.expect("<",">","<=",">="))&&(t=this.binaryFn(t,e.fn,this.relational())),t},additive:function(){for(var e,t=this.multiplicative();e=this.expect("+","-");)t=this.binaryFn(t,e.fn,this.multiplicative());return t},multiplicative:function(){for(var e,t=this.unary();e=this.expect("*","/","%");)t=this.binaryFn(t,e.fn,this.unary());return t},unary:function(){var e;return this.expect("+")?this.primary():(e=this.expect("-"))?this.binaryFn(Ki.ZERO,e.fn,this.unary()):(e=this.expect("!"))?this.unaryFn(e.fn,this.unary()):this.primary()},fieldAccess:function(e){var t=this.text,n=this.expect().text,i=At(n,this.options,t);return d(function(t,n,r){return i(r||e(t,n))},{assign:function(i,r,o){var a=e(i,o);return a||e.assign(i,a={}),Tt(a,n,r,t)}})},objectIndex:function(e){var t=this.text,i=this.expression();return this.consume("]"),d(function(r,o){var a=e(r,o),s=i(r,o);return Ct(s,t),a?kt(a[s],t):n},{assign:function(n,r,o){var a=Ct(i(n,o),t),s=kt(e(n,o),t);return s||e.assign(n,s={}),s[a]=r}})},functionCall:function(e,t){var n=[];if(")"!==this.peekToken().text)do{n.push(this.expression())}while(this.expect(","));this.consume(")");var i=this.text,r=n.length?[]:null;return function(o,a){var s=t?t(o,a):o,l=e(o,a,s)||h;if(r)for(var c=n.length;c--;)r[c]=kt(n[c](o,a),i);return kt(s,i),St(l,i),kt(l.apply?l.apply(s,r):l(r[0],r[1],r[2],r[3],r[4]),i)}},arrayDeclaration:function(){var e=[];if("]"!==this.peekToken().text)do{if(this.peek("]"))break;var t=this.expression();e.push(t)}while(this.expect(","));return this.consume("]"),d(function(t,n){for(var i=[],r=0,o=e.length;r<o;r++)i.push(e[r](t,n));return i},{literal:!0,constant:e.every(Et),inputs:e})},object:function(){var e=[],t=[];if("}"!==this.peekToken().text)do{if(this.peek("}"))break;var n=this.expect();e.push(n.string||n.text),this.consume(":");var i=this.expression();t.push(i)}while(this.expect(","));return this.consume("}"),d(function(n,i){for(var r={},o=0,a=t.length;o<a;o++)r[e[o]]=t[o](n,i);return r},{literal:!0,constant:t.every(Et),inputs:t})}};var Gi=se(),Xi=i("$sce"),Zi={HTML:"html",CSS:"css",URL:"url",RESOURCE_URL:"resourceUrl",JS:"js"},Pi=i("$compile"),Ji=t.createElement("a"),Qi=zt(e.location.href,!0);Gt.$inject=["$provide"],Zt.$inject=["$locale"],Jt.$inject=["$locale"];var er=".",tr={yyyy:tn("FullYear",4),yy:tn("FullYear",2,0,!0),y:tn("FullYear",1),MMMM:nn("Month"),MMM:nn("Month",!0),MM:tn("Month",2,1),M:tn("Month",1,1),dd:tn("Date",2),d:tn("Date",1),HH:tn("Hours",2),H:tn("Hours",1),hh:tn("Hours",2,-12),h:tn("Hours",1,-12),mm:tn("Minutes",2),m:tn("Minutes",1),ss:tn("Seconds",2),s:tn("Seconds",1),sss:tn("Milliseconds",3),EEEE:nn("Day"),EEE:nn("Day",!0),a:ln,Z:rn,ww:sn(2),w:sn(1)},nr=/((?:[^yMdHhmsaZEw']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|w+))(.*)/,ir=/^\-?\d+$/;cn.$inject=["$locale"];var rr=m(Nn),or=m(Fn);fn.$inject=["$parse"];var ar=m({restrict:"E",compile:function(e,t){if(!t.href&&!t.xlinkHref&&!t.name)return function(e,t){var n="[object SVGAnimatedString]"===zn.call(t.prop("href"))?"xlink:href":"href";t.on("click",function(e){t.attr(n)||e.preventDefault()})}}}),sr={};o(Ci,function(e,t){if("multiple"!=e){var n=ze("ng-"+t);sr[n]=function(){return{restrict:"A",priority:100,link:function(e,i,r){e.$watch(r[n],function(e){r.$set(t,!!e)})}}}}}),o(Si,function(e,t){sr[t]=function(){return{priority:100,link:function(e,n,i){if("ngPattern"===t&&"/"==i.ngPattern.charAt(0)){var r=i.ngPattern.match(In);if(r)return void i.$set("ngPattern",new RegExp(r[1],r[2]))}e.$watch(i[t],function(e){i.$set(t,e)})}}}}),o(["src","srcset","href"],function(e){var t=ze("ng-"+e);sr[t]=function(){return{priority:99,link:function(n,i,r){var o=e,a=e;"href"===e&&"[object SVGAnimatedString]"===zn.call(i.prop("href"))&&(a="xlinkHref",r.$attr[a]="xlink:href",o=null),r.$observe(t,function(t){if(!t)return void("href"===e&&r.$set(a,null));r.$set(a,t),Vn&&o&&i.prop(o,r[a])})}}}});var lr={$addControl:h,$$renameControl:hn,$removeControl:h,$setValidity:h,$setDirty:h,$setPristine:h,$setSubmitted:h},cr="ng-submitted";gn.$inject=["$element","$attrs","$scope","$animate","$interpolate"];var ur=function(e){return["$timeout",function(t){return{name:"form",restrict:e?"EAC":"E",controller:gn,compile:function(e){return e.addClass(Dr).addClass(Er),{pre:function(e,i,r,o){if(!("action"in r)){var a=function(t){e.$apply(function(){o.$commitViewValue(),o.$setSubmitted()}),t.preventDefault?t.preventDefault():t.returnValue=!1};di(i[0],"submit",a),i.on("$destroy",function(){t(function(){fi(i[0],"submit",a)},0,!1)})}var s=o.$$parentForm,l=o.$name;l&&(Tt(e,l,o,l),r.$observe(r.name?"name":"ngForm",function(t){l!==t&&(Tt(e,l,n,l),l=t,Tt(e,l,o,l),s.$$renameControl(o,l))})),i.on("$destroy",function(){s.$removeControl(o),l&&Tt(e,l,n,l),d(o,lr)})}}}}}]},dr=ur(),fr=ur(!0),pr=/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/,hr=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,gr=/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,mr=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,vr=/^(\d{4})-(\d{2})-(\d{2})$/,$r=/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,yr=/^(\d{4})-W(\d\d)$/,br=/^(\d{4})-(\d\d)$/,wr=/^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/,xr=/(\s+|^)default(\s+|$)/,Cr=new i("ngModel"),kr={text:vn,date:wn("date",vr,bn(vr,["yyyy","MM","dd"]),"yyyy-MM-dd"),"datetime-local":wn("datetimelocal",$r,bn($r,["yyyy","MM","dd","HH","mm","ss","sss"]),"yyyy-MM-ddTHH:mm:ss.sss"),time:wn("time",wr,bn(wr,["HH","mm","ss","sss"]),"HH:mm:ss.sss"),week:wn("week",yr,yn,"yyyy-Www"),month:wn("month",br,bn(br,["yyyy","MM"]),"yyyy-MM"),number:Cn,url:kn,email:Sn,radio:En,checkbox:Dn,hidden:h,button:h,submit:h,reset:h,file:h},Sr=["$browser","$sniffer","$filter","$parse",function(e,t,n,i){return{restrict:"E",require:["?ngModel"],link:{pre:function(r,o,a,s){s[0]&&(kr[Nn(a.type)]||kr.text)(r,o,a,s[0],t,e,n,i)}}}}],Er="ng-valid",Tr="ng-invalid",Dr="ng-pristine",Ar="ng-dirty",Mr="ng-pending",Or=["$scope","$exceptionHandler","$attrs","$element","$parse","$animate","$timeout","$rootScope","$q","$interpolate",function(e,t,i,r,a,s,l,c,u,d){this.$viewValue=Number.NaN,this.$modelValue=Number.NaN,this.$validators={},this.$asyncValidators={},this.$parsers=[],this.$formatters=[],this.$viewChangeListeners=[],this.$untouched=!0,this.$touched=!1,this.$pristine=!0,this.$dirty=!1,this.$valid=!0,this.$invalid=!1,this.$error={},this.$$success={},this.$pending=n,this.$name=d(i.name||"",!1)(e);var f=a(i.ngModel),p=null,g=this,m=function(){var t=f(e);return g.$options&&g.$options.getterSetter&&C(t)&&(t=t()),t},y=function(t){var n;g.$options&&g.$options.getterSetter&&C(n=f(e))?n(g.$modelValue):f.assign(e,g.$modelValue)};this.$$setOptions=function(e){if(g.$options=e,!(f.assign||e&&e.getterSetter))throw Cr("nonassign","Expression '{0}' is non-assignable. Element: {1}",i.ngModel,B(r))},this.$render=h,this.$isEmpty=function(e){return v(e)||""===e||null===e||e!==e};var b=r.inheritedData("$formController")||lr,x=0;An({ctrl:this,$element:r,set:function(e,t){e[t]=!0},unset:function(e,t){delete e[t]},parentForm:b,$animate:s}),this.$setPristine=function(){g.$dirty=!1,g.$pristine=!0,s.removeClass(r,Ar),s.addClass(r,Dr)},this.$setUntouched=function(){g.$touched=!1,g.$untouched=!0,s.setClass(r,"ng-untouched","ng-touched")},this.$setTouched=function(){g.$touched=!0,g.$untouched=!1,s.setClass(r,"ng-touched","ng-untouched")},this.$rollbackViewValue=function(){l.cancel(p),g.$viewValue=g.$$lastCommittedViewValue,g.$render()},this.$validate=function(){w(g.$modelValue)&&isNaN(g.$modelValue)||this.$$parseAndValidate()},this.$$runValidators=function(e,t,i,r){function a(e,t){l===x&&g.$setValidity(e,t)}function s(e){l===x&&r(e)}x++;var l=x;return function(e){var t=g.$$parserName||"parse";if(e===n)a(t,null);else if(a(t,e),!e)return o(g.$validators,function(e,t){a(t,null)}),o(g.$asyncValidators,function(e,t){a(t,null)}),!1;return!0}(e)&&function(){var e=!0;return o(g.$validators,function(n,r){var o=n(t,i);e=e&&o,a(r,o)}),!!e||(o(g.$asyncValidators,function(e,t){a(t,null)}),!1)}()?void function(){var e=[],r=!0;o(g.$asyncValidators,function(o,s){var l=o(t,i);if(!M(l))throw Cr("$asyncValidators","Expected asynchronous validator to return a promise but got '{0}' instead.",l);a(s,n),e.push(l.then(function(){a(s,!0)},function(e){r=!1,a(s,!1)}))}),e.length?u.all(e).then(function(){s(r)},h):s(!0)}():void s(!1)},this.$commitViewValue=function(){var e=g.$viewValue;l.cancel(p),(g.$$lastCommittedViewValue!==e||""===e&&g.$$hasNativeValidators)&&(g.$$lastCommittedViewValue=e,g.$pristine&&(g.$dirty=!0,g.$pristine=!1,s.removeClass(r,Dr),s.addClass(r,Ar),b.$setDirty()),this.$$parseAndValidate())},this.$$parseAndValidate=function(){function e(){g.$modelValue!==a&&g.$$writeModelToScope()}var t=g.$$lastCommittedViewValue,i=t,r=!v(i)||n;if(r)for(var o=0;o<g.$parsers.length;o++)if(i=g.$parsers[o](i),v(i)){r=!1;break}w(g.$modelValue)&&isNaN(g.$modelValue)&&(g.$modelValue=m());var a=g.$modelValue,s=g.$options&&g.$options.allowInvalid;s&&(g.$modelValue=i,e()),g.$$runValidators(r,i,t,function(t){s||(g.$modelValue=t?i:n,e())})},this.$$writeModelToScope=function(){y(g.$modelValue),o(g.$viewChangeListeners,function(e){try{e()}catch(e){t(e)}})},this.$setViewValue=function(e,t){g.$viewValue=e,g.$options&&!g.$options.updateOnDefault||g.$$debounceViewValueCommit(t)},this.$$debounceViewValueCommit=function(t){var n,i=0,r=g.$options;r&&$(r.debounce)&&(n=r.debounce,w(n)?i=n:w(n[t])?i=n[t]:w(n.default)&&(i=n.default)),l.cancel(p),i?p=l(function(){g.$commitViewValue()},i):c.$$phase?g.$commitViewValue():e.$apply(function(){g.$commitViewValue()})},e.$watch(function(){var e=m();if(e!==g.$modelValue){g.$modelValue=e;for(var t=g.$formatters,i=t.length,r=e;i--;)r=t[i](r);g.$viewValue!==r&&(g.$viewValue=g.$$lastCommittedViewValue=r,g.$render(),g.$$runValidators(n,e,r,h))}return e})}],Ir=function(){return{restrict:"A",require:["ngModel","^?form","^?ngModelOptions"],controller:Or,priority:1,compile:function(e){return e.addClass(Dr).addClass("ng-untouched").addClass(Er),{pre:function(e,t,n,i){var r=i[0],o=i[1]||lr;r.$$setOptions(i[2]&&i[2].$options),o.$addControl(r),n.$observe("name",function(e){r.$name!==e&&o.$$renameControl(r,e)}),e.$on("$destroy",function(){o.$removeControl(r)})},post:function(e,t,n,i){var r=i[0];r.$options&&r.$options.updateOn&&t.on(r.$options.updateOn,function(e){r.$$debounceViewValueCommit(e&&e.type)}),t.on("blur",function(t){r.$touched||e.$apply(function(){r.$setTouched()})})}}}}},Pr=m({restrict:"A",require:"ngModel",link:function(e,t,n,i){i.$viewChangeListeners.push(function(){e.$eval(n.ngChange)})}}),Nr=function(){return{restrict:"A",require:"?ngModel",link:function(e,t,n,i){i&&(n.required=!0,i.$validators.required=function(e){return!n.required||!i.$isEmpty(e)},n.$observe("required",function(){i.$validate()}))}}},jr=function(){return{restrict:"A",require:"?ngModel",link:function(e,t,r,o){if(o){var a,s=r.ngPattern||r.pattern;r.$observe("pattern",function(e){if(b(e)&&e.length>0&&(e=new RegExp(e)),e&&!e.test)throw i("ngPattern")("noregexp","Expected {0} to be a RegExp but was {1}. Element: {2}",s,e,B(t));a=e||n,o.$validate()}),o.$validators.pattern=function(e){return o.$isEmpty(e)||v(a)||a.test(e)}}}}},Fr=function(){return{restrict:"A",require:"?ngModel",link:function(e,t,n,i){if(i){var r=0;n.$observe("maxlength",function(e){r=f(e)||0,i.$validate()}),i.$validators.maxlength=function(e,t){return i.$isEmpty(e)||t.length<=r}}}}},Lr=function(){return{restrict:"A",require:"?ngModel",link:function(e,t,n,i){if(i){var r=0;n.$observe("minlength",function(e){r=f(e)||0,i.$validate()}),i.$validators.minlength=function(e,t){return i.$isEmpty(e)||t.length>=r}}}}},Rr=function(){return{restrict:"A",priority:100,require:"ngModel",link:function(e,t,i,r){var a=t.attr(i.$attr.ngList)||", ",s="false"!==i.ngTrim,l=s?Jn(a):a,c=function(e){if(!v(e)){var t=[];return e&&o(e.split(l),function(e){e&&t.push(s?Jn(e):e)}),t}};r.$parsers.push(c),r.$formatters.push(function(e){return Zn(e)?e.join(a):n}),r.$isEmpty=function(e){return!e||!e.length}}}},Vr=/^(true|false|\d+)$/,Hr=function(){return{restrict:"A",priority:100,compile:function(e,t){return Vr.test(t.ngValue)?function(e,t,n){n.$set("value",e.$eval(n.ngValue))}:function(e,t,n){e.$watch(n.ngValue,function(e){n.$set("value",e)})}}}},qr=function(){return{restrict:"A",controller:["$scope","$attrs",function(e,t){var i=this;this.$options=e.$eval(t.ngModelOptions),this.$options.updateOn!==n?(this.$options.updateOnDefault=!1,this.$options.updateOn=Jn(this.$options.updateOn.replace(xr,function(){return i.$options.updateOnDefault=!0," "}))):this.$options.updateOnDefault=!0}]}},Ur=["$compile",function(e){return{restrict:"AC",compile:function(t){return e.$$addBindingClass(t),function(t,i,r){e.$$addBindingInfo(i,r.ngBind),i=i[0],t.$watch(r.ngBind,function(e){i.textContent=e===n?"":e})}}}}],_r=["$interpolate","$compile",function(e,t){return{compile:function(i){return t.$$addBindingClass(i),function(i,r,o){var a=e(r.attr(o.$attr.ngBindTemplate));t.$$addBindingInfo(r,a.expressions),r=r[0],o.$observe("ngBindTemplate",function(e){r.textContent=e===n?"":e})}}}}],Br=["$sce","$parse","$compile",function(e,t,n){return{restrict:"A",compile:function(i,r){var o=t(r.ngBindHtml),a=t(r.ngBindHtml,function(e){return(e||"").toString()});return n.$$addBindingClass(i),function(t,i,r){n.$$addBindingInfo(i,r.ngBindHtml),t.$watch(a,function(){i.html(e.getTrustedHtml(o(t))||"")})}}}}],Wr=On("",!0),zr=On("Odd",0),Yr=On("Even",1),Kr=pn({compile:function(e,t){t.$set("ngCloak",n),e.removeClass("ng-cloak")}}),Gr=[function(){return{restrict:"A",scope:!0,controller:"@",priority:500}}],Xr={},Zr={blur:!0,focus:!0};o("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),function(e){var t=ze("ng-"+e);Xr[t]=["$parse","$rootScope",function(n,i){return{restrict:"A",compile:function(r,o){var a=n(o[t]);return function(t,n){n.on(e,function(n){var r=function(){a(t,{$event:n})};Zr[e]&&i.$$phase?t.$evalAsync(r):t.$apply(r)})}}}}]});var Jr=["$animate",function(e){return{multiElement:!0,transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(n,i,r,o,a){var s,l,c;n.$watch(r.ngIf,function(n){n?l||a(function(n,o){l=o,n[n.length++]=t.createComment(" end ngIf: "+r.ngIf+" "),s={clone:n},e.enter(n,i.parent(),i)}):(c&&(c.remove(),c=null),l&&(l.$destroy(),l=null),s&&(c=ae(s.clone),e.leave(c).then(function(){c=null}),s=null))})}}}],Qr=["$templateRequest","$anchorScroll","$animate","$sce",function(e,t,n,i){return{restrict:"ECA",priority:400,terminal:!0,transclude:"element",controller:Kn.noop,compile:function(r,o){var a=o.ngInclude||o.src,s=o.onload||"",l=o.autoscroll;return function(r,o,c,u,d){var f,p,h,g=0,m=function(){p&&(p.remove(),p=null),f&&(f.$destroy(),f=null),h&&(n.leave(h).then(function(){p=null}),p=h,h=null)};r.$watch(i.parseAsResourceUrl(a),function(i){var a=function(){!$(l)||l&&!r.$eval(l)||t()},c=++g;i?(e(i,!0).then(function(e){if(c===g){var t=r.$new();u.template=e;var l=d(t,function(e){m(),n.enter(e,null,o).then(a)});f=t,h=l,f.$emit("$includeContentLoaded",i),r.$eval(s)}},function(){c===g&&(m(),r.$emit("$includeContentError",i))}),r.$emit("$includeContentRequested",i)):(m(),u.template=null)})}}}}],eo=["$compile",function(e){return{restrict:"ECA",priority:-400,require:"ngInclude",link:function(i,r,o,a){if(/SVG/.test(r[0].toString()))return r.empty(),void e(pe(a.template,t).childNodes)(i,function(e){r.append(e)},n,n,r);r.html(a.template),e(r.contents())(i)}}}],to=pn({priority:450,compile:function(){return{pre:function(e,t,n){e.$eval(n.ngInit)}}}}),no=pn({terminal:!0,priority:1e3}),io=["$locale","$interpolate",function(e,t){var n=/{}/g;return{restrict:"EA",link:function(i,r,a){var s=a.count,l=a.$attr.when&&r.attr(a.$attr.when),c=a.offset||0,u=i.$eval(l)||{},d={},f=t.startSymbol(),p=t.endSymbol(),h=/^when(Minus)?(.+)$/;o(a,function(e,t){h.test(t)&&(u[Nn(t.replace("when","").replace("Minus","-"))]=r.attr(a.$attr[t]))}),o(u,function(e,i){d[i]=t(e.replace(n,f+s+"-"+c+p))}),i.$watch(function(){var t=parseFloat(i.$eval(s));return isNaN(t)?"":(t in u||(t=e.pluralCat(t-c)),d[t](i))},function(e){r.text(e)})}}}],ro=["$parse","$animate",function(e,a){var s=i("ngRepeat"),l=function(e,t,n,i,r,o,a){e[n]=i,r&&(e[r]=o),e.$index=t,e.$first=0===t,e.$last=t===a-1,e.$middle=!(e.$first||e.$last),e.$odd=!(e.$even=0==(1&t))},c=function(e){return e.clone[0]},u=function(e){return e.clone[e.clone.length-1]};return{restrict:"A",multiElement:!0,transclude:"element",priority:1e3,terminal:!0,$$tlb:!0,compile:function(i,d){var f=d.ngRepeat,p=t.createComment(" end ngRepeat: "+f+" "),h=f.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);if(!h)throw s("iexp","Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",f);var g=h[1],m=h[2],v=h[3],$=h[4];if(!(h=g.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/)))throw s("iidexp","'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",g);var y=h[3]||h[1],b=h[2];if(v&&(!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(v)||/^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent)$/.test(v)))throw s("badident","alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",v);var w,x,C,k,S={$id:Ne};return $?w=e($):(C=function(e,t){return Ne(t)},k=function(e){return e}),function(e,t,i,d,h){w&&(x=function(t,n,i){return b&&(S[b]=t),S[y]=n,S.$index=i,w(e,S)});var g=se();e.$watchCollection(m,function(i){var d,m,$,w,S,E,T,D,A,M,O,I,P=t[0],N=se();if(v&&(e[v]=i),r(i))A=i,D=x||C;else{D=x||k,A=[];for(var j in i)i.hasOwnProperty(j)&&"$"!=j.charAt(0)&&A.push(j);A.sort()}for(w=A.length,O=new Array(w),d=0;d<w;d++)if(S=i===A?d:A[d],E=i[S],T=D(S,E,d),g[T])M=g[T],delete g[T],N[T]=M,O[d]=M;else{if(N[T])throw o(O,function(e){e&&e.scope&&(g[e.id]=e)}),s("dupes","Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",f,T,U(E));O[d]={id:T,scope:n,clone:n},N[T]=!0}for(var F in g){if(M=g[F],I=ae(M.clone),a.leave(I),I[0].parentNode)for(d=0,m=I.length;d<m;d++)I[d].$$NG_REMOVED=!0;M.scope.$destroy()}for(d=0;d<w;d++)if(S=i===A?d:A[d],E=i[S],M=O[d],M.scope){$=P;do{$=$.nextSibling}while($&&$.$$NG_REMOVED);c(M)!=$&&a.move(ae(M.clone),null,Hn(P)),P=u(M),l(M.scope,d,y,E,b,S,w)}else h(function(e,t){M.scope=t;var n=p.cloneNode(!1);e[e.length++]=n,a.enter(e,null,Hn(P)),P=n,M.clone=e,N[M.id]=M,l(M.scope,d,y,E,b,S,w)});g=N})}}}}],oo=["$animate",function(e){return{restrict:"A",multiElement:!0,link:function(t,n,i){t.$watch(i.ngShow,function(t){e[t?"removeClass":"addClass"](n,"ng-hide",{tempClasses:"ng-hide-animate"})})}}}],ao=["$animate",function(e){return{restrict:"A",multiElement:!0,link:function(t,n,i){t.$watch(i.ngHide,function(t){e[t?"addClass":"removeClass"](n,"ng-hide",{tempClasses:"ng-hide-animate"})})}}}],so=pn(function(e,t,n){e.$watch(n.ngStyle,function(e,n){n&&e!==n&&o(n,function(e,n){t.css(n,"")}),e&&t.css(e)},!0)}),lo=["$animate",function(e){return{restrict:"EA",require:"ngSwitch",controller:["$scope",function(){this.cases={}}],link:function(n,i,r,a){var s=r.ngSwitch||r.on,l=[],c=[],u=[],d=[],f=function(e,t){return function(){e.splice(t,1)}};n.$watch(s,function(n){var i,r;for(i=0,r=u.length;i<r;++i)e.cancel(u[i]);for(u.length=0,i=0,r=d.length;i<r;++i){var s=ae(c[i].clone);d[i].$destroy();(u[i]=e.leave(s)).then(f(u,i))}c.length=0,d.length=0,(l=a.cases["!"+n]||a.cases["?"])&&o(l,function(n){n.transclude(function(i,r){d.push(r);var o=n.element;i[i.length++]=t.createComment(" end ngSwitchWhen: ");var a={clone:i};c.push(a),e.enter(i,o.parent(),o)})})})}}}],co=pn({transclude:"element",priority:1200,require:"^ngSwitch",multiElement:!0,link:function(e,t,n,i,r){i.cases["!"+n.ngSwitchWhen]=i.cases["!"+n.ngSwitchWhen]||[],i.cases["!"+n.ngSwitchWhen].push({transclude:r,element:t})}}),uo=pn({transclude:"element",priority:1200,require:"^ngSwitch",multiElement:!0,link:function(e,t,n,i,r){i.cases["?"]=i.cases["?"]||[],i.cases["?"].push({transclude:r,element:t})}}),fo=pn({restrict:"EAC",link:function(e,t,n,r,o){if(!o)throw i("ngTransclude")("orphan","Illegal use of ngTransclude directive in the template! No parent directive that requires a transclusion found. Element: {0}",B(t));o(function(e){t.empty(),t.append(e)})}}),po=["$templateCache",function(e){return{restrict:"E",terminal:!0,compile:function(t,n){if("text/ng-template"==n.type){var i=n.id,r=t[0].text;e.put(i,r)}}}}],ho=i("ngOptions"),go=m({restrict:"A",terminal:!0}),mo=["$compile","$parse",function(e,i){var r=/^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,s={$setViewValue:h};return{restrict:"E",require:["select","?ngModel"],controller:["$element","$scope","$attrs",function(e,t,n){var i,r,o=this,a={},l=s;o.databound=n.ngModel,o.init=function(e,t,n){l=e,i=t,r=n},o.addOption=function(t,n){re(t,'"option value"'),a[t]=!0,l.$viewValue==t&&(e.val(t),r.parent()&&r.remove()),n&&n[0].hasAttribute("selected")&&(n[0].selected=!0)},o.removeOption=function(e){this.hasOption(e)&&(delete a[e],l.$viewValue==e&&this.renderUnknownOption(e))},o.renderUnknownOption=function(t){var n="? "+Ne(t)+" ?";r.val(n),e.prepend(r),e.val(n),r.prop("selected",!0)},o.hasOption=function(e){return a.hasOwnProperty(e)},t.$on("$destroy",function(){o.renderUnknownOption=h})}],link:function(s,l,c,u){if(u[1]){for(var d,f=u[0],p=u[1],h=c.multiple,g=c.ngOptions,m=!1,y=!1,b=Hn(t.createElement("option")),w=Hn(t.createElement("optgroup")),x=b.clone(),C=0,k=l.children(),S=k.length;C<S;C++)if(""===k[C].value){d=m=k.eq(C);break}f.init(p,m,x),h&&(p.$isEmpty=function(e){return!e||0===e.length}),g?function(t,s,l){function c(e,n,i){return L[T]=i,M&&(L[M]=n),e(t,L)}function u(){t.$apply(function(){var e,n=P(t)||[];if(h)e=[],o(s.val(),function(t){e.push(d(t,n[t]))});else{var i=s.val();e=d(i,n[i])}l.$setViewValue(e),k()})}function d(e,t){return"?"===e?n:""===e?null:c(A||I,e,t)}function p(){var e,n=P(t);if(n&&Zn(n)){e=new Array(n.length);for(var i=0,r=n.length;i<r;i++)e[i]=c(E,i,n[i]);return e}if(n){e={};for(var o in n)n.hasOwnProperty(o)&&(e[o]=c(E,o,n[o]))}return e}function v(e){var t;if(h)if(j&&Zn(e)){t=new je([]);for(var n=0;n<e.length;n++)t.put(c(j,null,e[n]),!0)
+}else t=new je(e);else j&&(e=c(j,null,e));return function(n,i){var r;return r=j||A||I,h?$(t.remove(c(r,n,i))):e==c(r,n,i)}}function x(){y||(t.$$postDigest(k),y=!0)}function C(e,t,n){e[t]=e[t]||0,e[t]+=n?1:-1}function k(){y=!1;var e,n,i,r,u,d,p,g,x,k,S,T,D,A,I,N,j={"":[]},L=[""],R=l.$viewValue,V=P(t)||[],H=M?a(V):V,q={},U=v(R),_=!1;for(T=0;k=H.length,T<k;T++)p=T,M&&(p=H[T],"$"===p.charAt(0))||(g=V[p],e=c(O,p,g)||"",(n=j[e])||(n=j[e]=[],L.push(e)),D=U(p,g),_=_||D,N=c(E,p,g),N=$(N)?N:"",n.push({id:M?H[T]:T,label:N,selected:D}));for(h||(m||null===R?j[""].unshift({id:"",label:"",selected:!_}):_||j[""].unshift({id:"?",label:"",selected:!0})),S=0,x=L.length;S<x;S++){for(e=L[S],n=j[e],F.length<=S?(r={element:w.clone().attr("label",e),label:n.label},u=[r],F.push(u),s.append(r.element)):(u=F[S],r=u[0],r.label!=e&&r.element.attr("label",r.label=e)),A=null,T=0,k=n.length;T<k;T++)i=n[T],(d=u[T+1])?(A=d.element,d.label!==i.label&&(C(q,d.label,!1),C(q,i.label,!0),A.text(d.label=i.label)),d.id!==i.id&&A.val(d.id=i.id),A[0].selected!==i.selected&&(A.prop("selected",d.selected=i.selected),Vn&&A.prop("selected",d.selected))):(""===i.id&&m?I=m:(I=b.clone()).val(i.id).prop("selected",i.selected).attr("selected",i.selected).text(i.label),u.push(d={element:I,label:i.label,id:i.id,selected:i.selected}),C(q,i.label,!0),A?A.after(I):r.element.append(I),A=I);for(T++;u.length>T;)i=u.pop(),C(q,i.label,!1),i.element.remove();o(q,function(e,t){e>0?f.addOption(t):e<0&&f.removeOption(t)})}for(;F.length>S;)F.pop()[0].element.remove()}var S;if(!(S=g.match(r)))throw ho("iexp","Expected expression in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '{0}'. Element: {1}",g,B(s));var E=i(S[2]||S[1]),T=S[4]||S[6],D=/ as /.test(S[0])&&S[1],A=D?i(D):null,M=S[5],O=i(S[3]||""),I=i(S[2]?S[1]:T),P=i(S[7]),N=S[8],j=N?i(S[8]):null,F=[[{element:s,label:""}]],L={};m&&(e(m)(t),m.removeClass("ng-scope"),m.remove()),s.empty(),s.on("change",u),l.$render=k,t.$watchCollection(P,x),t.$watchCollection(p,x),h&&t.$watchCollection(function(){return l.$modelValue},x)}(s,l,p):h?function(e,t,n){var i;n.$render=function(){var e=new je(n.$viewValue);o(t.find("option"),function(t){t.selected=$(e.get(t.value))})},e.$watch(function(){L(i,n.$viewValue)||(i=F(n.$viewValue),n.$render())}),t.on("change",function(){e.$apply(function(){var e=[];o(t.find("option"),function(t){t.selected&&e.push(t.value)}),n.$setViewValue(e)})})}(s,l,p):function(e,t,n,i){n.$render=function(){var e=n.$viewValue;i.hasOption(e)?(x.parent()&&x.remove(),t.val(e),""===e&&d.prop("selected",!0)):v(e)&&d?t.val(""):i.renderUnknownOption(e)},t.on("change",function(){e.$apply(function(){x.parent()&&x.remove(),n.$setViewValue(t.val())})})}(s,l,p,f)}}}}],vo=["$interpolate",function(e){var t={addOption:h,removeOption:h};return{restrict:"E",priority:100,compile:function(n,i){if(v(i.value)){var r=e(n.text(),!0);r||i.$set("value",n.text())}return function(e,n,i){var o=n.parent(),a=o.data("$selectController")||o.parent().data("$selectController");a&&a.databound||(a=t),r?e.$watch(r,function(e,t){i.$set("value",e),t!==e&&a.removeOption(t),a.addOption(e,n)}):a.addOption(i.value,n),n.on("$destroy",function(){a.removeOption(i.value)})}}}}],$o=m({restrict:"E",terminal:!1});if(e.angular.bootstrap)return void console.log("WARNING: Tried to load angular more than once.");!function(){var t;ni||(qn=e.jQuery,qn&&qn.fn.on?(Hn=qn,d(qn.fn,{scope:xi.scope,isolateScope:xi.isolateScope,controller:xi.controller,injector:xi.injector,inheritedData:xi.inheritedData}),t=qn.cleanData,qn.cleanData=function(e){var n;if(Xn)Xn=!1;else for(var i,r=0;null!=(i=e[r]);r++)(n=qn._data(i,"events"))&&n.$destroy&&qn(i).triggerHandler("$destroy");t(e)}):Hn=ge,Kn.element=Hn,ni=!0)}(),function(t){d(t,{bootstrap:J,copy:j,extend:d,equals:L,element:Hn,forEach:o,injector:Re,noop:h,bind:H,toJson:U,fromJson:_,identity:g,isUndefined:v,isDefined:$,isString:b,isFunction:C,isObject:y,isNumber:w,isElement:O,isArray:Zn,version:li,isDate:x,lowercase:Nn,uppercase:Fn,callbacks:{counter:0},getTestability:ee,$$minErr:i,$$csp:Qn,reloadWithDebugInfo:Q}),Un=le(e);try{Un("ngLocale")}catch(e){Un("ngLocale",[]).provider("$locale",lt)}Un("ng",["ngLocale"],["$provide",function(e){e.provider({$$sanitizeUri:Ft}),e.provider("$compile",We).directive({a:ar,input:Sr,textarea:Sr,form:dr,script:po,select:mo,style:$o,option:vo,ngBind:Ur,ngBindHtml:Br,ngBindTemplate:_r,ngClass:Wr,ngClassEven:Yr,ngClassOdd:zr,ngCloak:Kr,ngController:Gr,ngForm:fr,ngHide:ao,ngIf:Jr,ngInclude:Qr,ngInit:to,ngNonBindable:no,ngPluralize:io,ngRepeat:ro,ngShow:oo,ngStyle:so,ngSwitch:lo,ngSwitchWhen:co,ngSwitchDefault:uo,ngOptions:go,ngTransclude:fo,ngModel:Ir,ngList:Rr,ngChange:Pr,pattern:jr,ngPattern:jr,required:Nr,ngRequired:Nr,minlength:Lr,ngMinlength:Lr,maxlength:Fr,ngMaxlength:Fr,ngValue:Hr,ngModelOptions:qr}).directive({ngInclude:eo}).directive(sr).directive(Xr),e.provider({$anchorScroll:Ve,$animate:Ii,$browser:Ue,$cacheFactory:_e,$controller:Ge,$document:Xe,$exceptionHandler:Ze,$filter:Gt,$interpolate:at,$interval:st,$http:nt,$httpBackend:rt,$location:wt,$log:xt,$parse:Mt,$rootScope:jt,$q:Ot,$$q:It,$sce:qt,$sceDelegate:Ht,$sniffer:Ut,$templateCache:Be,$templateRequest:_t,$$testability:Bt,$timeout:Wt,$window:Kt,$$rAF:Nt,$$asyncCallback:He})}])}(Kn),Hn(t).ready(function(){Z(t,J)})}(window,document),!window.angular.$$csp()&&window.angular.element(document).find("head").prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}</style>'),function(e,t,n){"use strict";function i(){function e(e,n){return t.extend(new(t.extend(function(){},{prototype:e})),n)}function n(e,t){var n=t.caseInsensitiveMatch,i={originalPath:e,regexp:e},r=i.keys=[];return e=e.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(e,t,n,i){var o="?"===i?i:null,a="*"===i?i:null;return r.push({name:n,optional:!!o}),t=t||"",(o?"":t)+"(?:"+(o?t:"")+(a&&"(.+?)"||"([^/]+)")+(o||"")+")"+(o||"")}).replace(/([\/$\*])/g,"\\$1"),i.regexp=new RegExp("^"+e+"$",n?"i":""),i}var i={};this.when=function(e,r){if(i[e]=t.extend({reloadOnSearch:!0},r,e&&n(e,r)),e){var o="/"==e[e.length-1]?e.substr(0,e.length-1):e+"/";i[o]=t.extend({redirectTo:e},n(o,r))}return this},this.otherwise=function(e){return"string"==typeof e&&(e={redirectTo:e}),this.when(null,e),this},this.$get=["$rootScope","$location","$routeParams","$q","$injector","$templateRequest","$sce",function(n,r,o,a,s,c,u){function d(e,t){var n=t.keys,i={};if(!t.regexp)return null;var r=t.regexp.exec(e);if(!r)return null;for(var o=1,a=r.length;o<a;++o){var s=n[o-1],l=r[o];s&&l&&(i[s.name]=l)}return i}function f(e){var i=y.current;m=h(),(v=m&&i&&m.$$route===i.$$route&&t.equals(m.pathParams,i.pathParams)&&!m.reloadOnSearch&&!$)||!i&&!m||n.$broadcast("$routeChangeStart",m,i).defaultPrevented&&e&&e.preventDefault()}function p(){var e=y.current,i=m;v?(e.params=i.params,t.copy(e.params,o),n.$broadcast("$routeUpdate",e)):(i||e)&&($=!1,y.current=i,i&&i.redirectTo&&(t.isString(i.redirectTo)?r.path(g(i.redirectTo,i.params)).search(i.params).replace():r.url(i.redirectTo(i.pathParams,r.path(),r.search())).replace()),a.when(i).then(function(){if(i){var e,n,r=t.extend({},i.resolve);return t.forEach(r,function(e,n){r[n]=t.isString(e)?s.get(e):s.invoke(e,null,null,n)}),t.isDefined(e=i.template)?t.isFunction(e)&&(e=e(i.params)):t.isDefined(n=i.templateUrl)&&(t.isFunction(n)&&(n=n(i.params)),n=u.getTrustedResourceUrl(n),t.isDefined(n)&&(i.loadedTemplateUrl=n,e=c(n))),t.isDefined(e)&&(r.$template=e),a.all(r)}}).then(function(r){i==y.current&&(i&&(i.locals=r,t.copy(i.params,o)),n.$broadcast("$routeChangeSuccess",i,e))},function(t){i==y.current&&n.$broadcast("$routeChangeError",i,e,t)}))}function h(){var n,o;return t.forEach(i,function(i,a){!o&&(n=d(r.path(),i))&&(o=e(i,{params:t.extend({},r.search(),n),pathParams:n}),o.$$route=i)}),o||i[null]&&e(i[null],{params:{},pathParams:{}})}function g(e,n){var i=[];return t.forEach((e||"").split(":"),function(e,t){if(0===t)i.push(e);else{var r=e.match(/(\w+)(.*)/),o=r[1];i.push(n[o]),i.push(r[2]||""),delete n[o]}}),i.join("")}var m,v,$=!1,y={routes:i,reload:function(){$=!0,n.$evalAsync(function(){f(),p()})},updateParams:function(e){if(!this.current||!this.current.$$route)throw l("norout","Tried updating route when with no current route");var n={},i=this;t.forEach(Object.keys(e),function(t){i.current.pathParams[t]||(n[t]=e[t])}),e=t.extend({},this.current.params,e),r.path(g(this.current.$$route.originalPath,e)),r.search(t.extend({},r.search(),n))}};return n.$on("$locationChangeStart",f),n.$on("$locationChangeSuccess",p),y}]}function r(){this.$get=function(){return{}}}function o(e,n,i){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(r,o,a,s,l){function c(){p&&(i.cancel(p),p=null),d&&(d.$destroy(),d=null),f&&(p=i.leave(f),p.then(function(){p=null}),f=null)}function u(){var a=e.current&&e.current.locals,s=a&&a.$template;if(t.isDefined(s)){var u=r.$new(),p=e.current,m=l(u,function(e){i.enter(e,null,f||o).then(function(){!t.isDefined(h)||h&&!r.$eval(h)||n()}),c()});f=m,d=p.scope=u,d.$emit("$viewContentLoaded"),d.$eval(g)}else c()}var d,f,p,h=a.autoscroll,g=a.onload||"";r.$on("$routeChangeSuccess",u),u()}}}function a(e,t,n){return{restrict:"ECA",priority:-400,link:function(i,r){var o=n.current,a=o.locals;r.html(a.$template);var s=e(r.contents());if(o.controller){a.$scope=i;var l=t(o.controller,a);o.controllerAs&&(i[o.controllerAs]=l),r.data("$ngControllerController",l),r.children().data("$ngControllerController",l)}s(i)}}}var s=t.module("ngRoute",["ng"]).provider("$route",i),l=t.$$minErr("ngRoute");s.provider("$routeParams",r),s.directive("ngView",o),s.directive("ngView",a),o.$inject=["$route","$anchorScroll","$animate"],a.$inject=["$compile","$controller","$route"]}(window,window.angular),function(e,t,n){"use strict";function i(e){return null!=e&&""!==e&&"hasOwnProperty"!==e&&s.test("."+e)}function r(e,t){if(!i(t))throw a("badmember",'Dotted member path "@{0}" is invalid.',t);for(var r=t.split("."),o=0,s=r.length;o<s&&e!==n;o++){var l=r[o];e=null!==e?e[l]:n}return e}function o(e,n){n=n||{},t.forEach(n,function(e,t){delete n[t]});for(var i in e)!e.hasOwnProperty(i)||"$"===i.charAt(0)&&"$"===i.charAt(1)||(n[i]=e[i]);return n}var a=t.$$minErr("$resource"),s=/^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;t.module("ngResource",["ng"]).provider("$resource",function(){var e=this;this.defaults={stripTrailingSlashes:!0,actions:{get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},delete:{method:"DELETE"}}},this.$get=["$http","$q",function(i,s){function l(e){return c(e,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function c(e,t){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,t?"%20":"+")}function u(t,n){this.template=t,this.defaults=h({},e.defaults,n),this.urlParams={}}function d(l,c,v,$){function y(e,t){var n={};return t=h({},c,t),p(t,function(t,i){m(t)&&(t=t()),n[i]=t&&t.charAt&&"@"==t.charAt(0)?r(e,t.substr(1)):t}),n}function b(e){return e.resource}function w(e){o(e||{},this)}var x=new u(l,$);return v=h({},e.defaults.actions,v),w.prototype.toJSON=function(){var e=h({},this);return delete e.$promise,delete e.$resolved,e},p(v,function(e,r){var l=/^(POST|PUT|PATCH)$/i.test(e.method);w[r]=function(c,u,d,v){var $,C,k,S={};switch(arguments.length){case 4:k=v,C=d;case 3:case 2:if(!m(u)){S=c,$=u,C=d;break}if(m(c)){C=c,k=u;break}C=u,k=d;case 1:m(c)?C=c:l?$=c:S=c;break;case 0:break;default:throw a("badargs","Expected up to 4 arguments [params, data, success, error], got {0} arguments",arguments.length)}var E=this instanceof w,T=E?$:e.isArray?[]:new w($),D={},A=e.interceptor&&e.interceptor.response||b,M=e.interceptor&&e.interceptor.responseError||n;p(e,function(e,t){"params"!=t&&"isArray"!=t&&"interceptor"!=t&&(D[t]=g(e))}),l&&(D.data=$),x.setUrlParams(D,h({},y($,e.params||{}),S),e.url);var O=i(D).then(function(n){var i=n.data,s=T.$promise;if(i){if(t.isArray(i)!==!!e.isArray)throw a("badcfg","Error in resource configuration for action `{0}`. Expected response to contain an {1} but got an {2}",r,e.isArray?"array":"object",t.isArray(i)?"array":"object");e.isArray?(T.length=0,p(i,function(e){"object"==typeof e?T.push(new w(e)):T.push(e)})):(o(i,T),T.$promise=s)}return T.$resolved=!0,n.resource=T,n},function(e){return T.$resolved=!0,(k||f)(e),s.reject(e)});return O=O.then(function(e){var t=A(e);return(C||f)(t,e.headers),t},M),E?O:(T.$promise=O,T.$resolved=!1,T)},w.prototype["$"+r]=function(e,t,n){m(e)&&(n=t,t=e,e={});var i=w[r].call(this,e,this,t,n);return i.$promise||i}}),w.bind=function(e){return d(l,h({},c,e),v)},w}var f=t.noop,p=t.forEach,h=t.extend,g=t.copy,m=t.isFunction;return u.prototype={setUrlParams:function(e,n,i){var r,o,s=this,c=i||s.template,u=s.urlParams={};p(c.split(/\W/),function(e){if("hasOwnProperty"===e)throw a("badname","hasOwnProperty is not a valid parameter name.");!new RegExp("^\\d+$").test(e)&&e&&new RegExp("(^|[^\\\\]):"+e+"(\\W|$)").test(c)&&(u[e]=!0)}),c=c.replace(/\\:/g,":"),n=n||{},p(s.urlParams,function(e,i){r=n.hasOwnProperty(i)?n[i]:s.defaults[i],t.isDefined(r)&&null!==r?(o=l(r),c=c.replace(new RegExp(":"+i+"(\\W|$)","g"),function(e,t){return o+t})):c=c.replace(new RegExp("(/?):"+i+"(\\W|$)","g"),function(e,t,n){return"/"==n.charAt(0)?n:t+n})}),s.defaults.stripTrailingSlashes&&(c=c.replace(/\/+$/,"")||"/"),c=c.replace(/\/\.(?=\w+($|\?))/,"."),e.url=c.replace(/\/\\\./,"/."),p(n,function(t,n){s.urlParams[n]||(e.params=e.params||{},e.params[n]=t)})}},d}]})}(window,window.angular),function(e,t,n){"use strict";t.module("ngCookies",["ng"]).factory("$cookies",["$rootScope","$browser",function(e,i){function r(){var e,r,o,l;for(e in s)u(a[e])&&i.cookies(e,n);for(e in a)r=a[e],t.isString(r)||(r=""+r,a[e]=r),r!==s[e]&&(i.cookies(e,r),l=!0);if(l){l=!1,o=i.cookies();for(e in a)a[e]!==o[e]&&(u(o[e])?delete a[e]:a[e]=o[e],l=!0)}}var o,a={},s={},l=!1,c=t.copy,u=t.isUndefined;return i.addPollFn(function(){var t=i.cookies();o!=t&&(o=t,c(t,s),c(t,a),l&&e.$apply())})(),l=!0,e.$watch(r),a}]).factory("$cookieStore",["$cookies",function(e){return{get:function(n){var i=e[n];return i?t.fromJson(i):i},put:function(n,i){e[n]=t.toJson(i)},remove:function(t){delete e[t]}}}])}(window,window.angular),function(e,t,n){"use strict";t.module("ngAnimate",["ng"]).directive("ngAnimateChildren",function(){return function(e,n,i){var r=i.ngAnimateChildren;t.isString(r)&&0===r.length?n.data("$$ngAnimateChildren",!0):e.$watch(r,function(e){n.data("$$ngAnimateChildren",!!e)})}}).factory("$$animateReflow",["$$rAF","$document",function(e,t){var n=t[0].body;return function(t){return e(function(){n.offsetWidth;t()})}}]).config(["$provide","$animateProvider",function(n,i){function r(e){for(var t=0;t<e.length;t++){var n=e[t];if(n.nodeType==h)return n}}function o(e){return e&&t.element(e)}function a(e){return t.element(r(e))}function s(e,t){return r(e)==r(t)}var l=t.noop,c=t.forEach,u=i.$$selectors,d=t.isArray,f=t.isString,p=t.isObject,h=1,g="$$ngAnimateState",m="ng-animate",v={running:!0};n.decorator("$animate",["$delegate","$$q","$injector","$sniffer","$rootElement","$$asyncCallback","$rootScope","$document","$templateRequest",function(e,n,h,$,y,b,w,x,C){function k(e,t){var n=e.data(g)||{};return t&&(n.running=!0,n.structural=!0,e.data(g,n)),n.disabled||n.running&&n.structural}function S(e){var t,i=n.defer();return i.promise.$$cancelFn=function(){t&&t()},w.$$postDigest(function(){t=e(function(){i.resolve()})}),i.promise}function E(e){if(p(e))return e.tempClasses&&f(e.tempClasses)&&(e.tempClasses=e.tempClasses.split(/\s+/)),e}function T(e,t,n){n=n||{};var i={};c(n,function(e,t){c(t.split(" "),function(t){i[t]=e})});var r=Object.create(null);c((e.attr("class")||"").split(/\s+/),function(e){r[e]=!0});var o=[],a=[];return c(t.classes,function(e,t){var n=r[t],s=i[t]||{};!1===e?(n||"addClass"==s.event)&&a.push(t):!0===e&&(n&&"removeClass"!=s.event||o.push(t))}),o.length+a.length>0&&[o.join(" "),a.join(" ")]}function D(e){if(e){var t=[],n={},i=e.substr(1).split(".");($.transitions||$.animations)&&t.push(h.get(u[""]));for(var r=0;r<i.length;r++){var o=i[r],a=u[o];a&&!n[o]&&(t.push(h.get(a)),n[o]=!0)}return t}}function A(e,n,i,r){function o(e,t){var n=e[t],i=e["before"+t.charAt(0).toUpperCase()+t.substr(1)];if(n||i)return"leave"==t&&(i=n,n=null),x.push({event:t,fn:n}),y.push({event:t,fn:i}),!0}function a(t,n,o){function a(e){if(n){if((n[e]||l)(),++d<s.length)return;n=null}o()}var s=[];c(t,function(e){e.fn&&s.push(e)});var d=0;c(s,function(t,o){var s=function(){a(o)};switch(t.event){case"setClass":n.push(t.fn(e,u,f,s,r));break;case"animate":n.push(t.fn(e,i,r.from,r.to,s));break;case"addClass":n.push(t.fn(e,u||i,s,r));break;case"removeClass":n.push(t.fn(e,f||i,s,r));break;default:n.push(t.fn(e,s,r))}}),n&&0===n.length&&o()}var s=e[0];if(s){r&&(r.to=r.to||{},r.from=r.from||{});var u,f;d(i)&&(u=i[0],f=i[1],u?f?i=u+" "+f:(i=u,n="addClass"):(i=f,n="removeClass"));var p="setClass"==n,h=p||"addClass"==n||"removeClass"==n||"animate"==n,g=e.attr("class"),m=g+" "+i;if(L(m)){var v=l,$=[],y=[],b=l,w=[],x=[],C=(" "+m).replace(/\s+/g,".");return c(D(C),function(e){!o(e,n)&&p&&(o(e,"addClass"),o(e,"removeClass"))}),{node:s,event:n,className:i,isClassBased:h,isSetClassOperation:p,applyStyles:function(){r&&e.css(t.extend(r.from||{},r.to||{}))},before:function(e){v=e,a(y,$,function(){v=l,e()})},after:function(e){b=e,a(x,w,function(){b=l,e()})},cancel:function(){$&&(c($,function(e){(e||l)(!0)}),v(!0)),w&&(c(w,function(e){(e||l)(!0)}),b(!0))}}}}}function M(e,n,i,r,o,a,s,u){function d(t){var r="$animate:"+t;x&&x[r]&&x[r].length>0&&b(function(){i.triggerHandler(r,{event:e,className:n})})}function f(){d("before")}function p(){d("after")}function h(){d("close"),u()}function v(){v.hasBeenRun||(v.hasBeenRun=!0,a())}function $(){if(!$.hasBeenRun){w&&w.applyStyles(),$.hasBeenRun=!0,s&&s.tempClasses&&c(s.tempClasses,function(e){i.removeClass(e)});var e=i.data(g);e&&(w&&w.isClassBased?I(i,n):(b(function(){var e=i.data(g)||{};N==e.index&&I(i,n)}),i.data(g,e))),h()}}var y=l,w=A(i,e,n,s);if(!w)return v(),f(),p(),$(),y;e=w.event,n=w.className;var x=t.element._data(w.node);if(x=x&&x.events,r||(r=o?o.parent():i.parent()),P(i,r))return v(),f(),p(),$(),y;var C=i.data(g)||{},k=C.active||{},S=C.totalActive||0,E=C.last,T=!1;if(S>0){var D=[];if(w.isClassBased){if("setClass"==E.event)D.push(E),I(i,n);else if(k[n]){var M=k[n];M.event==e?T=!0:(D.push(M),I(i,n))}}else if("leave"==e&&k["ng-leave"])T=!0;else{for(var O in k)D.push(k[O]);C={},I(i,!0)}D.length>0&&c(D,function(e){e.cancel()})}if(!w.isClassBased||w.isSetClassOperation||"animate"==e||T||(T="addClass"==e==i.hasClass(n)),T)return v(),f(),p(),h(),y;k=C.active||{},S=C.totalActive||0,"leave"==e&&i.one("$destroy",function(e){var n=t.element(this),i=n.data(g);if(i){var r=i.active["ng-leave"];r&&(r.cancel(),I(n,"ng-leave"))}}),i.addClass(m),s&&s.tempClasses&&c(s.tempClasses,function(e){i.addClass(e)});var N=j++;return S++,k[n]=w,i.data(g,{last:w,active:k,index:N,totalActive:S}),f(),w.before(function(t){var r=i.data(g);t=t||!r||!r.active[n]||w.isClassBased&&r.active[n].event!=e,v(),!0===t?$():(p(),w.after($))}),w.cancel}function O(e){var n=r(e);if(n){var i=t.isFunction(n.getElementsByClassName)?n.getElementsByClassName(m):n.querySelectorAll("."+m);c(i,function(e){e=t.element(e);var n=e.data(g);n&&n.active&&c(n.active,function(e){e.cancel()})})}}function I(e,t){if(s(e,y))v.disabled||(v.running=!1,v.structural=!1);else if(t){var n=e.data(g)||{},i=!0===t;!i&&n.active&&n.active[t]&&(n.totalActive--,delete n.active[t]),!i&&n.totalActive||(e.removeClass(m),e.removeData(g))}}function P(e,n){if(v.disabled)return!0;if(s(e,y))return v.running;var i,r,o;do{if(0===n.length)break;var a=s(n,y),l=a?v:n.data(g)||{};if(l.disabled)return!0;if(a&&(o=!0),!1!==i){var c=n.data("$$ngAnimateChildren");t.isDefined(c)&&(i=c)}r=r||l.running||l.last&&!l.last.isClassBased}while(n=n.parent());return!o||!i&&r}y.data(g,v);var N=w.$watch(function(){return C.totalPendingRequests},function(e,t){0===e&&(N(),w.$$postDigest(function(){w.$$postDigest(function(){v.running=!1})}))}),j=0,F=i.classNameFilter(),L=F?function(e){return F.test(e)}:function(){return!0};return{animate:function(e,t,n,i,r){return i=i||"ng-inline-animate",r=E(r)||{},r.from=n?t:null,r.to=n||t,S(function(t){return M("animate",i,a(e),null,null,l,r,t)})},enter:function(n,i,r,s){return s=E(s),n=t.element(n),i=o(i),r=o(r),k(n,!0),e.enter(n,i,r),S(function(e){return M("enter","ng-enter",a(n),i,r,l,s,e)})},leave:function(n,i){return i=E(i),n=t.element(n),O(n),k(n,!0),S(function(t){return M("leave","ng-leave",a(n),null,null,function(){e.leave(n)},i,t)})},move:function(n,i,r,s){return s=E(s),n=t.element(n),i=o(i),r=o(r),O(n),k(n,!0),e.move(n,i,r),S(function(e){return M("move","ng-move",a(n),i,r,l,s,e)})},addClass:function(e,t,n){return this.setClass(e,t,[],n)},removeClass:function(e,t,n){return this.setClass(e,[],t,n)},setClass:function(n,i,o,s){if(s=E(s),n=t.element(n),n=a(n),k(n))return e.$$setClassImmediately(n,i,o,s);var l,u=n.data("$$animateClasses"),f=!!u;return u||(u={},u.classes={}),l=u.classes,i=d(i)?i:i.split(" "),c(i,function(e){e&&e.length&&(l[e]=!0)}),o=d(o)?o:o.split(" "),c(o,function(e){e&&e.length&&(l[e]=!1)}),f?(s&&u.options&&(u.options=t.extend(u.options||{},s)),u.promise):(n.data("$$animateClasses",u={classes:l,options:s}),u.promise=S(function(t){var i=n.parent(),o=r(n),a=o.parentNode;if(!a||a.$$NG_REMOVED||o.$$NG_REMOVED)return void t();var s=n.data("$$animateClasses");n.removeData("$$animateClasses");var l=n.data(g)||{},c=T(n,s,l.active);return c?M("setClass",c,n,i,null,function(){c[0]&&e.$$addClassImmediately(n,c[0]),c[1]&&e.$$removeClassImmediately(n,c[1])},s.options,t):t()}))},cancel:function(e){e.$$cancelFn()},enabled:function(e,t){switch(arguments.length){case 2:if(e)I(t);else{var n=t.data(g)||{};n.disabled=!0,t.data(g,n)}break;case 1:v.disabled=!e;break;default:e=!v.disabled}return!!e}}}]),i.register("",["$window","$sniffer","$timeout","$$animateReflow",function(n,i,o,a){function s(){P||(P=a(function(){z=[],P=null,B={}}))}function u(e,t){P&&P(),z.push(t),P=a(function(){c(z,function(e){e()}),z=[],P=null,B={}})}function p(e,n){var i=r(e);e=t.element(i),G.push(e);var a=Date.now()+n;a<=K||(o.cancel(Y),K=a,Y=o(function(){g(G),G=[]},n,!1))}function g(e){c(e,function(e){var t=e.data(H);t&&c(t.closeAnimationFns,function(e){e()})})}function m(e,t){var i=t?B[t]:null;if(!i){var r=0,o=0,a=0,s=0;c(e,function(e){if(e.nodeType==h){var t=n.getComputedStyle(e)||{},i=t[D+N];r=Math.max(v(i),r);var l=t[D+F];o=Math.max(v(l),o),s=Math.max(v(t[M+F]),s);var c=v(t[M+N]);c>0&&(c*=parseInt(t[M+L],10)||1),a=Math.max(c,a)}}),i={total:0,transitionDelay:o,transitionDuration:r,animationDelay:s,animationDuration:a},t&&(B[t]=i)}return i}function v(e){var t=0,n=f(e)?e.split(/\s*,\s*/):[];return c(n,function(e){t=Math.max(parseFloat(e)||0,t)}),t}function $(e){var t=e.parent(),n=t.data(V);return n||(t.data(V,++W),n=W),n+"-"+r(e).getAttribute("class")}function y(e,t,n,i){var o=["ng-enter","ng-leave","ng-move"].indexOf(n)>=0,a=$(t),s=a+" "+n,l=B[s]?++B[s].total:0,c={};if(l>0){var u=n+"-stagger",d=a+" "+u,f=!B[d];f&&t.addClass(u),c=m(t,d),f&&t.removeClass(u)}t.addClass(n);var p=t.data(H)||{},h=m(t,s),g=h.transitionDuration,v=h.animationDuration;if(o&&0===g&&0===v)return t.removeClass(n),!1;var y=i||o&&g>0,b=v>0&&c.animationDelay>0&&0===c.animationDuration,C=p.closeAnimationFns||[];t.data(H,{stagger:c,cacheKey:s,running:p.running||0,itemIndex:l,blockTransition:y,closeAnimationFns:C});var k=r(t);return y&&(w(k,!0),i&&t.css(i)),b&&x(k,!0),!0}function b(e,t,n,i,a){function s(){t.off(F,l),t.removeClass(f),t.removeClass(h),N&&o.cancel(N),E(t,n);var e=r(t);for(var i in g)e.style.removeProperty(g[i])}function l(e){e.stopPropagation();var t=e.originalEvent||e,n=t.$manualTimeStamp||t.timeStamp||Date.now(),r=parseFloat(t.elapsedTime.toFixed(q));Math.max(n-j,0)>=M&&r>=T&&i()}var u=r(t),d=t.data(H);if(-1==u.getAttribute("class").indexOf(n)||!d)return void i();var f="",h="";c(n.split(" "),function(e,t){var n=(t>0?" ":"")+e;f+=n+"-active",h+=n+"-pending"});var g=[],v=d.itemIndex,$=d.stagger,y=0;if(v>0){var b=0;$.transitionDelay>0&&0===$.transitionDuration&&(b=$.transitionDelay*v);var C=0;$.animationDelay>0&&0===$.animationDuration&&(C=$.animationDelay*v,g.push(I+"animation-play-state")),y=Math.round(100*Math.max(b,C))/100}y||(t.addClass(f),d.blockTransition&&w(u,!1));var k=d.cacheKey+" "+f,S=m(t,k),T=Math.max(S.transitionDuration,S.animationDuration);if(0===T)return t.removeClass(f),E(t,n),void i();!y&&a&&(S.transitionDuration||(t.css("transition",S.animationDuration+"s linear all"),g.push("transition")),t.css(a));var D=Math.max(S.transitionDelay,S.animationDelay),M=D*_;if(g.length>0){var P=u.getAttribute("style")||"";";"!==P.charAt(P.length-1)&&(P+=";"),u.setAttribute("style",P+" ")}var N,j=Date.now(),F=O+" "+A,L=(D+T)*U,R=(y+L)*_;return y>0&&(t.addClass(h),N=o(function(){N=null,S.transitionDuration>0&&w(u,!1),S.animationDuration>0&&x(u,!1),t.addClass(f),t.removeClass(h),a&&(0===S.transitionDuration&&t.css("transition",S.animationDuration+"s linear all"),t.css(a),g.push("transition"))},y*_,!1)),t.on(F,l),d.closeAnimationFns.push(function(){s(),i()}),d.running++,p(t,R),s}function w(e,t){e.style[D+j]=t?"none":""}function x(e,t){e.style[M+R]=t?"paused":""}function C(e,t,n,i){if(y(e,t,n,i))return function(e){e&&E(t,n)}}function k(e,t,n,i,r){if(t.data(H))return b(e,t,n,i,r);E(t,n),i()}function S(e,t,n,i,r){var o=C(e,t,n,r.from);if(!o)return s(),void i();var a=o;return u(t,function(){a=k(e,t,n,i,r.to)}),function(e){(a||l)(e)}}function E(e,t){e.removeClass(t);var n=e.data(H);n&&(n.running&&n.running--,n.running&&0!==n.running||e.removeData(H))}function T(e,t){var n="";return e=d(e)?e:e.split(/\s+/),c(e,function(e,i){e&&e.length>0&&(n+=(i>0?" ":"")+e+t)}),n}var D,A,M,O,I="";void 0===e.ontransitionend&&void 0!==e.onwebkittransitionend?(I="-webkit-",D="WebkitTransition",A="webkitTransitionEnd transitionend"):(D="transition",A="transitionend"),void 0===e.onanimationend&&void 0!==e.onwebkitanimationend?(I="-webkit-",M="WebkitAnimation",O="webkitAnimationEnd animationend"):(M="animation",O="animationend");var P,N="Duration",j="Property",F="Delay",L="IterationCount",R="PlayState",V="$$ngAnimateKey",H="$$ngAnimateCSS3Data",q=3,U=1.5,_=1e3,B={},W=0,z=[],Y=null,K=0,G=[];return{animate:function(e,t,n,i,r,o){return o=o||{},o.from=n,o.to=i,S("animate",e,t,r,o)},enter:function(e,t,n){return n=n||{},S("enter",e,"ng-enter",t,n)},leave:function(e,t,n){return n=n||{},S("leave",e,"ng-leave",t,n)},move:function(e,t,n){return n=n||{},S("move",e,"ng-move",t,n)},beforeSetClass:function(e,t,n,i,r){r=r||{};var o=T(n,"-remove")+" "+T(t,"-add"),a=C("setClass",e,o,r.from);if(a)return u(e,i),a;s(),i()},beforeAddClass:function(e,t,n,i){i=i||{};var r=C("addClass",e,T(t,"-add"),i.from);if(r)return u(e,n),r;s(),n()},beforeRemoveClass:function(e,t,n,i){i=i||{};var r=C("removeClass",e,T(t,"-remove"),i.from);if(r)return u(e,n),r;s(),n()},setClass:function(e,t,n,i,r){return r=r||{},n=T(n,"-remove"),t=T(t,"-add"),k("setClass",e,n+" "+t,i,r.to)},addClass:function(e,t,n,i){return i=i||{},k("addClass",e,T(t,"-add"),n,i.to)},removeClass:function(e,t,n,i){return i=i||{},k("removeClass",e,T(t,"-remove"),n,i.to)}}}])}])}(window,window.angular),function(e,t,n){"use strict";function i(){return["$animate",function(e){return{restrict:"AE",transclude:"element",priority:1,terminal:!0,require:"^^ngMessages",link:function(t,n,i,o,a){var s,l=n[0],c=i.ngMessage||i.when;i=i.ngMessageExp||i.whenExp;var u=function(e){s=e?r(e)?e:e.split(/[\s,]+/):null,o.reRender()};i?(u(t.$eval(i)),t.$watchCollection(i,u)):u(c);var d,f;o.register(l,f={test:function(e){var t=s;return e=t?r(t)?0<=t.indexOf(e):t.hasOwnProperty(e):void 0},attach:function(){d||a(t,function(t){e.enter(t,null,n),d=t;var i=d.$$attachId=o.getAttachId();d.on("$destroy",function(){d&&d.$$attachId===i&&(o.deregister(l),f.detach())})})},detach:function(){if(d){var t=d;d=null,e.leave(t)}}})}}}]}var r=t.isArray,o=t.forEach,a=t.isString,s=t.element;t.module("ngMessages",[]).directive("ngMessages",["$animate",function(e){function t(e,t){return a(t)&&0===t.length||n(e.$eval(t))}function n(e){return a(e)?e.length:!!e}return{require:"ngMessages",restrict:"AE",controller:["$element","$scope","$attrs",function(i,r,a){function s(e,t){for(var n=t,i=[];n&&n!==e;){var r=n.$$ngMessageNode;if(r&&r.length)return p[r];n.childNodes.length&&-1==i.indexOf(n)?(i.push(n),n=n.childNodes[n.childNodes.length-1]):n=n.previousSibling||n.parentNode}}var l=this,c=0,u=0;this.getAttachId=function(){return u++};var d,f,p=this.messages={};this.render=function(s){s=s||{},d=!1,f=s;for(var c=t(r,a.ngMessagesMultiple)||t(r,a.multiple),u=[],p={},h=l.head,g=!1,m=0;null!=h;){m++;var v=h.message,$=!1;g||o(s,function(e,t){!$&&n(e)&&v.test(t)&&!p[t]&&($=p[t]=!0,v.attach())}),$?g=!c:u.push(v),h=h.next}o(u,function(e){e.detach()}),u.length!==m?e.setClass(i,"ng-active","ng-inactive"):e.setClass(i,"ng-inactive","ng-active")},r.$watchCollection(a.ngMessages||a.for,l.render),this.reRender=function(){d||(d=!0,r.$evalAsync(function(){d&&f&&l.render(f)}))},this.register=function(e,t){var n=c.toString();p[n]={message:t};var r=i[0],o=p[n];l.head?(r=s(r,e))?(o.next=r.next,r.next=o):(o.next=l.head,l.head=o):l.head=o,e.$$ngMessageNode=n,c++,l.reRender()},this.deregister=function(e){var t=e.$$ngMessageNode;delete e.$$ngMessageNode;var n=p[t];(e=s(i[0],e))?e.next=n.next:l.head=n.next,delete p[t],l.reRender()}}]}}]).directive("ngMessagesInclude",["$templateRequest","$document","$compile",function(e,t,n){return{restrict:"AE",require:"^^ngMessages",link:function(i,r,o){var a=o.ngMessagesInclude||o.src;e(a).then(function(e){n(e)(i,function(e){r.after(e),e=s(t[0].createComment(" ngMessagesInclude: "+a+" ")),r.after(e),r.remove()})})}}}]).directive("ngMessage",i()).directive("ngMessageExp",i())}(window,window.angular),angular.module("ui.bootstrap",["ui.bootstrap.tpls","ui.bootstrap.transition","ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.bindHtml","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.dateparser","ui.bootstrap.position","ui.bootstrap.datepicker","ui.bootstrap.dropdown","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.typeahead"]),angular.module("ui.bootstrap.tpls",["template/accordion/accordion-group.html","template/accordion/accordion.html","template/alert/alert.html","template/carousel/carousel.html","template/carousel/slide.html","template/datepicker/datepicker.html","template/datepicker/day.html","template/datepicker/month.html","template/datepicker/popup.html","template/datepicker/year.html","template/modal/backdrop.html","template/modal/window.html","template/pagination/pager.html","template/pagination/pagination.html","template/tooltip/tooltip-html-unsafe-popup.html","template/tooltip/tooltip-popup.html","template/popover/popover.html","template/progressbar/bar.html","template/progressbar/progress.html","template/progressbar/progressbar.html","template/rating/rating.html","template/tabs/tab.html","template/tabs/tabset.html","template/timepicker/timepicker.html","template/typeahead/typeahead-match.html","template/typeahead/typeahead-popup.html"]),angular.module("ui.bootstrap.transition",[]).factory("$transition",["$q","$timeout","$rootScope",function(e,t,n){function i(e){for(var t in e)if(void 0!==o.style[t])return e[t]}var r=function(i,o,a){a=a||{};var s=e.defer(),l=r[a.animation?"animationEndEventName":"transitionEndEventName"],c=function(e){n.$apply(function(){i.unbind(l,c),s.resolve(i)})};return l&&i.bind(l,c),t(function(){angular.isString(o)?i.addClass(o):angular.isFunction(o)?o(i):angular.isObject(o)&&i.css(o),
+l||s.resolve(i)}),s.promise.cancel=function(){l&&i.unbind(l,c),s.reject("Transition cancelled")},s.promise},o=document.createElement("trans"),a={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",transition:"transitionend"},s={WebkitTransition:"webkitAnimationEnd",MozTransition:"animationend",OTransition:"oAnimationEnd",transition:"animationend"};return r.transitionEndEventName=i(a),r.animationEndEventName=i(s),r}]),angular.module("ui.bootstrap.collapse",["ui.bootstrap.transition"]).directive("collapse",["$transition",function(e){return{link:function(t,n,i){function r(t){function i(){c===r&&(c=void 0)}var r=e(n,t);return c&&c.cancel(),c=r,r.then(i,i),r}function o(){u?(u=!1,a()):(n.removeClass("collapse").addClass("collapsing"),r({height:n[0].scrollHeight+"px"}).then(a))}function a(){n.removeClass("collapsing"),n.addClass("collapse in"),n.css({height:"auto"})}function s(){if(u)u=!1,l(),n.css({height:0});else{n.css({height:n[0].scrollHeight+"px"});n[0].offsetWidth;n.removeClass("collapse in").addClass("collapsing"),r({height:0}).then(l)}}function l(){n.removeClass("collapsing"),n.addClass("collapse")}var c,u=!0;t.$watch(i.collapse,function(e){e?s():o()})}}}]),angular.module("ui.bootstrap.accordion",["ui.bootstrap.collapse"]).constant("accordionConfig",{closeOthers:!0}).controller("AccordionController",["$scope","$attrs","accordionConfig",function(e,t,n){this.groups=[],this.closeOthers=function(i){(angular.isDefined(t.closeOthers)?e.$eval(t.closeOthers):n.closeOthers)&&angular.forEach(this.groups,function(e){e!==i&&(e.isOpen=!1)})},this.addGroup=function(e){var t=this;this.groups.push(e),e.$on("$destroy",function(n){t.removeGroup(e)})},this.removeGroup=function(e){var t=this.groups.indexOf(e);-1!==t&&this.groups.splice(t,1)}}]).directive("accordion",function(){return{restrict:"EA",controller:"AccordionController",transclude:!0,replace:!1,templateUrl:"template/accordion/accordion.html"}}).directive("accordionGroup",function(){return{require:"^accordion",restrict:"EA",transclude:!0,replace:!0,templateUrl:"template/accordion/accordion-group.html",scope:{heading:"@",isOpen:"=?",isDisabled:"=?"},controller:function(){this.setHeading=function(e){this.heading=e}},link:function(e,t,n,i){i.addGroup(e),e.$watch("isOpen",function(t){t&&i.closeOthers(e)}),e.toggleOpen=function(){e.isDisabled||(e.isOpen=!e.isOpen)}}}}).directive("accordionHeading",function(){return{restrict:"EA",transclude:!0,template:"",replace:!0,require:"^accordionGroup",link:function(e,t,n,i,r){i.setHeading(r(e,function(){}))}}}).directive("accordionTransclude",function(){return{require:"^accordionGroup",link:function(e,t,n,i){e.$watch(function(){return i[n.accordionTransclude]},function(e){e&&(t.html(""),t.append(e))})}}}),angular.module("ui.bootstrap.alert",[]).controller("AlertController",["$scope","$attrs",function(e,t){e.closeable="close"in t,this.close=e.close}]).directive("alert",function(){return{restrict:"EA",controller:"AlertController",templateUrl:"template/alert/alert.html",transclude:!0,replace:!0,scope:{type:"@",close:"&"}}}).directive("dismissOnTimeout",["$timeout",function(e){return{require:"alert",link:function(t,n,i,r){e(function(){r.close()},parseInt(i.dismissOnTimeout,10))}}}]),angular.module("ui.bootstrap.bindHtml",[]).directive("bindHtmlUnsafe",function(){return function(e,t,n){t.addClass("ng-binding").data("$binding",n.bindHtmlUnsafe),e.$watch(n.bindHtmlUnsafe,function(e){t.html(e||"")})}}),angular.module("ui.bootstrap.buttons",[]).constant("buttonConfig",{activeClass:"active",toggleEvent:"click"}).controller("ButtonsController",["buttonConfig",function(e){this.activeClass=e.activeClass||"active",this.toggleEvent=e.toggleEvent||"click"}]).directive("btnRadio",function(){return{require:["btnRadio","ngModel"],controller:"ButtonsController",link:function(e,t,n,i){var r=i[0],o=i[1];o.$render=function(){t.toggleClass(r.activeClass,angular.equals(o.$modelValue,e.$eval(n.btnRadio)))},t.bind(r.toggleEvent,function(){var i=t.hasClass(r.activeClass);i&&!angular.isDefined(n.uncheckable)||e.$apply(function(){o.$setViewValue(i?null:e.$eval(n.btnRadio)),o.$render()})})}}}).directive("btnCheckbox",function(){return{require:["btnCheckbox","ngModel"],controller:"ButtonsController",link:function(e,t,n,i){function r(){return a(n.btnCheckboxTrue,!0)}function o(){return a(n.btnCheckboxFalse,!1)}function a(t,n){var i=e.$eval(t);return angular.isDefined(i)?i:n}var s=i[0],l=i[1];l.$render=function(){t.toggleClass(s.activeClass,angular.equals(l.$modelValue,r()))},t.bind(s.toggleEvent,function(){e.$apply(function(){l.$setViewValue(t.hasClass(s.activeClass)?o():r()),l.$render()})})}}}),angular.module("ui.bootstrap.carousel",["ui.bootstrap.transition"]).controller("CarouselController",["$scope","$timeout","$interval","$transition",function(e,t,n,i){function r(){o();var t=+e.interval;!isNaN(t)&&t>0&&(s=n(a,t))}function o(){s&&(n.cancel(s),s=null)}function a(){var t=+e.interval;l&&!isNaN(t)&&t>0?e.next():e.pause()}var s,l,c=this,u=c.slides=e.slides=[],d=-1;c.currentSlide=null;var f=!1;c.select=e.select=function(n,o){function a(){if(!f){if(c.currentSlide&&angular.isString(o)&&!e.noTransition&&n.$element){n.$element.addClass(o);n.$element[0].offsetWidth;angular.forEach(u,function(e){angular.extend(e,{direction:"",entering:!1,leaving:!1,active:!1})}),angular.extend(n,{direction:o,active:!0,entering:!0}),angular.extend(c.currentSlide||{},{direction:o,leaving:!0}),e.$currentTransition=i(n.$element,{}),function(t,n){e.$currentTransition.then(function(){s(t,n)},function(){s(t,n)})}(n,c.currentSlide)}else s(n,c.currentSlide);c.currentSlide=n,d=l,r()}}function s(t,n){angular.extend(t,{direction:"",active:!0,leaving:!1,entering:!1}),angular.extend(n||{},{direction:"",active:!1,leaving:!1,entering:!1}),e.$currentTransition=null}var l=u.indexOf(n);void 0===o&&(o=l>d?"next":"prev"),n&&n!==c.currentSlide&&(e.$currentTransition?(e.$currentTransition.cancel(),t(a)):a())},e.$on("$destroy",function(){f=!0}),c.indexOfSlide=function(e){return u.indexOf(e)},e.next=function(){var t=(d+1)%u.length;if(!e.$currentTransition)return c.select(u[t],"next")},e.prev=function(){var t=d-1<0?u.length-1:d-1;if(!e.$currentTransition)return c.select(u[t],"prev")},e.isActive=function(e){return c.currentSlide===e},e.$watch("interval",r),e.$on("$destroy",o),e.play=function(){l||(l=!0,r())},e.pause=function(){e.noPause||(l=!1,o())},c.addSlide=function(t,n){t.$element=n,u.push(t),1===u.length||t.active?(c.select(u[u.length-1]),1==u.length&&e.play()):t.active=!1},c.removeSlide=function(e){var t=u.indexOf(e);u.splice(t,1),u.length>0&&e.active?t>=u.length?c.select(u[t-1]):c.select(u[t]):d>t&&d--}}]).directive("carousel",[function(){return{restrict:"EA",transclude:!0,replace:!0,controller:"CarouselController",require:"carousel",templateUrl:"template/carousel/carousel.html",scope:{interval:"=",noTransition:"=",noPause:"="}}}]).directive("slide",function(){return{require:"^carousel",restrict:"EA",transclude:!0,replace:!0,templateUrl:"template/carousel/slide.html",scope:{active:"=?"},link:function(e,t,n,i){i.addSlide(e,t),e.$on("$destroy",function(){i.removeSlide(e)}),e.$watch("active",function(t){t&&i.select(e)})}}}),angular.module("ui.bootstrap.dateparser",[]).service("dateParser",["$locale","orderByFilter",function(e,t){function n(e){var n=[],i=e.split("");return angular.forEach(r,function(t,r){var o=e.indexOf(r);if(o>-1){e=e.split(""),i[o]="("+t.regex+")",e[o]="$";for(var a=o+1,s=o+r.length;a<s;a++)i[a]="",e[a]="$";e=e.join(""),n.push({index:o,apply:t.apply})}}),{regex:new RegExp("^"+i.join("")+"$"),map:t(n,"index")}}function i(e,t,n){return 1===t&&n>28?29===n&&(e%4==0&&e%100!=0||e%400==0):3!==t&&5!==t&&8!==t&&10!==t||n<31}this.parsers={};var r={yyyy:{regex:"\\d{4}",apply:function(e){this.year=+e}},yy:{regex:"\\d{2}",apply:function(e){this.year=+e+2e3}},y:{regex:"\\d{1,4}",apply:function(e){this.year=+e}},MMMM:{regex:e.DATETIME_FORMATS.MONTH.join("|"),apply:function(t){this.month=e.DATETIME_FORMATS.MONTH.indexOf(t)}},MMM:{regex:e.DATETIME_FORMATS.SHORTMONTH.join("|"),apply:function(t){this.month=e.DATETIME_FORMATS.SHORTMONTH.indexOf(t)}},MM:{regex:"0[1-9]|1[0-2]",apply:function(e){this.month=e-1}},M:{regex:"[1-9]|1[0-2]",apply:function(e){this.month=e-1}},dd:{regex:"[0-2][0-9]{1}|3[0-1]{1}",apply:function(e){this.date=+e}},d:{regex:"[1-2]?[0-9]{1}|3[0-1]{1}",apply:function(e){this.date=+e}},EEEE:{regex:e.DATETIME_FORMATS.DAY.join("|")},EEE:{regex:e.DATETIME_FORMATS.SHORTDAY.join("|")}};this.parse=function(t,r){if(!angular.isString(t)||!r)return t;r=e.DATETIME_FORMATS[r]||r,this.parsers[r]||(this.parsers[r]=n(r));var o=this.parsers[r],a=o.regex,s=o.map,l=t.match(a);if(l&&l.length){for(var c,u={year:1900,month:0,date:1,hours:0},d=1,f=l.length;d<f;d++){var p=s[d-1];p.apply&&p.apply.call(u,l[d])}return i(u.year,u.month,u.date)&&(c=new Date(u.year,u.month,u.date,u.hours)),c}}}]),angular.module("ui.bootstrap.position",[]).factory("$position",["$document","$window",function(e,t){function n(e,n){return e.currentStyle?e.currentStyle[n]:t.getComputedStyle?t.getComputedStyle(e)[n]:e.style[n]}function i(e){return"static"===(n(e,"position")||"static")}var r=function(t){for(var n=e[0],r=t.offsetParent||n;r&&r!==n&&i(r);)r=r.offsetParent;return r||n};return{position:function(t){var n=this.offset(t),i={top:0,left:0},o=r(t[0]);o!=e[0]&&(i=this.offset(angular.element(o)),i.top+=o.clientTop-o.scrollTop,i.left+=o.clientLeft-o.scrollLeft);var a=t[0].getBoundingClientRect();return{width:a.width||t.prop("offsetWidth"),height:a.height||t.prop("offsetHeight"),top:n.top-i.top,left:n.left-i.left}},offset:function(n){var i=n[0].getBoundingClientRect();return{width:i.width||n.prop("offsetWidth"),height:i.height||n.prop("offsetHeight"),top:i.top+(t.pageYOffset||e[0].documentElement.scrollTop),left:i.left+(t.pageXOffset||e[0].documentElement.scrollLeft)}},positionElements:function(e,t,n,i){var r,o,a,s,l=n.split("-"),c=l[0],u=l[1]||"center";r=i?this.offset(e):this.position(e),o=t.prop("offsetWidth"),a=t.prop("offsetHeight");var d={center:function(){return r.left+r.width/2-o/2},left:function(){return r.left},right:function(){return r.left+r.width}},f={center:function(){return r.top+r.height/2-a/2},top:function(){return r.top},bottom:function(){return r.top+r.height}};switch(c){case"right":s={top:f[u](),left:d[c]()};break;case"left":s={top:f[u](),left:r.left-o};break;case"bottom":s={top:f[c](),left:d[u]()};break;default:s={top:r.top-a,left:d[u]()}}return s}}}]),angular.module("ui.bootstrap.datepicker",["ui.bootstrap.dateparser","ui.bootstrap.position"]).constant("datepickerConfig",{formatDay:"dd",formatMonth:"MMMM",formatYear:"yyyy",formatDayHeader:"EEE",formatDayTitle:"MMMM yyyy",formatMonthTitle:"yyyy",datepickerMode:"day",minMode:"day",maxMode:"year",showWeeks:!0,startingDay:0,yearRange:20,minDate:null,maxDate:null}).controller("DatepickerController",["$scope","$attrs","$parse","$interpolate","$timeout","$log","dateFilter","datepickerConfig",function(e,t,n,i,r,o,a,s){var l=this,c={$setViewValue:angular.noop};this.modes=["day","month","year"],angular.forEach(["formatDay","formatMonth","formatYear","formatDayHeader","formatDayTitle","formatMonthTitle","minMode","maxMode","showWeeks","startingDay","yearRange"],function(n,r){l[n]=angular.isDefined(t[n])?r<8?i(t[n])(e.$parent):e.$parent.$eval(t[n]):s[n]}),angular.forEach(["minDate","maxDate"],function(i){t[i]?e.$parent.$watch(n(t[i]),function(e){l[i]=e?new Date(e):null,l.refreshView()}):l[i]=s[i]?new Date(s[i]):null}),e.datepickerMode=e.datepickerMode||s.datepickerMode,e.uniqueId="datepicker-"+e.$id+"-"+Math.floor(1e4*Math.random()),this.activeDate=angular.isDefined(t.initDate)?e.$parent.$eval(t.initDate):new Date,e.isActive=function(t){return 0===l.compare(t.date,l.activeDate)&&(e.activeDateId=t.uid,!0)},this.init=function(e){c=e,c.$render=function(){l.render()}},this.render=function(){if(c.$modelValue){var e=new Date(c.$modelValue),t=!isNaN(e);t?this.activeDate=e:o.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.'),c.$setValidity("date",t)}this.refreshView()},this.refreshView=function(){if(this.element){this._refreshView();var e=c.$modelValue?new Date(c.$modelValue):null;c.$setValidity("date-disabled",!e||this.element&&!this.isDisabled(e))}},this.createDateObject=function(e,t){var n=c.$modelValue?new Date(c.$modelValue):null;return{date:e,label:a(e,t),selected:n&&0===this.compare(e,n),disabled:this.isDisabled(e),current:0===this.compare(e,new Date)}},this.isDisabled=function(n){return this.minDate&&this.compare(n,this.minDate)<0||this.maxDate&&this.compare(n,this.maxDate)>0||t.dateDisabled&&e.dateDisabled({date:n,mode:e.datepickerMode})},this.split=function(e,t){for(var n=[];e.length>0;)n.push(e.splice(0,t));return n},e.select=function(t){if(e.datepickerMode===l.minMode){var n=c.$modelValue?new Date(c.$modelValue):new Date(0,0,0,0,0,0,0);n.setFullYear(t.getFullYear(),t.getMonth(),t.getDate()),c.$setViewValue(n),c.$render()}else l.activeDate=t,e.datepickerMode=l.modes[l.modes.indexOf(e.datepickerMode)-1]},e.move=function(e){var t=l.activeDate.getFullYear()+e*(l.step.years||0),n=l.activeDate.getMonth()+e*(l.step.months||0);l.activeDate.setFullYear(t,n,1),l.refreshView()},e.toggleMode=function(t){t=t||1,e.datepickerMode===l.maxMode&&1===t||e.datepickerMode===l.minMode&&-1===t||(e.datepickerMode=l.modes[l.modes.indexOf(e.datepickerMode)+t])},e.keys={13:"enter",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down"};var u=function(){r(function(){l.element[0].focus()},0,!1)};e.$on("datepicker.focus",u),e.keydown=function(t){var n=e.keys[t.which];if(n&&!t.shiftKey&&!t.altKey)if(t.preventDefault(),t.stopPropagation(),"enter"===n||"space"===n){if(l.isDisabled(l.activeDate))return;e.select(l.activeDate),u()}else!t.ctrlKey||"up"!==n&&"down"!==n?(l.handleKeyDown(n,t),l.refreshView()):(e.toggleMode("up"===n?1:-1),u())}}]).directive("datepicker",function(){return{restrict:"EA",replace:!0,templateUrl:"template/datepicker/datepicker.html",scope:{datepickerMode:"=?",dateDisabled:"&"},require:["datepicker","?^ngModel"],controller:"DatepickerController",link:function(e,t,n,i){var r=i[0],o=i[1];o&&r.init(o)}}}).directive("daypicker",["dateFilter",function(e){return{restrict:"EA",replace:!0,templateUrl:"template/datepicker/day.html",require:"^datepicker",link:function(t,n,i,r){function o(e,t){return 1!==t||e%4!=0||e%100==0&&e%400!=0?l[t]:29}function a(e,t){var n=new Array(t),i=new Date(e),r=0;for(i.setHours(12);r<t;)n[r++]=new Date(i),i.setDate(i.getDate()+1);return n}function s(e){var t=new Date(e);t.setDate(t.getDate()+4-(t.getDay()||7));var n=t.getTime();return t.setMonth(0),t.setDate(1),Math.floor(Math.round((n-t)/864e5)/7)+1}t.showWeeks=r.showWeeks,r.step={months:1},r.element=n;var l=[31,28,31,30,31,30,31,31,30,31,30,31];r._refreshView=function(){var n=r.activeDate.getFullYear(),i=r.activeDate.getMonth(),o=new Date(n,i,1),l=r.startingDay-o.getDay(),c=l>0?7-l:-l,u=new Date(o);c>0&&u.setDate(1-c);for(var d=a(u,42),f=0;f<42;f++)d[f]=angular.extend(r.createDateObject(d[f],r.formatDay),{secondary:d[f].getMonth()!==i,uid:t.uniqueId+"-"+f});t.labels=new Array(7);for(var p=0;p<7;p++)t.labels[p]={abbr:e(d[p].date,r.formatDayHeader),full:e(d[p].date,"EEEE")};if(t.title=e(r.activeDate,r.formatDayTitle),t.rows=r.split(d,7),t.showWeeks){t.weekNumbers=[];for(var h=s(t.rows[0][0].date),g=t.rows.length;t.weekNumbers.push(h++)<g;);}},r.compare=function(e,t){return new Date(e.getFullYear(),e.getMonth(),e.getDate())-new Date(t.getFullYear(),t.getMonth(),t.getDate())},r.handleKeyDown=function(e,t){var n=r.activeDate.getDate();if("left"===e)n-=1;else if("up"===e)n-=7;else if("right"===e)n+=1;else if("down"===e)n+=7;else if("pageup"===e||"pagedown"===e){var i=r.activeDate.getMonth()+("pageup"===e?-1:1);r.activeDate.setMonth(i,1),n=Math.min(o(r.activeDate.getFullYear(),r.activeDate.getMonth()),n)}else"home"===e?n=1:"end"===e&&(n=o(r.activeDate.getFullYear(),r.activeDate.getMonth()));r.activeDate.setDate(n)},r.refreshView()}}}]).directive("monthpicker",["dateFilter",function(e){return{restrict:"EA",replace:!0,templateUrl:"template/datepicker/month.html",require:"^datepicker",link:function(t,n,i,r){r.step={years:1},r.element=n,r._refreshView=function(){for(var n=new Array(12),i=r.activeDate.getFullYear(),o=0;o<12;o++)n[o]=angular.extend(r.createDateObject(new Date(i,o,1),r.formatMonth),{uid:t.uniqueId+"-"+o});t.title=e(r.activeDate,r.formatMonthTitle),t.rows=r.split(n,3)},r.compare=function(e,t){return new Date(e.getFullYear(),e.getMonth())-new Date(t.getFullYear(),t.getMonth())},r.handleKeyDown=function(e,t){var n=r.activeDate.getMonth();if("left"===e)n-=1;else if("up"===e)n-=3;else if("right"===e)n+=1;else if("down"===e)n+=3;else if("pageup"===e||"pagedown"===e){var i=r.activeDate.getFullYear()+("pageup"===e?-1:1);r.activeDate.setFullYear(i)}else"home"===e?n=0:"end"===e&&(n=11);r.activeDate.setMonth(n)},r.refreshView()}}}]).directive("yearpicker",["dateFilter",function(e){return{restrict:"EA",replace:!0,templateUrl:"template/datepicker/year.html",require:"^datepicker",link:function(e,t,n,i){function r(e){return parseInt((e-1)/o,10)*o+1}var o=i.yearRange;i.step={years:o},i.element=t,i._refreshView=function(){for(var t=new Array(o),n=0,a=r(i.activeDate.getFullYear());n<o;n++)t[n]=angular.extend(i.createDateObject(new Date(a+n,0,1),i.formatYear),{uid:e.uniqueId+"-"+n});e.title=[t[0].label,t[o-1].label].join(" - "),e.rows=i.split(t,5)},i.compare=function(e,t){return e.getFullYear()-t.getFullYear()},i.handleKeyDown=function(e,t){var n=i.activeDate.getFullYear();"left"===e?n-=1:"up"===e?n-=5:"right"===e?n+=1:"down"===e?n+=5:"pageup"===e||"pagedown"===e?n+=("pageup"===e?-1:1)*i.step.years:"home"===e?n=r(i.activeDate.getFullYear()):"end"===e&&(n=r(i.activeDate.getFullYear())+o-1),i.activeDate.setFullYear(n)},i.refreshView()}}}]).constant("datepickerPopupConfig",{datepickerPopup:"yyyy-MM-dd",currentText:"Today",clearText:"Clear",closeText:"Done",closeOnDateSelection:!0,appendToBody:!1,showButtonBar:!0}).directive("datepickerPopup",["$compile","$parse","$document","$position","dateFilter","dateParser","datepickerPopupConfig",function(e,t,n,i,r,o,a){return{restrict:"EA",require:"ngModel",scope:{isOpen:"=?",currentText:"@",clearText:"@",closeText:"@",dateDisabled:"&"},link:function(s,l,c,u){function d(e){return e.replace(/([A-Z])/g,function(e){return"-"+e.toLowerCase()})}function f(e){if(e){if(angular.isDate(e)&&!isNaN(e))return u.$setValidity("date",!0),e;if(angular.isString(e)){var t=o.parse(e,p)||new Date(e);return isNaN(t)?void u.$setValidity("date",!1):(u.$setValidity("date",!0),t)}return void u.$setValidity("date",!1)}return u.$setValidity("date",!0),null}var p,h=angular.isDefined(c.closeOnDateSelection)?s.$parent.$eval(c.closeOnDateSelection):a.closeOnDateSelection,g=angular.isDefined(c.datepickerAppendToBody)?s.$parent.$eval(c.datepickerAppendToBody):a.appendToBody;s.showButtonBar=angular.isDefined(c.showButtonBar)?s.$parent.$eval(c.showButtonBar):a.showButtonBar,s.getText=function(e){return s[e+"Text"]||a[e+"Text"]},c.$observe("datepickerPopup",function(e){p=e||a.datepickerPopup,u.$render()});var m=angular.element("<div datepicker-popup-wrap><div datepicker></div></div>");m.attr({"ng-model":"date","ng-change":"dateSelection()"});var v=angular.element(m.children()[0]);c.datepickerOptions&&angular.forEach(s.$parent.$eval(c.datepickerOptions),function(e,t){v.attr(d(t),e)}),s.watchData={},angular.forEach(["minDate","maxDate","datepickerMode"],function(e){if(c[e]){var n=t(c[e]);if(s.$parent.$watch(n,function(t){s.watchData[e]=t}),v.attr(d(e),"watchData."+e),"datepickerMode"===e){var i=n.assign;s.$watch("watchData."+e,function(e,t){e!==t&&i(s.$parent,e)})}}}),c.dateDisabled&&v.attr("date-disabled","dateDisabled({ date: date, mode: mode })"),u.$parsers.unshift(f),s.dateSelection=function(e){angular.isDefined(e)&&(s.date=e),u.$setViewValue(s.date),u.$render(),h&&(s.isOpen=!1,l[0].focus())},l.bind("input change keyup",function(){s.$apply(function(){s.date=u.$modelValue})}),u.$render=function(){var e=u.$viewValue?r(u.$viewValue,p):"";l.val(e),s.date=f(u.$modelValue)};var $=function(e){s.isOpen&&e.target!==l[0]&&s.$apply(function(){s.isOpen=!1})},y=function(e,t){s.keydown(e)};l.bind("keydown",y),s.keydown=function(e){27===e.which?(e.preventDefault(),e.stopPropagation(),s.close()):40!==e.which||s.isOpen||(s.isOpen=!0)},s.$watch("isOpen",function(e){e?(s.$broadcast("datepicker.focus"),s.position=g?i.offset(l):i.position(l),s.position.top=s.position.top+l.prop("offsetHeight"),n.bind("click",$)):n.unbind("click",$)}),s.select=function(e){if("today"===e){var t=new Date;angular.isDate(u.$modelValue)?(e=new Date(u.$modelValue),e.setFullYear(t.getFullYear(),t.getMonth(),t.getDate())):e=new Date(t.setHours(0,0,0,0))}s.dateSelection(e)},s.close=function(){s.isOpen=!1,l[0].focus()};var b=e(m)(s);m.remove(),g?n.find("body").append(b):l.after(b),s.$on("$destroy",function(){b.remove(),l.unbind("keydown",y),n.unbind("click",$)})}}}]).directive("datepickerPopupWrap",function(){return{restrict:"EA",replace:!0,transclude:!0,templateUrl:"template/datepicker/popup.html",link:function(e,t,n){t.bind("click",function(e){e.preventDefault(),e.stopPropagation()})}}}),angular.module("ui.bootstrap.dropdown",[]).constant("dropdownConfig",{openClass:"open"}).service("dropdownService",["$document",function(e){var t=null;this.open=function(r){t||(e.bind("click",n),e.bind("keydown",i)),t&&t!==r&&(t.isOpen=!1),t=r},this.close=function(r){t===r&&(t=null,e.unbind("click",n),e.unbind("keydown",i))};var n=function(e){if(t){var n=t.getToggleElement();e&&n&&n[0].contains(e.target)||t.$apply(function(){t.isOpen=!1})}},i=function(e){27===e.which&&(t.focusToggleElement(),n())}}]).controller("DropdownController",["$scope","$attrs","$parse","dropdownConfig","dropdownService","$animate",function(e,t,n,i,r,o){var a,s=this,l=e.$new(),c=i.openClass,u=angular.noop,d=t.onToggle?n(t.onToggle):angular.noop;this.init=function(i){s.$element=i,t.isOpen&&(a=n(t.isOpen),u=a.assign,e.$watch(a,function(e){l.isOpen=!!e}))},this.toggle=function(e){return l.isOpen=arguments.length?!!e:!l.isOpen},this.isOpen=function(){return l.isOpen},l.getToggleElement=function(){return s.toggleElement},l.focusToggleElement=function(){s.toggleElement&&s.toggleElement[0].focus()},l.$watch("isOpen",function(t,n){o[t?"addClass":"removeClass"](s.$element,c),t?(l.focusToggleElement(),r.open(l)):r.close(l),u(e,t),angular.isDefined(t)&&t!==n&&d(e,{open:!!t})}),e.$on("$locationChangeSuccess",function(){l.isOpen=!1}),e.$on("$destroy",function(){l.$destroy()})}]).directive("dropdown",function(){return{controller:"DropdownController",link:function(e,t,n,i){i.init(t)}}}).directive("dropdownToggle",function(){return{require:"?^dropdown",link:function(e,t,n,i){if(i){i.toggleElement=t;var r=function(r){r.preventDefault(),t.hasClass("disabled")||n.disabled||e.$apply(function(){i.toggle()})};t.bind("click",r),t.attr({"aria-haspopup":!0,"aria-expanded":!1}),e.$watch(i.isOpen,function(e){t.attr("aria-expanded",!!e)}),e.$on("$destroy",function(){t.unbind("click",r)})}}}}),angular.module("ui.bootstrap.modal",["ui.bootstrap.transition"]).factory("$$stackedMap",function(){return{createNew:function(){var e=[];return{add:function(t,n){e.push({key:t,value:n})},get:function(t){for(var n=0;n<e.length;n++)if(t==e[n].key)return e[n]},keys:function(){for(var t=[],n=0;n<e.length;n++)t.push(e[n].key);return t},top:function(){return e[e.length-1]},remove:function(t){for(var n=-1,i=0;i<e.length;i++)if(t==e[i].key){n=i;break}return e.splice(n,1)[0]},removeTop:function(){return e.splice(e.length-1,1)[0]},length:function(){return e.length}}}}}).directive("modalBackdrop",["$timeout",function(e){return{restrict:"EA",replace:!0,templateUrl:"template/modal/backdrop.html",link:function(t,n,i){t.backdropClass=i.backdropClass||"",t.animate=!1,e(function(){t.animate=!0})}}}]).directive("modalWindow",["$modalStack","$timeout",function(e,t){return{restrict:"EA",scope:{index:"@",animate:"="},replace:!0,transclude:!0,templateUrl:function(e,t){return t.templateUrl||"template/modal/window.html"},link:function(n,i,r){i.addClass(r.windowClass||""),n.size=r.size,t(function(){n.animate=!0,i[0].querySelectorAll("[autofocus]").length||i[0].focus()}),n.close=function(t){var n=e.getTop();n&&n.value.backdrop&&"static"!=n.value.backdrop&&t.target===t.currentTarget&&(t.preventDefault(),t.stopPropagation(),e.dismiss(n.key,"backdrop click"))}}}}]).directive("modalTransclude",function(){return{link:function(e,t,n,i,r){r(e.$parent,function(e){t.empty(),t.append(e)})}}}).factory("$modalStack",["$transition","$timeout","$document","$compile","$rootScope","$$stackedMap",function(e,t,n,i,r,o){function a(){for(var e=-1,t=p.keys(),n=0;n<t.length;n++)p.get(t[n]).value.backdrop&&(e=n);return e}function s(e){var t=n.find("body").eq(0),i=p.get(e).value;p.remove(e),c(i.modalDomEl,i.modalScope,300,function(){i.modalScope.$destroy(),t.toggleClass(f,p.length()>0),l()})}function l(){if(u&&-1==a()){var e=d;c(u,d,150,function(){e.$destroy(),e=null}),u=void 0,d=void 0}}function c(n,i,r,o){function a(){a.done||(a.done=!0,n.remove(),o&&o())}i.animate=!1;var s=e.transitionEndEventName;if(s){var l=t(a,r);n.bind(s,function(){t.cancel(l),a(),i.$apply()})}else t(a)}var u,d,f="modal-open",p=o.createNew(),h={};return r.$watch(a,function(e){d&&(d.index=e)}),n.bind("keydown",function(e){var t;27===e.which&&(t=p.top())&&t.value.keyboard&&(e.preventDefault(),r.$apply(function(){h.dismiss(t.key,"escape key press")}))}),h.open=function(e,t){p.add(e,{deferred:t.deferred,modalScope:t.scope,backdrop:t.backdrop,keyboard:t.keyboard});var o=n.find("body").eq(0),s=a();if(s>=0&&!u){d=r.$new(!0),d.index=s;var l=angular.element("<div modal-backdrop></div>");l.attr("backdrop-class",t.backdropClass),u=i(l)(d),o.append(u)}var c=angular.element("<div modal-window></div>");c.attr({"template-url":t.windowTemplateUrl,"window-class":t.windowClass,size:t.size,index:p.length()-1,animate:"animate"}).html(t.content);var h=i(c)(t.scope);p.top().value.modalDomEl=h,o.append(h),o.addClass(f)},h.close=function(e,t){var n=p.get(e);n&&(n.value.deferred.resolve(t),s(e))},h.dismiss=function(e,t){var n=p.get(e);n&&(n.value.deferred.reject(t),s(e))},h.dismissAll=function(e){for(var t=this.getTop();t;)this.dismiss(t.key,e),t=this.getTop()},h.getTop=function(){return p.top()},h}]).provider("$modal",function(){var e={options:{backdrop:!0,keyboard:!0},$get:["$injector","$rootScope","$q","$http","$templateCache","$controller","$modalStack",function(t,n,i,r,o,a,s){function l(e){return e.template?i.when(e.template):r.get(angular.isFunction(e.templateUrl)?e.templateUrl():e.templateUrl,{cache:o}).then(function(e){return e.data})}function c(e){var n=[];return angular.forEach(e,function(e){(angular.isFunction(e)||angular.isArray(e))&&n.push(i.when(t.invoke(e)))}),n}var u={};return u.open=function(t){var r=i.defer(),o=i.defer(),u={result:r.promise,opened:o.promise,close:function(e){s.close(u,e)},dismiss:function(e){s.dismiss(u,e)}};if(t=angular.extend({},e.options,t),t.resolve=t.resolve||{},!t.template&&!t.templateUrl)throw new Error("One of template or templateUrl options is required.");var d=i.all([l(t)].concat(c(t.resolve)));return d.then(function(e){var i=(t.scope||n).$new();i.$close=u.close,i.$dismiss=u.dismiss;var o,l={},c=1;t.controller&&(l.$scope=i,l.$modalInstance=u,angular.forEach(t.resolve,function(t,n){l[n]=e[c++]}),o=a(t.controller,l),t.controllerAs&&(i[t.controllerAs]=o)),s.open(u,{scope:i,deferred:r,content:e[0],backdrop:t.backdrop,keyboard:t.keyboard,backdropClass:t.backdropClass,windowClass:t.windowClass,windowTemplateUrl:t.windowTemplateUrl,size:t.size})},function(e){r.reject(e)}),d.then(function(){o.resolve(!0)},function(){o.reject(!1)}),u},u}]};return e}),angular.module("ui.bootstrap.pagination",[]).controller("PaginationController",["$scope","$attrs","$parse",function(e,t,n){var i=this,r={$setViewValue:angular.noop},o=t.numPages?n(t.numPages).assign:angular.noop;this.init=function(o,a){r=o,this.config=a,r.$render=function(){i.render()},t.itemsPerPage?e.$parent.$watch(n(t.itemsPerPage),function(t){i.itemsPerPage=parseInt(t,10),e.totalPages=i.calculateTotalPages()}):this.itemsPerPage=a.itemsPerPage},this.calculateTotalPages=function(){var t=this.itemsPerPage<1?1:Math.ceil(e.totalItems/this.itemsPerPage);return Math.max(t||0,1)},this.render=function(){e.page=parseInt(r.$viewValue,10)||1},e.selectPage=function(t){e.page!==t&&t>0&&t<=e.totalPages&&(r.$setViewValue(t),r.$render())},e.getText=function(t){return e[t+"Text"]||i.config[t+"Text"]},e.noPrevious=function(){return 1===e.page},e.noNext=function(){return e.page===e.totalPages},e.$watch("totalItems",function(){e.totalPages=i.calculateTotalPages()}),e.$watch("totalPages",function(t){o(e.$parent,t),e.page>t?e.selectPage(t):r.$render()})}]).constant("paginationConfig",{itemsPerPage:10,boundaryLinks:!1,directionLinks:!0,firstText:"First",previousText:"Previous",nextText:"Next",lastText:"Last",rotate:!0}).directive("pagination",["$parse","paginationConfig",function(e,t){return{restrict:"EA",scope:{totalItems:"=",firstText:"@",previousText:"@",nextText:"@",lastText:"@"},require:["pagination","?ngModel"],controller:"PaginationController",templateUrl:"template/pagination/pagination.html",replace:!0,link:function(n,i,r,o){function a(e,t,n){return{number:e,text:t,active:n}}function s(e,t){var n=[],i=1,r=t,o=angular.isDefined(u)&&u<t;o&&(d?(i=Math.max(e-Math.floor(u/2),1),(r=i+u-1)>t&&(r=t,i=r-u+1)):(i=(Math.ceil(e/u)-1)*u+1,r=Math.min(i+u-1,t)));for(var s=i;s<=r;s++){var l=a(s,s,s===e);n.push(l)}if(o&&!d){if(i>1){var c=a(i-1,"...",!1);n.unshift(c)}if(r<t){var f=a(r+1,"...",!1);n.push(f)}}return n}var l=o[0],c=o[1];if(c){var u=angular.isDefined(r.maxSize)?n.$parent.$eval(r.maxSize):t.maxSize,d=angular.isDefined(r.rotate)?n.$parent.$eval(r.rotate):t.rotate;n.boundaryLinks=angular.isDefined(r.boundaryLinks)?n.$parent.$eval(r.boundaryLinks):t.boundaryLinks,n.directionLinks=angular.isDefined(r.directionLinks)?n.$parent.$eval(r.directionLinks):t.directionLinks,l.init(c,t),r.maxSize&&n.$parent.$watch(e(r.maxSize),function(e){u=parseInt(e,10),l.render()});var f=l.render;l.render=function(){f(),n.page>0&&n.page<=n.totalPages&&(n.pages=s(n.page,n.totalPages))}}}}}]).constant("pagerConfig",{itemsPerPage:10,previousText:"« Previous",nextText:"Next »",align:!0}).directive("pager",["pagerConfig",function(e){return{restrict:"EA",scope:{totalItems:"=",previousText:"@",nextText:"@"},require:["pager","?ngModel"],controller:"PaginationController",templateUrl:"template/pagination/pager.html",replace:!0,link:function(t,n,i,r){var o=r[0],a=r[1];a&&(t.align=angular.isDefined(i.align)?t.$parent.$eval(i.align):e.align,o.init(a,e))}}}]),angular.module("ui.bootstrap.tooltip",["ui.bootstrap.position","ui.bootstrap.bindHtml"]).provider("$tooltip",function(){function e(e){var t=/[A-Z]/g;return e.replace(t,function(e,t){return(t?"-":"")+e.toLowerCase()})}var t={placement:"top",animation:!0,popupDelay:0},n={mouseenter:"mouseleave",click:"click",focus:"blur"},i={};this.options=function(e){angular.extend(i,e)},this.setTriggers=function(e){angular.extend(n,e)},this.$get=["$window","$compile","$timeout","$document","$position","$interpolate",function(r,o,a,s,l,c){return function(r,u,d){function f(e){var t=e||p.trigger||d;return{show:t,hide:n[t]||t}}var p=angular.extend({},t,i),h=e(r),g=c.startSymbol(),m=c.endSymbol(),v="<div "+h+'-popup title="'+g+"title"+m+'" content="'+g+"content"+m+'" placement="'+g+"placement"+m+'" animation="animation" is-open="isOpen"></div>';return{restrict:"EA",compile:function(e,t){var n=o(v);return function(e,t,i){function o(){D.isOpen?d():c()}function c(){T&&!e.$eval(i[u+"Enable"])||($(),D.popupDelay?k||(k=a(h,D.popupDelay,!1),k.then(function(e){e()})):h()())}function d(){e.$apply(function(){g()})}function h(){return k=null,C&&(a.cancel(C),C=null),D.content?(m(),w.css({top:0,
+left:0,display:"block"}),D.$digest(),A(),D.isOpen=!0,D.$digest(),A):angular.noop}function g(){D.isOpen=!1,a.cancel(k),k=null,D.animation?C||(C=a(v,500)):v()}function m(){w&&v(),x=D.$new(),w=n(x,function(e){S?s.find("body").append(e):t.after(e)})}function v(){C=null,w&&(w.remove(),w=null),x&&(x.$destroy(),x=null)}function $(){y(),b()}function y(){var e=i[u+"Placement"];D.placement=angular.isDefined(e)?e:p.placement}function b(){var e=i[u+"PopupDelay"],t=parseInt(e,10);D.popupDelay=isNaN(t)?p.popupDelay:t}var w,x,C,k,S=!!angular.isDefined(p.appendToBody)&&p.appendToBody,E=f(void 0),T=angular.isDefined(i[u+"Enable"]),D=e.$new(!0),A=function(){var e=l.positionElements(t,w,D.placement,S);e.top+="px",e.left+="px",w.css(e)};D.isOpen=!1,i.$observe(r,function(e){D.content=e,!e&&D.isOpen&&g()}),i.$observe(u+"Title",function(e){D.title=e});var M=function(){t.unbind(E.show,c),t.unbind(E.hide,d)};!function(){var e=i[u+"Trigger"];M(),E=f(e),E.show===E.hide?t.bind(E.show,o):(t.bind(E.show,c),t.bind(E.hide,d))}();var O=e.$eval(i[u+"Animation"]);D.animation=angular.isDefined(O)?!!O:p.animation;var I=e.$eval(i[u+"AppendToBody"]);S=angular.isDefined(I)?I:S,S&&e.$on("$locationChangeSuccess",function(){D.isOpen&&g()}),e.$on("$destroy",function(){a.cancel(C),a.cancel(k),M(),v(),D=null})}}}}}]}).directive("tooltipPopup",function(){return{restrict:"EA",replace:!0,scope:{content:"@",placement:"@",animation:"&",isOpen:"&"},templateUrl:"template/tooltip/tooltip-popup.html"}}).directive("tooltip",["$tooltip",function(e){return e("tooltip","tooltip","mouseenter")}]).directive("tooltipHtmlUnsafePopup",function(){return{restrict:"EA",replace:!0,scope:{content:"@",placement:"@",animation:"&",isOpen:"&"},templateUrl:"template/tooltip/tooltip-html-unsafe-popup.html"}}).directive("tooltipHtmlUnsafe",["$tooltip",function(e){return e("tooltipHtmlUnsafe","tooltip","mouseenter")}]),angular.module("ui.bootstrap.popover",["ui.bootstrap.tooltip"]).directive("popoverPopup",function(){return{restrict:"EA",replace:!0,scope:{title:"@",content:"@",placement:"@",animation:"&",isOpen:"&"},templateUrl:"template/popover/popover.html"}}).directive("popover",["$tooltip",function(e){return e("popover","popover","click")}]),angular.module("ui.bootstrap.progressbar",[]).constant("progressConfig",{animate:!0,max:100}).controller("ProgressController",["$scope","$attrs","progressConfig",function(e,t,n){var i=this,r=angular.isDefined(t.animate)?e.$parent.$eval(t.animate):n.animate;this.bars=[],e.max=angular.isDefined(t.max)?e.$parent.$eval(t.max):n.max,this.addBar=function(t,n){r||n.css({transition:"none"}),this.bars.push(t),t.$watch("value",function(n){t.percent=+(100*n/e.max).toFixed(2)}),t.$on("$destroy",function(){n=null,i.removeBar(t)})},this.removeBar=function(e){this.bars.splice(this.bars.indexOf(e),1)}}]).directive("progress",function(){return{restrict:"EA",replace:!0,transclude:!0,controller:"ProgressController",require:"progress",scope:{},templateUrl:"template/progressbar/progress.html"}}).directive("bar",function(){return{restrict:"EA",replace:!0,transclude:!0,require:"^progress",scope:{value:"=",type:"@"},templateUrl:"template/progressbar/bar.html",link:function(e,t,n,i){i.addBar(e,t)}}}).directive("progressbar",function(){return{restrict:"EA",replace:!0,transclude:!0,controller:"ProgressController",scope:{value:"=",type:"@"},templateUrl:"template/progressbar/progressbar.html",link:function(e,t,n,i){i.addBar(e,angular.element(t.children()[0]))}}}),angular.module("ui.bootstrap.rating",[]).constant("ratingConfig",{max:5,stateOn:null,stateOff:null}).controller("RatingController",["$scope","$attrs","ratingConfig",function(e,t,n){var i={$setViewValue:angular.noop};this.init=function(r){i=r,i.$render=this.render,this.stateOn=angular.isDefined(t.stateOn)?e.$parent.$eval(t.stateOn):n.stateOn,this.stateOff=angular.isDefined(t.stateOff)?e.$parent.$eval(t.stateOff):n.stateOff;var o=angular.isDefined(t.ratingStates)?e.$parent.$eval(t.ratingStates):new Array(angular.isDefined(t.max)?e.$parent.$eval(t.max):n.max);e.range=this.buildTemplateObjects(o)},this.buildTemplateObjects=function(e){for(var t=0,n=e.length;t<n;t++)e[t]=angular.extend({index:t},{stateOn:this.stateOn,stateOff:this.stateOff},e[t]);return e},e.rate=function(t){!e.readonly&&t>=0&&t<=e.range.length&&(i.$setViewValue(t),i.$render())},e.enter=function(t){e.readonly||(e.value=t),e.onHover({value:t})},e.reset=function(){e.value=i.$viewValue,e.onLeave()},e.onKeydown=function(t){/(37|38|39|40)/.test(t.which)&&(t.preventDefault(),t.stopPropagation(),e.rate(e.value+(38===t.which||39===t.which?1:-1)))},this.render=function(){e.value=i.$viewValue}}]).directive("rating",function(){return{restrict:"EA",require:["rating","ngModel"],scope:{readonly:"=?",onHover:"&",onLeave:"&"},controller:"RatingController",templateUrl:"template/rating/rating.html",replace:!0,link:function(e,t,n,i){var r=i[0],o=i[1];o&&r.init(o)}}}),angular.module("ui.bootstrap.tabs",[]).controller("TabsetController",["$scope",function(e){var t=this,n=t.tabs=e.tabs=[];t.select=function(e){angular.forEach(n,function(t){t.active&&t!==e&&(t.active=!1,t.onDeselect())}),e.active=!0,e.onSelect()},t.addTab=function(e){n.push(e),1===n.length?e.active=!0:e.active&&t.select(e)},t.removeTab=function(e){var r=n.indexOf(e);if(e.active&&n.length>1&&!i){var o=r==n.length-1?r-1:r+1;t.select(n[o])}n.splice(r,1)};var i;e.$on("$destroy",function(){i=!0})}]).directive("tabset",function(){return{restrict:"EA",transclude:!0,replace:!0,scope:{type:"@"},controller:"TabsetController",templateUrl:"template/tabs/tabset.html",link:function(e,t,n){e.vertical=!!angular.isDefined(n.vertical)&&e.$parent.$eval(n.vertical),e.justified=!!angular.isDefined(n.justified)&&e.$parent.$eval(n.justified)}}}).directive("tab",["$parse",function(e){return{require:"^tabset",restrict:"EA",replace:!0,templateUrl:"template/tabs/tab.html",transclude:!0,scope:{active:"=?",heading:"@",onSelect:"&select",onDeselect:"&deselect"},controller:function(){},compile:function(t,n,i){return function(t,n,r,o){t.$watch("active",function(e){e&&o.select(t)}),t.disabled=!1,r.disabled&&t.$parent.$watch(e(r.disabled),function(e){t.disabled=!!e}),t.select=function(){t.disabled||(t.active=!0)},o.addTab(t),t.$on("$destroy",function(){o.removeTab(t)}),t.$transcludeFn=i}}}}]).directive("tabHeadingTransclude",[function(){return{restrict:"A",require:"^tab",link:function(e,t,n,i){e.$watch("headingElement",function(e){e&&(t.html(""),t.append(e))})}}}]).directive("tabContentTransclude",function(){function e(e){return e.tagName&&(e.hasAttribute("tab-heading")||e.hasAttribute("data-tab-heading")||"tab-heading"===e.tagName.toLowerCase()||"data-tab-heading"===e.tagName.toLowerCase())}return{restrict:"A",require:"^tabset",link:function(t,n,i){var r=t.$eval(i.tabContentTransclude);r.$transcludeFn(r.$parent,function(t){angular.forEach(t,function(t){e(t)?r.headingElement=t:n.append(t)})})}}}),angular.module("ui.bootstrap.timepicker",[]).constant("timepickerConfig",{hourStep:1,minuteStep:1,showMeridian:!0,meridians:null,readonlyInput:!1,mousewheel:!0}).controller("TimepickerController",["$scope","$attrs","$parse","$log","$locale","timepickerConfig",function(e,t,n,i,r,o){function a(){var t=parseInt(e.hours,10);if(e.showMeridian?t>0&&t<13:t>=0&&t<24)return e.showMeridian&&(12===t&&(t=0),e.meridian===g[1]&&(t+=12)),t}function s(){var t=parseInt(e.minutes,10);return t>=0&&t<60?t:void 0}function l(e){return angular.isDefined(e)&&e.toString().length<2?"0"+e:e}function c(e){u(),h.$setViewValue(new Date(p)),d(e)}function u(){h.$setValidity("time",!0),e.invalidHours=!1,e.invalidMinutes=!1}function d(t){var n=p.getHours(),i=p.getMinutes();e.showMeridian&&(n=0===n||12===n?12:n%12),e.hours="h"===t?n:l(n),e.minutes="m"===t?i:l(i),e.meridian=p.getHours()<12?g[0]:g[1]}function f(e){var t=new Date(p.getTime()+6e4*e);p.setHours(t.getHours(),t.getMinutes()),c()}var p=new Date,h={$setViewValue:angular.noop},g=angular.isDefined(t.meridians)?e.$parent.$eval(t.meridians):o.meridians||r.DATETIME_FORMATS.AMPMS;this.init=function(n,i){h=n,h.$render=this.render;var r=i.eq(0),a=i.eq(1);(angular.isDefined(t.mousewheel)?e.$parent.$eval(t.mousewheel):o.mousewheel)&&this.setupMousewheelEvents(r,a),e.readonlyInput=angular.isDefined(t.readonlyInput)?e.$parent.$eval(t.readonlyInput):o.readonlyInput,this.setupInputEvents(r,a)};var m=o.hourStep;t.hourStep&&e.$parent.$watch(n(t.hourStep),function(e){m=parseInt(e,10)});var v=o.minuteStep;t.minuteStep&&e.$parent.$watch(n(t.minuteStep),function(e){v=parseInt(e,10)}),e.showMeridian=o.showMeridian,t.showMeridian&&e.$parent.$watch(n(t.showMeridian),function(t){if(e.showMeridian=!!t,h.$error.time){var n=a(),i=s();angular.isDefined(n)&&angular.isDefined(i)&&(p.setHours(n),c())}else d()}),this.setupMousewheelEvents=function(t,n){var i=function(e){e.originalEvent&&(e=e.originalEvent);var t=e.wheelDelta?e.wheelDelta:-e.deltaY;return e.detail||t>0};t.bind("mousewheel wheel",function(t){e.$apply(i(t)?e.incrementHours():e.decrementHours()),t.preventDefault()}),n.bind("mousewheel wheel",function(t){e.$apply(i(t)?e.incrementMinutes():e.decrementMinutes()),t.preventDefault()})},this.setupInputEvents=function(t,n){if(e.readonlyInput)return e.updateHours=angular.noop,void(e.updateMinutes=angular.noop);var i=function(t,n){h.$setViewValue(null),h.$setValidity("time",!1),angular.isDefined(t)&&(e.invalidHours=t),angular.isDefined(n)&&(e.invalidMinutes=n)};e.updateHours=function(){var e=a();angular.isDefined(e)?(p.setHours(e),c("h")):i(!0)},t.bind("blur",function(t){!e.invalidHours&&e.hours<10&&e.$apply(function(){e.hours=l(e.hours)})}),e.updateMinutes=function(){var e=s();angular.isDefined(e)?(p.setMinutes(e),c("m")):i(void 0,!0)},n.bind("blur",function(t){!e.invalidMinutes&&e.minutes<10&&e.$apply(function(){e.minutes=l(e.minutes)})})},this.render=function(){var e=h.$modelValue?new Date(h.$modelValue):null;isNaN(e)?(h.$setValidity("time",!1),i.error('Timepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.')):(e&&(p=e),u(),d())},e.incrementHours=function(){f(60*m)},e.decrementHours=function(){f(60*-m)},e.incrementMinutes=function(){f(v)},e.decrementMinutes=function(){f(-v)},e.toggleMeridian=function(){f(720*(p.getHours()<12?1:-1))}}]).directive("timepicker",function(){return{restrict:"EA",require:["timepicker","?^ngModel"],controller:"TimepickerController",replace:!0,scope:{},templateUrl:"template/timepicker/timepicker.html",link:function(e,t,n,i){var r=i[0],o=i[1];o&&r.init(o,t.find("input"))}}}),angular.module("ui.bootstrap.typeahead",["ui.bootstrap.position","ui.bootstrap.bindHtml"]).factory("typeaheadParser",["$parse",function(e){var t=/^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+([\s\S]+?)$/;return{parse:function(n){var i=n.match(t);if(!i)throw new Error('Expected typeahead specification in form of "_modelValue_ (as _label_)? for _item_ in _collection_" but got "'+n+'".');return{itemName:i[3],source:e(i[4]),viewMapper:e(i[2]||i[1]),modelMapper:e(i[1])}}}}]).directive("typeahead",["$compile","$parse","$q","$timeout","$document","$position","typeaheadParser",function(e,t,n,i,r,o,a){var s=[9,13,27,38,40];return{require:"ngModel",link:function(l,c,u,d){var f,p=l.$eval(u.typeaheadMinLength)||1,h=l.$eval(u.typeaheadWaitMs)||0,g=!1!==l.$eval(u.typeaheadEditable),m=t(u.typeaheadLoading).assign||angular.noop,v=t(u.typeaheadOnSelect),$=u.typeaheadInputFormatter?t(u.typeaheadInputFormatter):void 0,y=!!u.typeaheadAppendToBody&&l.$eval(u.typeaheadAppendToBody),b=!1!==l.$eval(u.typeaheadFocusFirst),w=t(u.ngModel).assign,x=a.parse(u.typeahead),C=l.$new();l.$on("$destroy",function(){C.$destroy()});var k="typeahead-"+C.$id+"-"+Math.floor(1e4*Math.random());c.attr({"aria-autocomplete":"list","aria-expanded":!1,"aria-owns":k});var S=angular.element("<div typeahead-popup></div>");S.attr({id:k,matches:"matches",active:"activeIdx",select:"select(activeIdx)",query:"query",position:"position"}),angular.isDefined(u.typeaheadTemplateUrl)&&S.attr("template-url",u.typeaheadTemplateUrl);var E=function(){C.matches=[],C.activeIdx=-1,c.attr("aria-expanded",!1)},T=function(e){return k+"-option-"+e};C.$watch("activeIdx",function(e){e<0?c.removeAttr("aria-activedescendant"):c.attr("aria-activedescendant",T(e))});var D=function(e){var t={$viewValue:e};m(l,!0),n.when(x.source(l,t)).then(function(n){var i=e===d.$viewValue;if(i&&f)if(n.length>0){C.activeIdx=b?0:-1,C.matches.length=0;for(var r=0;r<n.length;r++)t[x.itemName]=n[r],C.matches.push({id:T(r),label:x.viewMapper(C,t),model:n[r]});C.query=e,C.position=y?o.offset(c):o.position(c),C.position.top=C.position.top+c.prop("offsetHeight"),c.attr("aria-expanded",!0)}else E();i&&m(l,!1)},function(){E(),m(l,!1)})};E(),C.query=void 0;var A,M=function(e){A=i(function(){D(e)},h)},O=function(){A&&i.cancel(A)};d.$parsers.unshift(function(e){return f=!0,e&&e.length>=p?h>0?(O(),M(e)):D(e):(m(l,!1),O(),E()),g?e:e?void d.$setValidity("editable",!1):(d.$setValidity("editable",!0),e)}),d.$formatters.push(function(e){var t,n,i={};return $?(i.$model=e,$(l,i)):(i[x.itemName]=e,t=x.viewMapper(l,i),i[x.itemName]=void 0,n=x.viewMapper(l,i),t!==n?t:e)}),C.select=function(e){var t,n,r={};r[x.itemName]=n=C.matches[e].model,t=x.modelMapper(l,r),w(l,t),d.$setValidity("editable",!0),v(l,{$item:n,$model:t,$label:x.viewMapper(l,r)}),E(),i(function(){c[0].focus()},0,!1)},c.bind("keydown",function(e){0!==C.matches.length&&-1!==s.indexOf(e.which)&&(-1!=C.activeIdx||13!==e.which&&9!==e.which)&&(e.preventDefault(),40===e.which?(C.activeIdx=(C.activeIdx+1)%C.matches.length,C.$digest()):38===e.which?(C.activeIdx=(C.activeIdx>0?C.activeIdx:C.matches.length)-1,C.$digest()):13===e.which||9===e.which?C.$apply(function(){C.select(C.activeIdx)}):27===e.which&&(e.stopPropagation(),E(),C.$digest()))}),c.bind("blur",function(e){f=!1});var I=function(e){c[0]!==e.target&&(E(),C.$digest())};r.bind("click",I),l.$on("$destroy",function(){r.unbind("click",I),y&&P.remove()});var P=e(S)(C);y?r.find("body").append(P):c.after(P)}}}]).directive("typeaheadPopup",function(){return{restrict:"EA",scope:{matches:"=",query:"=",active:"=",position:"=",select:"&"},replace:!0,templateUrl:"template/typeahead/typeahead-popup.html",link:function(e,t,n){e.templateUrl=n.templateUrl,e.isOpen=function(){return e.matches.length>0},e.isActive=function(t){return e.active==t},e.selectActive=function(t){e.active=t},e.selectMatch=function(t){e.select({activeIdx:t})}}}}).directive("typeaheadMatch",["$http","$templateCache","$compile","$parse",function(e,t,n,i){return{restrict:"EA",scope:{index:"=",match:"=",query:"="},link:function(r,o,a){var s=i(a.templateUrl)(r.$parent)||"template/typeahead/typeahead-match.html";e.get(s,{cache:t}).success(function(e){o.replaceWith(n(e.trim())(r))})}}}]).filter("typeaheadHighlight",function(){function e(e){return e.replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1")}return function(t,n){return n?(""+t).replace(new RegExp(e(n),"gi"),"<strong>$&</strong>"):t}}),angular.module("template/accordion/accordion-group.html",[]).run(["$templateCache",function(e){e.put("template/accordion/accordion-group.html",'<div class="panel panel-default">\n <div class="panel-heading">\n <h4 class="panel-title">\n <a href class="accordion-toggle" ng-click="toggleOpen()" accordion-transclude="heading"><span ng-class="{\'text-muted\': isDisabled}">{{heading}}</span></a>\n </h4>\n </div>\n <div class="panel-collapse" collapse="!isOpen">\n\t <div class="panel-body" ng-transclude></div>\n </div>\n</div>\n')}]),angular.module("template/accordion/accordion.html",[]).run(["$templateCache",function(e){e.put("template/accordion/accordion.html",'<div class="panel-group" ng-transclude></div>')}]),angular.module("template/alert/alert.html",[]).run(["$templateCache",function(e){e.put("template/alert/alert.html",'<div class="alert" ng-class="[\'alert-\' + (type || \'warning\'), closeable ? \'alert-dismissable\' : null]" role="alert">\n <button ng-show="closeable" type="button" class="close" ng-click="close()">\n <span aria-hidden="true">&times;</span>\n <span class="sr-only">Close</span>\n </button>\n <div ng-transclude></div>\n</div>\n')}]),angular.module("template/carousel/carousel.html",[]).run(["$templateCache",function(e){e.put("template/carousel/carousel.html",'<div ng-mouseenter="pause()" ng-mouseleave="play()" class="carousel" ng-swipe-right="prev()" ng-swipe-left="next()">\n <ol class="carousel-indicators" ng-show="slides.length > 1">\n <li ng-repeat="slide in slides track by $index" ng-class="{active: isActive(slide)}" ng-click="select(slide)"></li>\n </ol>\n <div class="carousel-inner" ng-transclude></div>\n <a class="left carousel-control" ng-click="prev()" ng-show="slides.length > 1"><span class="glyphicon glyphicon-chevron-left"></span></a>\n <a class="right carousel-control" ng-click="next()" ng-show="slides.length > 1"><span class="glyphicon glyphicon-chevron-right"></span></a>\n</div>\n')}]),angular.module("template/carousel/slide.html",[]).run(["$templateCache",function(e){e.put("template/carousel/slide.html","<div ng-class=\"{\n 'active': leaving || (active && !entering),\n 'prev': (next || active) && direction=='prev',\n 'next': (next || active) && direction=='next',\n 'right': direction=='prev',\n 'left': direction=='next'\n }\" class=\"item text-center\" ng-transclude></div>\n")}]),angular.module("template/datepicker/datepicker.html",[]).run(["$templateCache",function(e){e.put("template/datepicker/datepicker.html",'<div ng-switch="datepickerMode" role="application" ng-keydown="keydown($event)">\n <daypicker ng-switch-when="day" tabindex="0"></daypicker>\n <monthpicker ng-switch-when="month" tabindex="0"></monthpicker>\n <yearpicker ng-switch-when="year" tabindex="0"></yearpicker>\n</div>')}]),angular.module("template/datepicker/day.html",[]).run(["$templateCache",function(e){e.put("template/datepicker/day.html",'<table role="grid" aria-labelledby="{{uniqueId}}-title" aria-activedescendant="{{activeDateId}}">\n <thead>\n <tr>\n <th><button type="button" class="btn btn-default btn-sm pull-left" ng-click="move(-1)" tabindex="-1"><i class="glyphicon glyphicon-chevron-left"></i></button></th>\n <th colspan="{{5 + showWeeks}}"><button id="{{uniqueId}}-title" role="heading" aria-live="assertive" aria-atomic="true" type="button" class="btn btn-default btn-sm" ng-click="toggleMode()" tabindex="-1" style="width:100%;"><strong>{{title}}</strong></button></th>\n <th><button type="button" class="btn btn-default btn-sm pull-right" ng-click="move(1)" tabindex="-1"><i class="glyphicon glyphicon-chevron-right"></i></button></th>\n </tr>\n <tr>\n <th ng-show="showWeeks" class="text-center"></th>\n <th ng-repeat="label in labels track by $index" class="text-center"><small aria-label="{{label.full}}">{{label.abbr}}</small></th>\n </tr>\n </thead>\n <tbody>\n <tr ng-repeat="row in rows track by $index">\n <td ng-show="showWeeks" class="text-center h6"><em>{{ weekNumbers[$index] }}</em></td>\n <td ng-repeat="dt in row track by dt.date" class="text-center" role="gridcell" id="{{dt.uid}}" aria-disabled="{{!!dt.disabled}}">\n <button type="button" style="width:100%;" class="btn btn-default btn-sm" ng-class="{\'btn-info\': dt.selected, active: isActive(dt)}" ng-click="select(dt.date)" ng-disabled="dt.disabled" tabindex="-1"><span ng-class="{\'text-muted\': dt.secondary, \'text-info\': dt.current}">{{dt.label}}</span></button>\n </td>\n </tr>\n </tbody>\n</table>\n')}]),angular.module("template/datepicker/month.html",[]).run(["$templateCache",function(e){e.put("template/datepicker/month.html",'<table role="grid" aria-labelledby="{{uniqueId}}-title" aria-activedescendant="{{activeDateId}}">\n <thead>\n <tr>\n <th><button type="button" class="btn btn-default btn-sm pull-left" ng-click="move(-1)" tabindex="-1"><i class="glyphicon glyphicon-chevron-left"></i></button></th>\n <th><button id="{{uniqueId}}-title" role="heading" aria-live="assertive" aria-atomic="true" type="button" class="btn btn-default btn-sm" ng-click="toggleMode()" tabindex="-1" style="width:100%;"><strong>{{title}}</strong></button></th>\n <th><button type="button" class="btn btn-default btn-sm pull-right" ng-click="move(1)" tabindex="-1"><i class="glyphicon glyphicon-chevron-right"></i></button></th>\n </tr>\n </thead>\n <tbody>\n <tr ng-repeat="row in rows track by $index">\n <td ng-repeat="dt in row track by dt.date" class="text-center" role="gridcell" id="{{dt.uid}}" aria-disabled="{{!!dt.disabled}}">\n <button type="button" style="width:100%;" class="btn btn-default" ng-class="{\'btn-info\': dt.selected, active: isActive(dt)}" ng-click="select(dt.date)" ng-disabled="dt.disabled" tabindex="-1"><span ng-class="{\'text-info\': dt.current}">{{dt.label}}</span></button>\n </td>\n </tr>\n </tbody>\n</table>\n')}]),angular.module("template/datepicker/popup.html",[]).run(["$templateCache",function(e){e.put("template/datepicker/popup.html",'<ul class="dropdown-menu" ng-style="{display: (isOpen && \'block\') || \'none\', top: position.top+\'px\', left: position.left+\'px\'}" ng-keydown="keydown($event)">\n\t<li ng-transclude></li>\n\t<li ng-if="showButtonBar" style="padding:10px 9px 2px">\n\t\t<span class="btn-group pull-left">\n\t\t\t<button type="button" class="btn btn-sm btn-info" ng-click="select(\'today\')">{{ getText(\'current\') }}</button>\n\t\t\t<button type="button" class="btn btn-sm btn-danger" ng-click="select(null)">{{ getText(\'clear\') }}</button>\n\t\t</span>\n\t\t<button type="button" class="btn btn-sm btn-success pull-right" ng-click="close()">{{ getText(\'close\') }}</button>\n\t</li>\n</ul>\n')}]),angular.module("template/datepicker/year.html",[]).run(["$templateCache",function(e){e.put("template/datepicker/year.html",'<table role="grid" aria-labelledby="{{uniqueId}}-title" aria-activedescendant="{{activeDateId}}">\n <thead>\n <tr>\n <th><button type="button" class="btn btn-default btn-sm pull-left" ng-click="move(-1)" tabindex="-1"><i class="glyphicon glyphicon-chevron-left"></i></button></th>\n <th colspan="3"><button id="{{uniqueId}}-title" role="heading" aria-live="assertive" aria-atomic="true" type="button" class="btn btn-default btn-sm" ng-click="toggleMode()" tabindex="-1" style="width:100%;"><strong>{{title}}</strong></button></th>\n <th><button type="button" class="btn btn-default btn-sm pull-right" ng-click="move(1)" tabindex="-1"><i class="glyphicon glyphicon-chevron-right"></i></button></th>\n </tr>\n </thead>\n <tbody>\n <tr ng-repeat="row in rows track by $index">\n <td ng-repeat="dt in row track by dt.date" class="text-center" role="gridcell" id="{{dt.uid}}" aria-disabled="{{!!dt.disabled}}">\n <button type="button" style="width:100%;" class="btn btn-default" ng-class="{\'btn-info\': dt.selected, active: isActive(dt)}" ng-click="select(dt.date)" ng-disabled="dt.disabled" tabindex="-1"><span ng-class="{\'text-info\': dt.current}">{{dt.label}}</span></button>\n </td>\n </tr>\n </tbody>\n</table>\n')}]),angular.module("template/modal/backdrop.html",[]).run(["$templateCache",function(e){e.put("template/modal/backdrop.html",'<div class="modal-backdrop fade {{ backdropClass }}"\n ng-class="{in: animate}"\n ng-style="{\'z-index\': 1040 + (index && 1 || 0) + index*10}"\n></div>\n')}]),angular.module("template/modal/window.html",[]).run(["$templateCache",function(e){e.put("template/modal/window.html",'<div tabindex="-1" role="dialog" class="modal fade" ng-class="{in: animate}" ng-style="{\'z-index\': 1050 + index*10, display: \'block\'}" ng-click="close($event)">\n <div class="modal-dialog" ng-class="{\'modal-sm\': size == \'sm\', \'modal-lg\': size == \'lg\'}"><div class="modal-content" modal-transclude></div></div>\n</div>')}]),angular.module("template/pagination/pager.html",[]).run(["$templateCache",function(e){e.put("template/pagination/pager.html",'<ul class="pager">\n <li ng-class="{disabled: noPrevious(), previous: align}"><a href ng-click="selectPage(page - 1)">{{getText(\'previous\')}}</a></li>\n <li ng-class="{disabled: noNext(), next: align}"><a href ng-click="selectPage(page + 1)">{{getText(\'next\')}}</a></li>\n</ul>')}]),angular.module("template/pagination/pagination.html",[]).run(["$templateCache",function(e){e.put("template/pagination/pagination.html",'<ul class="pagination">\n <li ng-if="boundaryLinks" ng-class="{disabled: noPrevious()}"><a href ng-click="selectPage(1)">{{getText(\'first\')}}</a></li>\n <li ng-if="directionLinks" ng-class="{disabled: noPrevious()}"><a href ng-click="selectPage(page - 1)">{{getText(\'previous\')}}</a></li>\n <li ng-repeat="page in pages track by $index" ng-class="{active: page.active}"><a href ng-click="selectPage(page.number)">{{page.text}}</a></li>\n <li ng-if="directionLinks" ng-class="{disabled: noNext()}"><a href ng-click="selectPage(page + 1)">{{getText(\'next\')}}</a></li>\n <li ng-if="boundaryLinks" ng-class="{disabled: noNext()}"><a href ng-click="selectPage(totalPages)">{{getText(\'last\')}}</a></li>\n</ul>')}]),angular.module("template/tooltip/tooltip-html-unsafe-popup.html",[]).run(["$templateCache",function(e){e.put("template/tooltip/tooltip-html-unsafe-popup.html",'<div class="tooltip {{placement}}" ng-class="{ in: isOpen(), fade: animation() }">\n <div class="tooltip-arrow"></div>\n <div class="tooltip-inner" bind-html-unsafe="content"></div>\n</div>\n')}]),angular.module("template/tooltip/tooltip-popup.html",[]).run(["$templateCache",function(e){e.put("template/tooltip/tooltip-popup.html",'<div class="tooltip {{placement}}" ng-class="{ in: isOpen(), fade: animation() }">\n <div class="tooltip-arrow"></div>\n <div class="tooltip-inner" ng-bind="content"></div>\n</div>\n')}]),angular.module("template/popover/popover.html",[]).run(["$templateCache",function(e){e.put("template/popover/popover.html",'<div class="popover {{placement}}" ng-class="{ in: isOpen(), fade: animation() }">\n <div class="arrow"></div>\n\n <div class="popover-inner">\n <h3 class="popover-title" ng-bind="title" ng-show="title"></h3>\n <div class="popover-content" ng-bind="content"></div>\n </div>\n</div>\n')}]),angular.module("template/progressbar/bar.html",[]).run(["$templateCache",function(e){e.put("template/progressbar/bar.html",'<div class="progress-bar" ng-class="type && \'progress-bar-\' + type" role="progressbar" aria-valuenow="{{value}}" aria-valuemin="0" aria-valuemax="{{max}}" ng-style="{width: percent + \'%\'}" aria-valuetext="{{percent | number:0}}%" ng-transclude></div>')}]),angular.module("template/progressbar/progress.html",[]).run(["$templateCache",function(e){e.put("template/progressbar/progress.html",'<div class="progress" ng-transclude></div>')}]),angular.module("template/progressbar/progressbar.html",[]).run(["$templateCache",function(e){e.put("template/progressbar/progressbar.html",'<div class="progress">\n <div class="progress-bar" ng-class="type && \'progress-bar-\' + type" role="progressbar" aria-valuenow="{{value}}" aria-valuemin="0" aria-valuemax="{{max}}" ng-style="{width: percent + \'%\'}" aria-valuetext="{{percent | number:0}}%" ng-transclude></div>\n</div>')}]),angular.module("template/rating/rating.html",[]).run(["$templateCache",function(e){e.put("template/rating/rating.html",'<span ng-mouseleave="reset()" ng-keydown="onKeydown($event)" tabindex="0" role="slider" aria-valuemin="0" aria-valuemax="{{range.length}}" aria-valuenow="{{value}}">\n <i ng-repeat="r in range track by $index" ng-mouseenter="enter($index + 1)" ng-click="rate($index + 1)" class="glyphicon" ng-class="$index < value && (r.stateOn || \'glyphicon-star\') || (r.stateOff || \'glyphicon-star-empty\')">\n <span class="sr-only">({{ $index < value ? \'*\' : \' \' }})</span>\n </i>\n</span>')}]),angular.module("template/tabs/tab.html",[]).run(["$templateCache",function(e){e.put("template/tabs/tab.html",'<li ng-class="{active: active, disabled: disabled}">\n <a href ng-click="select()" tab-heading-transclude>{{heading}}</a>\n</li>\n')}]),angular.module("template/tabs/tabset.html",[]).run(["$templateCache",function(e){e.put("template/tabs/tabset.html",'<div>\n <ul class="nav nav-{{type || \'tabs\'}}" ng-class="{\'nav-stacked\': vertical, \'nav-justified\': justified}" ng-transclude></ul>\n <div class="tab-content">\n <div class="tab-pane" \n ng-repeat="tab in tabs" \n ng-class="{active: tab.active}"\n tab-content-transclude="tab">\n </div>\n </div>\n</div>\n')}]),angular.module("template/timepicker/timepicker.html",[]).run(["$templateCache",function(e){e.put("template/timepicker/timepicker.html",'<table>\n\t<tbody>\n\t\t<tr class="text-center">\n\t\t\t<td><a ng-click="incrementHours()" class="btn btn-link"><span class="glyphicon glyphicon-chevron-up"></span></a></td>\n\t\t\t<td>&nbsp;</td>\n\t\t\t<td><a ng-click="incrementMinutes()" class="btn btn-link"><span class="glyphicon glyphicon-chevron-up"></span></a></td>\n\t\t\t<td ng-show="showMeridian"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td style="width:50px;" class="form-group" ng-class="{\'has-error\': invalidHours}">\n\t\t\t\t<input type="text" ng-model="hours" ng-change="updateHours()" class="form-control text-center" ng-mousewheel="incrementHours()" ng-readonly="readonlyInput" maxlength="2">\n\t\t\t</td>\n\t\t\t<td>:</td>\n\t\t\t<td style="width:50px;" class="form-group" ng-class="{\'has-error\': invalidMinutes}">\n\t\t\t\t<input type="text" ng-model="minutes" ng-change="updateMinutes()" class="form-control text-center" ng-readonly="readonlyInput" maxlength="2">\n\t\t\t</td>\n\t\t\t<td ng-show="showMeridian"><button type="button" class="btn btn-default text-center" ng-click="toggleMeridian()">{{meridian}}</button></td>\n\t\t</tr>\n\t\t<tr class="text-center">\n\t\t\t<td><a ng-click="decrementHours()" class="btn btn-link"><span class="glyphicon glyphicon-chevron-down"></span></a></td>\n\t\t\t<td>&nbsp;</td>\n\t\t\t<td><a ng-click="decrementMinutes()" class="btn btn-link"><span class="glyphicon glyphicon-chevron-down"></span></a></td>\n\t\t\t<td ng-show="showMeridian"></td>\n\t\t</tr>\n\t</tbody>\n</table>\n')}]),angular.module("template/typeahead/typeahead-match.html",[]).run(["$templateCache",function(e){e.put("template/typeahead/typeahead-match.html",'<a tabindex="-1" bind-html-unsafe="match.label | typeaheadHighlight:query"></a>')}]),angular.module("template/typeahead/typeahead-popup.html",[]).run(["$templateCache",function(e){e.put("template/typeahead/typeahead-popup.html",'<ul class="dropdown-menu" ng-show="isOpen()" ng-style="{top: position.top+\'px\', left: position.left+\'px\'}" style="display: block;" role="listbox" aria-hidden="{{!isOpen()}}">\n <li ng-repeat="match in matches track by $index" ng-class="{active: isActive($index) }" ng-mouseenter="selectActive($index)" ng-click="selectMatch($index)" role="option" id="{{match.id}}">\n <div typeahead-match index="$index" match="match" query="query" template-url="templateUrl"></div>\n </li>\n</ul>\n')}]),"undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="ui.router"),function(e,t,n){"use strict";function i(e,t){return j(new(j(function(){},{prototype:e})),t)}function r(e){return N(arguments,function(t){t!==e&&N(t,function(t,n){e.hasOwnProperty(n)||(e[n]=t)})}),e}function o(e,t){var n=[];for(var i in e.path){if(e.path[i]!==t.path[i])break;n.push(e.path[i])}return n}function a(e){if(Object.keys)return Object.keys(e);var n=[];return t.forEach(e,function(e,t){n.push(t)}),n}function s(e,t){if(Array.prototype.indexOf)return e.indexOf(t,Number(arguments[2])||0);var n=e.length>>>0,i=Number(arguments[2])||0;for(i=i<0?Math.ceil(i):Math.floor(i),i<0&&(i+=n);i<n;i++)if(i in e&&e[i]===t)return i;return-1}function l(e,t,n,i){var r,l=o(n,i),c={},u=[]
+;for(var d in l)if(l[d].params&&(r=a(l[d].params),r.length))for(var f in r)s(u,r[f])>=0||(u.push(r[f]),c[r[f]]=e[r[f]]);return j({},c,t)}function c(e,t,n){if(!n){n=[];for(var i in e)n.push(i)}for(var r=0;r<n.length;r++){var o=n[r];if(e[o]!=t[o])return!1}return!0}function u(e,t){var n={};return N(e,function(e){n[e]=t[e]}),n}function d(e,t){var i=1,o=2,a={},s=[],l=a,c=j(e.when(a),{$$promises:a,$$values:a});this.study=function(a){function u(e,n){if(h[n]!==o){if(p.push(n),h[n]===i)throw p.splice(0,p.indexOf(n)),new Error("Cyclic dependency: "+p.join(" -> "));if(h[n]=i,O(e))f.push(n,[function(){return t.get(e)}],s);else{var r=t.annotate(e);N(r,function(e){e!==n&&a.hasOwnProperty(e)&&u(a[e],e)}),f.push(n,e,r)}p.pop(),h[n]=o}}function d(e){return I(e)&&e.then&&e.$$promises}if(!I(a))throw new Error("'invocables' must be an object");var f=[],p=[],h={};return N(a,u),a=p=h=null,function(i,o,a){function s(){--v||($||r(m,o.$$values),h.$$values=m,h.$$promises=!0,delete h.$$inheritedValues,p.resolve(m))}function u(e){h.$$failure=e,p.reject(e)}if(d(i)&&a===n&&(a=o,o=i,i=null),i){if(!I(i))throw new Error("'locals' must be an object")}else i=l;if(o){if(!d(o))throw new Error("'parent' must be a promise returned by $resolve.resolve()")}else o=c;var p=e.defer(),h=p.promise,g=h.$$promises={},m=j({},i),v=1+f.length/3,$=!1;if(A(o.$$failure))return u(o.$$failure),h;o.$$inheritedValues&&r(m,o.$$inheritedValues),o.$$values?($=r(m,o.$$values),h.$$inheritedValues=o.$$values,s()):(o.$$inheritedValues&&(h.$$inheritedValues=o.$$inheritedValues),j(g,o.$$promises),o.then(s,u));for(var y=0,b=f.length;y<b;y+=3)i.hasOwnProperty(f[y])?s():function(n,r,o){function l(e){d.reject(e),u(e)}function c(){if(!A(h.$$failure))try{d.resolve(t.invoke(r,a,m)),d.promise.then(function(e){m[n]=e,s()},l)}catch(e){l(e)}}var d=e.defer(),f=0;N(o,function(e){g.hasOwnProperty(e)&&!i.hasOwnProperty(e)&&(f++,g[e].then(function(t){m[e]=t,--f||c()},l))}),f||c(),g[n]=d.promise}(f[y],f[y+1],f[y+2]);return h}},this.resolve=function(e,t,n,i){return this.study(e)(t,n,i)}}function f(e,t,n){this.fromConfig=function(e,t,n){return A(e.template)?this.fromString(e.template,t):A(e.templateUrl)?this.fromUrl(e.templateUrl,t):A(e.templateProvider)?this.fromProvider(e.templateProvider,t,n):null},this.fromString=function(e,t){return M(e)?e(t):e},this.fromUrl=function(n,i){return M(n)&&(n=n(i)),null==n?null:e.get(n,{cache:t}).then(function(e){return e.data})},this.fromProvider=function(e,t,i){return n.invoke(e,null,i||{params:t})}}function p(e,i){function r(e){return A(e)?this.type.decode(e):g.$$getDefaultValue(this)}function o(t,n,i){if(!/^\w+(-+\w+)*$/.test(t))throw new Error("Invalid parameter name '"+t+"' in pattern '"+e+"'");if(p[t])throw new Error("Duplicate parameter name '"+t+"' in pattern '"+e+"'");p[t]=j({type:n||new h,$value:r},i)}function a(e,t,n){var i=e.replace(/[\\\[\]\^$*+?.()|{}]/g,"\\$&");if(!t)return i;var r=n?"?":"";return i+r+"("+t+")"+r}function s(e){if(!i.params||!i.params[e])return{};var t=i.params[e];return I(t)?t:{value:t}}i=t.isObject(i)?i:{};var l,c=/([:*])(\w+)|\{(\w+)(?:\:((?:[^{}\\]+|\\.|\{(?:[^{}\\]+|\\.)*\})+))?\}/g,u="^",d=0,f=this.segments=[],p=this.params={};this.source=e;for(var m,v,$,y,b;(l=c.exec(e))&&(m=l[2]||l[3],v=l[4]||("*"==l[1]?".*":"[^/]*"),$=e.substring(d,l.index),y=this.$types[v]||new h({pattern:new RegExp(v)}),b=s(m),!($.indexOf("?")>=0));)u+=a($,y.$subPattern(),A(b.value)),o(m,y,b),f.push($),d=c.lastIndex;$=e.substring(d);var w=$.indexOf("?");if(w>=0){var x=this.sourceSearch=$.substring(w);$=$.substring(0,w),this.sourcePath=e.substring(0,d+w),N(x.substring(1).split(/[&?]/),function(e){o(e,null,s(e))})}else this.sourcePath=e,this.sourceSearch="";u+=a($)+(!1===i.strict?"/?":"")+"$",f.push($),this.regexp=new RegExp(u,i.caseInsensitive?"i":n),this.prefix=f[0]}function h(e){j(this,e)}function g(){function e(){return{strict:o,caseInsensitive:r}}function t(e){return M(e)||P(e)&&M(e[e.length-1])}function n(){N(s,function(e){if(p.prototype.$types[e.name])throw new Error("A type named '"+e.name+"' has already been defined.");var n=new h(t(e.def)?i.invoke(e.def):e.def);p.prototype.$types[e.name]=n})}var i,r=!1,o=!0,a=!0,s=[],l={int:{decode:function(e){return parseInt(e,10)},is:function(e){return!!A(e)&&this.decode(e.toString())===e},pattern:/\d+/},bool:{encode:function(e){return e?1:0},decode:function(e){return 0!==parseInt(e,10)},is:function(e){return!0===e||!1===e},pattern:/0|1/},string:{pattern:/[^\/]*/},date:{equals:function(e,t){return e.toISOString()===t.toISOString()},decode:function(e){return new Date(e)},encode:function(e){return[e.getFullYear(),("0"+(e.getMonth()+1)).slice(-2),("0"+e.getDate()).slice(-2)].join("-")},pattern:/[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[0-1])/}};g.$$getDefaultValue=function(e){if(!t(e.value))return e.value;if(!i)throw new Error("Injectable functions cannot be called at configuration time");return i.invoke(e.value)},this.caseInsensitive=function(e){r=e},this.strictMode=function(e){o=e},this.compile=function(t,n){return new p(t,j(e(),n))},this.isMatcher=function(e){if(!I(e))return!1;var t=!0;return N(p.prototype,function(n,i){M(n)&&(t=t&&A(e[i])&&M(e[i]))}),t},this.type=function(e,t){return A(t)?(s.push({name:e,def:t}),a||n(),this):p.prototype.$types[e]},this.$get=["$injector",function(e){return i=e,a=!1,p.prototype.$types={},n(),N(l,function(e,t){p.prototype.$types[t]||(p.prototype.$types[t]=new h(e))}),this}]}function m(e,t){function i(e){var t=/^\^((?:\\[^a-zA-Z0-9]|[^\\\[\]\^$*+?.()|{}]+)*)/.exec(e.source);return null!=t?t[1].replace(/\\(.)/g,"$1"):""}function r(e,t){return e.replace(/\$(\$|\d{1,2})/,function(e,n){return t["$"===n?0:Number(n)]})}function o(e,t,n){if(!n)return!1;var i=e.invoke(t,t,{$match:n});return!A(i)||i}function a(t,n,i,r){function o(e,t,n){return"/"===f?e:t?f.slice(0,-1)+e:n?f.slice(1)+e:e}function a(e){function n(e){var n=e(i,t);return!!n&&(O(n)&&t.replace().url(n),!0)}if(!e||!e.defaultPrevented){var r,o=l.length;for(r=0;r<o;r++)if(n(l[r]))return;c&&n(c)}}function d(){return s=s||n.$on("$locationChangeSuccess",a)}var f=r.baseHref(),p=t.url();return u||d(),{sync:function(){a()},listen:function(){return d()},update:function(e){if(e)return void(p=t.url());t.url()!==p&&(t.url(p),t.replace())},push:function(e,n,i){t.url(e.format(n||{})),i&&i.replace&&t.replace()},href:function(n,i,r){if(!n.validates(i))return null;var a=e.html5Mode(),s=n.format(i);if(r=r||{},a||null===s||(s="#"+e.hashPrefix()+s),s=o(s,a,r.absolute),!r.absolute||!s)return s;var l=!a&&s?"/":"",c=t.port();return c=80===c||443===c?"":":"+c,[t.protocol(),"://",t.host(),c,l,s].join("")}}}var s,l=[],c=null,u=!1;this.rule=function(e){if(!M(e))throw new Error("'rule' must be a function");return l.push(e),this},this.otherwise=function(e){if(O(e)){var t=e;e=function(){return t}}else if(!M(e))throw new Error("'rule' must be a function");return c=e,this},this.when=function(e,n){var a,s=O(n);if(O(e)&&(e=t.compile(e)),!s&&!M(n)&&!P(n))throw new Error("invalid 'handler' in when()");var l={matcher:function(e,n){return s&&(a=t.compile(n),n=["$match",function(e){return a.format(e)}]),j(function(t,i){return o(t,n,e.exec(i.path(),i.search()))},{prefix:O(e.prefix)?e.prefix:""})},regex:function(e,t){if(e.global||e.sticky)throw new Error("when() RegExp must not be global or sticky");return s&&(a=t,t=["$match",function(e){return r(a,e)}]),j(function(n,i){return o(n,t,e.exec(i.path()))},{prefix:i(e)})}},c={matcher:t.isMatcher(e),regex:e instanceof RegExp};for(var u in c)if(c[u])return this.rule(l[u](e,n));throw new Error("invalid 'what' in when()")},this.deferIntercept=function(e){e===n&&(e=!0),u=e},this.$get=a,a.$inject=["$location","$rootScope","$injector","$browser"]}function v(e,r){function o(e){return 0===e.indexOf(".")||0===e.indexOf("^")}function s(e,t){if(!e)return n;var i=O(e),r=i?e:e.name;if(o(r)){if(!t)throw new Error("No reference point given for path '"+r+"'");for(var a=r.split("."),s=0,l=a.length,c=t;s<l;s++)if(""!==a[s]||0!==s){if("^"!==a[s])break;if(!c.parent)throw new Error("Path '"+r+"' not valid for state '"+t.name+"'");c=c.parent}else c=t;a=a.slice(s).join("."),r=c.name+(c.name&&a?".":"")+a}var u=w[r];return!u||!i&&(i||u!==e&&u.self!==e)?n:u}function d(e,t){x[e]||(x[e]=[]),x[e].push(t)}function f(t){t=i(t,{self:t,resolve:t.resolve||{},toString:function(){return this.name}});var n=t.name;if(!O(n)||n.indexOf("@")>=0)throw new Error("State must have a valid name");if(w.hasOwnProperty(n))throw new Error("State '"+n+"'' is already defined");var r=-1!==n.indexOf(".")?n.substring(0,n.lastIndexOf(".")):O(t.parent)?t.parent:"";if(r&&!w[r])return d(r,t.self);for(var o in k)M(k[o])&&(t[o]=k[o](t,k.$delegates[o]));if(w[n]=t,!t[C]&&t.url&&e.when(t.url,["$match","$stateParams",function(e,n){b.$current.navigable==t&&c(e,n)||b.transitionTo(t,e,{location:!1})}]),x[n])for(var a=0;a<x[n].length;a++)f(x[n][a]);return t}function p(e){return e.indexOf("*")>-1}function h(e){var t=e.split("."),n=b.$current.name.split(".");if("**"===t[0]&&(n=n.slice(n.indexOf(t[1])),n.unshift("**")),"**"===t[t.length-1]&&(n.splice(n.indexOf(t[t.length-2])+1,Number.MAX_VALUE),n.push("**")),t.length!=n.length)return!1;for(var i=0,r=t.length;i<r;i++)"*"===t[i]&&(n[i]="*");return n.join("")===t.join("")}function g(e,t){return O(e)&&!A(t)?k[e]:M(t)&&O(e)?(k[e]&&!k.$delegates[e]&&(k.$delegates[e]=k[e]),k[e]=t,this):this}function m(e,t){return I(e)?t=e:t.name=e,f(t),this}function v(e,r,o,d,f,g,m){function v(t,n,i,o){var a=e.$broadcast("$stateNotFound",t,n,i);if(a.defaultPrevented)return m.update(),E;if(!a.retry)return null;if(o.$retry)return m.update(),T;var s=b.transition=r.when(a.retry);return s.then(function(){return s!==b.transition?k:(t.options.$retry=!0,b.transitionTo(t.to,t.toParams,t.options))},function(){return E}),m.update(),s}function x(e,n,i,s,l){var c=i?n:u(a(e.params),n),p={$stateParams:c};l.resolve=f.resolve(e.resolve,p,l.resolve,e);var h=[l.resolve.then(function(e){l.globals=e})];return s&&h.push(s),N(e.views,function(n,i){var r=n.resolve&&n.resolve!==e.resolve?n.resolve:{};r.$template=[function(){return o.load(i,{view:n,locals:p,params:c})||""}],h.push(f.resolve(r,p,l.resolve,e).then(function(o){if(M(n.controllerProvider)||P(n.controllerProvider)){var a=t.extend({},r,p);o.$$controller=d.invoke(n.controllerProvider,null,a)}else o.$$controller=n.controller;o.$$state=e,o.$$controllerAs=n.controllerAs,l[i]=o}))}),r.all(h).then(function(e){return l})}var k=r.reject(new Error("transition superseded")),S=r.reject(new Error("transition prevented")),E=r.reject(new Error("transition aborted")),T=r.reject(new Error("transition failed"));return y.locals={resolve:null,globals:{$stateParams:{}}},b={params:{},current:y.self,$current:y,transition:null},b.reload=function(){b.transitionTo(b.current,g,{reload:!0,inherit:!1,notify:!1})},b.go=function(e,t,n){return b.transitionTo(e,t,j({inherit:!0,relative:b.$current},n))},b.transitionTo=function(t,n,o){n=n||{},o=j({location:!0,inherit:!1,relative:null,notify:!0,reload:!1,$retry:!1},o||{});var f,p=b.$current,h=b.params,w=p.path,E=s(t,o.relative);if(!A(E)){var T={to:t,toParams:n,options:o},D=v(T,p.self,h,o);if(D)return D;if(t=T.to,n=T.toParams,o=T.options,E=s(t,o.relative),!A(E)){if(!o.relative)throw new Error("No such state '"+t+"'");throw new Error("Could not resolve '"+t+"' from state '"+o.relative+"'")}}if(E[C])throw new Error("Cannot transition to abstract state '"+t+"'");o.inherit&&(n=l(g,n||{},b.$current,E)),t=E;var M=t.path,O=0,I=M[O],P=y.locals,N=[];if(!o.reload)for(;I&&I===w[O]&&c(n,h,I.ownParams);)P=N[O]=I.locals,O++,I=M[O];if($(t,p,P,o))return!1!==t.self.reloadOnSearch&&m.update(),b.transition=null,r.when(b.current);if(n=u(a(t.params),n||{}),o.notify&&e.$broadcast("$stateChangeStart",t.self,n,p.self,h).defaultPrevented)return m.update(),S;for(var L=r.when(P),R=O;R<M.length;R++,I=M[R])P=N[R]=i(P),L=x(I,n,I===t,L,P);var V=b.transition=L.then(function(){var i,r,a;if(b.transition!==V)return k;for(i=w.length-1;i>=O;i--)a=w[i],a.self.onExit&&d.invoke(a.self.onExit,a.self,a.locals.globals),a.locals=null;for(i=O;i<M.length;i++)r=M[i],r.locals=N[i],r.self.onEnter&&d.invoke(r.self.onEnter,r.self,r.locals.globals);return b.transition!==V?k:(b.$current=t,b.current=t.self,b.params=n,F(b.params,g),b.transition=null,o.location&&t.navigable&&m.push(t.navigable.url,t.navigable.locals.globals.$stateParams,{replace:"replace"===o.location}),o.notify&&e.$broadcast("$stateChangeSuccess",t.self,n,p.self,h),m.update(!0),b.current)},function(i){return b.transition!==V?k:(b.transition=null,f=e.$broadcast("$stateChangeError",t.self,n,p.self,h,i),f.defaultPrevented||m.update(),r.reject(i))});return V},b.is=function(e,i){var r=s(e);return A(r)?b.$current===r&&(!A(i)||null===i||t.equals(g,i)):n},b.includes=function(e,t){if(O(e)&&p(e)){if(!h(e))return!1;e=b.$current.name}var i=s(e);return A(i)?!!A(b.$current.includes[i.name])&&c(t,g):n},b.href=function(e,t,n){n=j({lossy:!0,inherit:!0,absolute:!1,relative:b.$current},n||{});var i=s(e,n.relative);if(!A(i))return null;n.inherit&&(t=l(g,t||{},b.$current,i));var r=i&&n.lossy?i.navigable:i;return r&&r.url?m.href(r.url,u(a(i.params),t||{}),{absolute:n.absolute}):null},b.get=function(e,t){if(0===arguments.length)return a(w).map(function(e){return w[e].self});var n=s(e,t);return n&&n.self?n.self:null},b}function $(e,t,n,i){if(e===t&&(n===t.locals&&!i.reload||!1===e.self.reloadOnSearch))return!0}var y,b,w={},x={},C="abstract",k={parent:function(e){if(A(e.parent)&&e.parent)return s(e.parent);var t=/^(.+)\.[^.]+$/.exec(e.name);return t?s(t[1]):y},data:function(e){return e.parent&&e.parent.data&&(e.data=e.self.data=j({},e.parent.data,e.data)),e.data},url:function(e){var t=e.url,n={params:e.params||{}};if(O(t))return"^"==t.charAt(0)?r.compile(t.substring(1),n):(e.parent.navigable||y).url.concat(t,n);if(!t||r.isMatcher(t))return t;throw new Error("Invalid url '"+t+"' in state '"+e+"'")},navigable:function(e){return e.url?e:e.parent?e.parent.navigable:null},params:function(e){return e.params?e.params:e.url?e.url.params:e.parent.params},views:function(e){var t={};return N(A(e.views)?e.views:{"":e},function(n,i){i.indexOf("@")<0&&(i+="@"+e.parent.name),t[i]=n}),t},ownParams:function(e){if(e.params=e.params||{},!e.parent)return a(e.params);var t={};N(e.params,function(e,n){t[n]=!0}),N(e.parent.params,function(n,i){if(!t[i])throw new Error("Missing required parameter '"+i+"' in state '"+e.name+"'");t[i]=!1});var n=[];return N(t,function(e,t){e&&n.push(t)}),n},path:function(e){return e.parent?e.parent.path.concat(e):[]},includes:function(e){var t=e.parent?j({},e.parent.includes):{};return t[e.name]=!0,t},$delegates:{}};y=f({name:"",url:"^",views:null,abstract:!0}),y.navigable=null,this.decorator=g,this.state=m,this.$get=v,v.$inject=["$rootScope","$q","$view","$injector","$resolve","$stateParams","$urlRouter"]}function $(){function e(e,t){return{load:function(n,i){var r;return i=j({template:null,controller:null,view:null,locals:null,notify:!0,async:!0,params:{}},i),i.view&&(r=t.fromConfig(i.view,i.params,i.locals)),r&&i.notify&&e.$broadcast("$viewContentLoading",i),r}}}this.$get=e,e.$inject=["$rootScope","$templateFactory"]}function y(){var e=!1;this.useAnchorScroll=function(){e=!0},this.$get=["$anchorScroll","$timeout",function(t,n){return e?t:function(e){n(function(){e[0].scrollIntoView()},0,!1)}}]}function b(e,n,i){function r(e,t){if(s)return{enter:function(e,t,n){s.enter(e,null,t,n)},leave:function(e,t){s.leave(e,t)}};if(a){var n=a&&a(t,e);return{enter:function(e,t,i){n.enter(e,null,t),i()},leave:function(e,t){n.leave(e),t()}}}return function(){return{enter:function(e,t,n){t.after(e),n()},leave:function(e,t){e.remove(),t()}}}()}var o=function(){return n.has?function(e){return n.has(e)?n.get(e):null}:function(e){try{return n.get(e)}catch(e){return null}}}(),a=o("$animator"),s=o("$animate");return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",compile:function(n,o,a){return function(n,o,s){function l(){u&&(u.remove(),u=null),f&&(f.$destroy(),f=null),d&&(m.leave(d,function(){u=null}),u=d,d=null)}function c(r){var c,u=x(s,o.inheritedData("$uiView")),v=u&&e.$current&&e.$current.locals[u];if(r||v!==p){c=n.$new(),p=e.$current.locals[u];var $=a(c,function(e){m.enter(e,o,function(){(t.isDefined(g)&&!g||n.$eval(g))&&i(e)}),l()});d=$,f=c,f.$emit("$viewContentLoaded"),f.$eval(h)}}var u,d,f,p,h=s.onload||"",g=s.autoscroll,m=r(s,n);n.$on("$stateChangeSuccess",function(){c(!1)}),n.$on("$viewContentLoading",function(){c(!1)}),c(!0)}}}}function w(e,t,n){return{restrict:"ECA",priority:-400,compile:function(i){var r=i.html();return function(i,o,a){var s=n.$current,l=x(a,o.inheritedData("$uiView")),c=s&&s.locals[l];if(c){o.data("$uiView",{name:l,state:c.$$state}),o.html(c.$template?c.$template:r);var u=e(o.contents());if(c.$$controller){c.$scope=i;var d=t(c.$$controller,c);c.$$controllerAs&&(i[c.$$controllerAs]=d),o.data("$ngControllerController",d),o.children().data("$ngControllerController",d)}u(i)}}}}}function x(e,t){var n=e.uiView||e.name||"";return n.indexOf("@")>=0?n:n+"@"+(t?t.state.name:"")}function C(e,t){var n,i=e.match(/^\s*({[^}]*})\s*$/);if(i&&(e=t+"("+i[1]+")"),!(n=e.replace(/\n/g," ").match(/^([^(]+?)\s*(\((.*)\))?$/))||4!==n.length)throw new Error("Invalid state ref '"+e+"'");return{state:n[1],paramExpr:n[3]||null}}function k(e){var t=e.parent().inheritedData("$uiView");if(t&&t.state&&t.state.name)return t.state}function S(e,n){var i=["location","inherit","reload"];return{restrict:"A",require:["?^uiSrefActive","?^uiSrefActiveEq"],link:function(r,o,a,s){var l=C(a.uiSref,e.current.name),c=null,u=k(o)||e.$current,d="FORM"===o[0].nodeName,f=d?"action":"href",p=!0,h={relative:u,inherit:!0},g=r.$eval(a.uiSrefOpts)||{};t.forEach(i,function(e){e in g&&(h[e]=g[e])});var m=function(t){if(t&&(c=t),p){var n=e.href(l.state,c,h),i=s[1]||s[0];if(i&&i.$$setStateInfo(l.state,c),null===n)return p=!1,!1;o[0][f]=n}};l.paramExpr&&(r.$watch(l.paramExpr,function(e,t){e!==c&&m(e)},!0),c=r.$eval(l.paramExpr)),m(),d||o.bind("click",function(t){if(!((t.which||t.button)>1||t.ctrlKey||t.metaKey||t.shiftKey||o.attr("target"))){var i=n(function(){e.go(l.state,c,h)});t.preventDefault(),t.preventDefault=function(){n.cancel(i)}}})}}}function E(e,t,n){return{restrict:"A",controller:["$scope","$element","$attrs",function(i,r,o){function a(){s()?r.addClass(f):r.removeClass(f)}function s(){return void 0!==o.uiSrefActiveEq?e.$current.self===u&&l():e.includes(u.name)&&l()}function l(){return!d||c(d,t)}var u,d,f;f=n(o.uiSrefActiveEq||o.uiSrefActive||"",!1)(i),this.$$setStateInfo=function(t,n){u=e.get(t,k(r)),d=n,a()},i.$on("$stateChangeSuccess",a)}]}}function T(e){return function(t){return e.is(t)}}function D(e){return function(t){return e.includes(t)}}var A=t.isDefined,M=t.isFunction,O=t.isString,I=t.isObject,P=t.isArray,N=t.forEach,j=t.extend,F=t.copy;t.module("ui.router.util",["ng"]),t.module("ui.router.router",["ui.router.util"]),t.module("ui.router.state",["ui.router.router","ui.router.util"]),t.module("ui.router",["ui.router.state"]),t.module("ui.router.compat",["ui.router"]),d.$inject=["$q","$injector"],t.module("ui.router.util").service("$resolve",d),f.$inject=["$http","$templateCache","$injector"],t.module("ui.router.util").service("$templateFactory",f),p.prototype.concat=function(e,t){return new p(this.sourcePath+e+this.sourceSearch,t)},p.prototype.toString=function(){return this.source},p.prototype.exec=function(e,t){var n=this.regexp.exec(e);if(!n)return null;t=t||{};var i,r,o,a=this.parameters(),s=a.length,l=this.segments.length-1,c={};if(l!==n.length-1)throw new Error("Unbalanced capture group in route '"+this.source+"'");for(i=0;i<l;i++)o=a[i],r=this.params[o],c[o]=r.$value(n[i+1]);for(;i<s;i++)o=a[i],r=this.params[o],c[o]=r.$value(t[o]);return c},p.prototype.parameters=function(e){return A(e)?this.params[e]||null:a(this.params)},p.prototype.validates=function(e){var t,n,i=!0,r=this;return N(e,function(e,o){r.params[o]&&(n=r.params[o],t=!e&&A(n.value),i=i&&(t||n.type.is(e)))}),i},p.prototype.format=function(e){var t=this.segments,n=this.parameters();if(!e)return t.join("").replace("//","/");var i,r,o,a,s,l,c=t.length-1,u=n.length,d=t[0];if(!this.validates(e))return null;for(i=0;i<c;i++)a=n[i],o=e[a],s=this.params[a],(A(o)||"/"!==t[i]&&"/"!==t[i+1])&&(null!=o&&(d+=encodeURIComponent(s.type.encode(o))),d+=t[i+1]);for(;i<u;i++)a=n[i],null!=(o=e[a])&&(l=P(o),l&&(o=o.map(encodeURIComponent).join("&"+a+"=")),d+=(r?"&":"?")+a+"="+(l?o:encodeURIComponent(o)),r=!0);return d},p.prototype.$types={},h.prototype.is=function(e,t){return!0},h.prototype.encode=function(e,t){return e},h.prototype.decode=function(e,t){return e},h.prototype.equals=function(e,t){return e==t},h.prototype.$subPattern=function(){var e=this.pattern.toString();return e.substr(1,e.length-2)},h.prototype.pattern=/.*/,t.module("ui.router.util").provider("$urlMatcherFactory",g),m.$inject=["$locationProvider","$urlMatcherFactoryProvider"],t.module("ui.router.router").provider("$urlRouter",m),v.$inject=["$urlRouterProvider","$urlMatcherFactoryProvider"],t.module("ui.router.state").value("$stateParams",{}).provider("$state",v),$.$inject=[],t.module("ui.router.state").provider("$view",$),t.module("ui.router.state").provider("$uiViewScroll",y),b.$inject=["$state","$injector","$uiViewScroll"],w.$inject=["$compile","$controller","$state"],t.module("ui.router.state").directive("uiView",b),t.module("ui.router.state").directive("uiView",w),S.$inject=["$state","$timeout"],E.$inject=["$state","$stateParams","$interpolate"],t.module("ui.router.state").directive("uiSref",S).directive("uiSrefActive",E).directive("uiSrefActiveEq",E),T.$inject=["$state"],D.$inject=["$state"],t.module("ui.router.state").filter("isState",T).filter("includedByState",D)}(window,window.angular),angular.module("pascalprecht.translate",["ng"]).run(["$translate",function(e){var t=e.storageKey(),n=e.storage();n?n.get(t)?e.use(n.get(t)):angular.isString(e.preferredLanguage())?e.use(e.preferredLanguage()):n.set(t,e.use()):angular.isString(e.preferredLanguage())&&e.use(e.preferredLanguage())}]),angular.module("pascalprecht.translate").provider("$translate",["$STORAGE_KEY",function(e){var t,n,i,r,o,a,s,l,c,u,d,f,p,h,g,m={},v=[],$=e,y=[],b=!1,w="translate-cloak",x=!1,C=function(){var e=window.navigator;return((angular.isArray(e.languages)?e.languages[0]:e.language||e.browserLanguage||e.systemLanguage||e.userLanguage)||"").split("-").join("_")},k=function(e,t){for(var n=0,i=e.length;n<i;n++)if(e[n]===t)return n;return-1},S=function(){return this.replace(/^\s+|\s+$/g,"")},E=function(e){for(var t=[],i=angular.lowercase(e),r=0,o=v.length;r<o;r++)t.push(angular.lowercase(v[r]));if(k(t,i)>-1)return e;if(n){var a;for(var s in n){var l=!1,c=Object.prototype.hasOwnProperty.call(n,s)&&angular.lowercase(s)===angular.lowercase(e);if("*"===s.slice(-1)&&(l=s.slice(0,-1)===e.slice(0,s.length-1)),(c||l)&&(a=n[s],k(t,angular.lowercase(a))>-1))return a}}var u=e.split("_");return u.length>1&&k(t,angular.lowercase(u[0]))>-1?u[0]:e},T=function(e,t){if(!e&&!t)return m;if(e&&!t){if(angular.isString(e))return m[e]}else angular.isObject(m[e])||(m[e]={}),angular.extend(m[e],D(t));return this};this.translations=T,this.cloakClassName=function(e){return e?(w=e,this):w};var D=function(e,t,n,i){var r,o,a,s;t||(t=[]),n||(n={});for(r in e)Object.prototype.hasOwnProperty.call(e,r)&&(s=e[r],angular.isObject(s)?D(s,t.concat(r),n,r):(o=t.length?t.join(".")+"."+r:r,t.length&&r===i&&(a=""+t.join("."),n[a]="@:"+o),n[o]=s));return n};this.addInterpolation=function(e){return y.push(e),this},this.useMessageFormatInterpolation=function(){return this.useInterpolation("$translateMessageFormatInterpolation")},this.useInterpolation=function(e){return u=e,this},this.useSanitizeValueStrategy=function(e){return b=e,this},this.preferredLanguage=function(e){return A(e),this};var A=function(e){return e&&(t=e),t};this.translationNotFoundIndicator=function(e){return this.translationNotFoundIndicatorLeft(e),this.translationNotFoundIndicatorRight(e),this},this.translationNotFoundIndicatorLeft=function(e){return e?(p=e,this):p},this.translationNotFoundIndicatorRight=function(e){return e?(h=e,this):h},this.fallbackLanguage=function(e){return M(e),this};var M=function(e){return e?(angular.isString(e)?(r=!0,i=[e]):angular.isArray(e)&&(r=!1,i=e),angular.isString(t)&&k(i,t)<0&&i.push(t),this):r?i[0]:i};this.use=function(e){if(e){if(!m[e]&&!d)throw new Error("$translateProvider couldn't find translationTable for langKey: '"+e+"'");return o=e,this}return o};var O=function(e){if(!e)return l?l+$:$;$=e};this.storageKey=O,this.useUrlLoader=function(e,t){return this.useLoader("$translateUrlLoader",angular.extend({url:e},t))},this.useStaticFilesLoader=function(e){return this.useLoader("$translateStaticFilesLoader",e)},this.useLoader=function(e,t){return d=e,f=t||{},this},this.useLocalStorage=function(){return this.useStorage("$translateLocalStorage")},this.useCookieStorage=function(){return this.useStorage("$translateCookieStorage")},this.useStorage=function(e){return s=e,this},this.storagePrefix=function(e){return e?(l=e,this):e},this.useMissingTranslationHandlerLog=function(){return this.useMissingTranslationHandler("$translateMissingTranslationHandlerLog")},this.useMissingTranslationHandler=function(e){return c=e,this},this.usePostCompiling=function(e){return x=!!e,this},this.determinePreferredLanguage=function(e){var n=e&&angular.isFunction(e)?e():C();return t=v.length?E(n):n,this},this.registerAvailableLanguageKeys=function(e,t){return e?(v=e,t&&(n=t),this):v},this.useLoaderCache=function(e){return!1===e?g=void 0:!0===e?g=!0:void 0===e?g="$translationCache":e&&(g=e),this},this.$get=["$log","$injector","$rootScope","$q",function(e,n,l,v){var C,I,P,N=n.get(u||"$translateDefaultInterpolation"),j=!1,F={},L={},R=function(e,n,r){if(angular.isArray(e)){return function(e){for(var t={},i=[],o=0,a=e.length;o<a;o++)i.push(function(e){var i=v.defer(),o=function(n){t[e]=n,i.resolve([e,n])};return R(e,n,r).then(o,o),i.promise}(e[o]));return v.all(i).then(function(){return t})}(e)}var a=v.defer();e&&(e=S.apply(e));var l=function(){var e=t?L[t]:L[o];if(I=0,s&&!e){var n=C.get($);if(e=L[n],i&&i.length){var r=k(i,n);I=0===r?1:0,k(i,t)<0&&i.push(t)}}return e}();return l?l.then(function(){X(e,n,r).then(a.resolve,a.reject)},a.reject):X(e,n,r).then(a.resolve,a.reject),a.promise},V=function(e){return p&&(e=[p,e].join(" ")),h&&(e=[e,h].join(" ")),e},H=function(e){o=e,l.$emit("$translateChangeSuccess",{language:e}),s&&C.set(R.storageKey(),o),N.setLocale(o),angular.forEach(F,function(e,t){F[t].setLocale(o)}),l.$emit("$translateChangeEnd",{language:e})},q=function(e){if(!e)throw"No language key specified for loading.";var t=v.defer();l.$emit("$translateLoadingStart",{language:e}),j=!0;var i=g;"string"==typeof i&&(i=n.get(i));var r=angular.extend({},f,{key:e,$http:angular.extend({},{cache:i},f.$http)});return n.get(d)(r).then(function(n){var i={};l.$emit("$translateLoadingSuccess",{language:e}),angular.isArray(n)?angular.forEach(n,function(e){angular.extend(i,D(e))}):angular.extend(i,D(n)),j=!1,t.resolve({key:e,table:i}),l.$emit("$translateLoadingEnd",{language:e})},function(e){l.$emit("$translateLoadingError",{language:e}),t.reject(e),l.$emit("$translateLoadingEnd",{language:e})}),t.promise};if(s&&(C=n.get(s),!C.get||!C.set))throw new Error("Couldn't use storage '"+s+"', missing get() or set() method!");angular.isFunction(N.useSanitizeValueStrategy)&&N.useSanitizeValueStrategy(b),y.length&&angular.forEach(y,function(e){var i=n.get(e);i.setLocale(t||o),angular.isFunction(i.useSanitizeValueStrategy)&&i.useSanitizeValueStrategy(b),F[i.getInterpolationIdentifier()]=i});var U=function(e){var t=v.defer();return Object.prototype.hasOwnProperty.call(m,e)?t.resolve(m[e]):L[e]?L[e].then(function(e){T(e.key,e.table),t.resolve(e.table)},t.reject):t.reject(),t.promise},_=function(e,t,n,i){var r=v.defer();return U(e).then(function(a){Object.prototype.hasOwnProperty.call(a,t)?(i.setLocale(e),r.resolve(i.interpolate(a[t],n)),i.setLocale(o)):r.reject()},r.reject),r.promise},B=function(e,t,n,i){var r,a=m[e];return Object.prototype.hasOwnProperty.call(a,t)&&(i.setLocale(e),r=i.interpolate(a[t],n),i.setLocale(o)),r},W=function(e){if(c){var t=n.get(c)(e,o);return void 0!==t?t:e}return e},z=function(e,t,n,r){var o=v.defer();if(e<i.length){var a=i[e];_(a,t,n,r).then(o.resolve,function(){z(e+1,t,n,r).then(o.resolve)})}else o.resolve(W(t));return o.promise},Y=function(e,t,n,r){var o;if(e<i.length){var a=i[e];o=B(a,t,n,r),o||(o=Y(e+1,t,n,r))}return o},K=function(e,t,n){return z(P>0?P:I,e,t,n)},G=function(e,t,n){return Y(P>0?P:I,e,t,n)},X=function(e,t,n){var r=v.defer(),a=o?m[o]:m,s=n?F[n]:N;if(a&&Object.prototype.hasOwnProperty.call(a,e)){var l=a[e];"@:"===l.substr(0,2)?R(l.substr(2),t,n).then(r.resolve,r.reject):r.resolve(s.interpolate(l,t))}else{var u;c&&!j&&(u=W(e)),o&&i&&i.length?K(e,t,s).then(function(e){r.resolve(e)},function(e){r.reject(V(e))}):c&&!j&&u?r.resolve(u):r.reject(V(e))}return r.promise},Z=function(e,t,n){var r,a=o?m[o]:m,s=n?F[n]:N;if(a&&Object.prototype.hasOwnProperty.call(a,e)){var l=a[e];r="@:"===l.substr(0,2)?Z(l.substr(2),t,n):s.interpolate(l,t)}else{var u;c&&!j&&(u=W(e)),o&&i&&i.length?(I=0,r=G(e,t,s)):r=c&&!j&&u?u:V(e)}return r};if(R.preferredLanguage=function(e){return e&&A(e),t},R.cloakClassName=function(){return w},R.fallbackLanguage=function(e){if(void 0!==e&&null!==e){if(M(e),d&&i&&i.length)for(var t=0,n=i.length;t<n;t++)L[i[t]]||(L[i[t]]=q(i[t]));R.use(R.use())}return r?i[0]:i},R.useFallbackLanguage=function(e){if(void 0!==e&&null!==e)if(e){var t=k(i,e);t>-1&&(P=t)}else P=0},R.proposedLanguage=function(){return a},R.storage=function(){return C},R.use=function(e){if(!e)return o;var t=v.defer();l.$emit("$translateChangeStart",{language:e});var n=E(e);return n&&(e=n),m[e]||!d||L[e]?(t.resolve(e),H(e)):(a=e,L[e]=q(e).then(function(n){T(n.key,n.table),t.resolve(n.key),H(n.key),a===e&&(a=void 0)},function(e){a===e&&(a=void 0),l.$emit("$translateChangeError",{language:e}),t.reject(e),l.$emit("$translateChangeEnd",{language:e})})),t.promise},R.storageKey=function(){return O()},R.isPostCompilingEnabled=function(){return x},R.refresh=function(e){function t(){r.resolve(),l.$emit("$translateRefreshEnd",{language:e})}function n(){r.reject(),l.$emit("$translateRefreshEnd",{language:e})}if(!d)throw new Error("Couldn't refresh translation table, no loader registered!");var r=v.defer();if(l.$emit("$translateRefreshStart",{language:e}),e)m[e]?q(e).then(function(n){T(n.key,n.table),e===o&&H(o),t()},n):n();else{var a=[],s={};if(i&&i.length)for(var c=0,u=i.length;c<u;c++)a.push(q(i[c])),s[i[c]]=!0;o&&!s[o]&&a.push(q(o)),v.all(a).then(function(e){angular.forEach(e,function(e){m[e.key]&&delete m[e.key],T(e.key,e.table)}),o&&H(o),t()})}return r.promise},R.instant=function(e,n,r){if(null===e||angular.isUndefined(e))return e;if(angular.isArray(e)){for(var a={},s=0,l=e.length;s<l;s++)a[e[s]]=R.instant(e[s],n,r);return a}if(angular.isString(e)&&e.length<1)return e;e&&(e=S.apply(e));var u,d=[];t&&d.push(t),o&&d.push(o),i&&i.length&&(d=d.concat(i));for(var f=0,p=d.length;f<p;f++){var h=d[f];if(m[h]&&void 0!==m[h][e]&&(u=Z(e,n,r)),void 0!==u)break}return u||""===u||(u=N.interpolate(e,n),c&&!j&&(u=W(e))),u},R.versionInfo=function(){return"2.4.1"},R.loaderCache=function(){return g},d&&(angular.equals(m,{})&&R.use(R.use()),i&&i.length))for(var J=function(e){T(e.key,e.table),l.$emit("$translateChangeEnd",{language:e.key})},Q=0,ee=i.length;Q<ee;Q++)L[i[Q]]=q(i[Q]).then(J);return R}]}]),angular.module("pascalprecht.translate").factory("$translateDefaultInterpolation",["$interpolate",function(e){var t,n={},i=null,r={escaped:function(e){var t={};for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=angular.element("<div></div>").text(e[n]).html());return t}},o=function(e){return angular.isFunction(r[i])?r[i](e):e};return n.setLocale=function(e){t=e},n.getInterpolationIdentifier=function(){return"default"},n.useSanitizeValueStrategy=function(e){return i=e,this},n.interpolate=function(t,n){
+return i&&(n=o(n)),e(t)(n||{})},n}]),angular.module("pascalprecht.translate").constant("$STORAGE_KEY","NG_TRANSLATE_LANG_KEY"),angular.module("pascalprecht.translate").directive("translate",["$translate","$q","$interpolate","$compile","$parse","$rootScope",function(e,t,n,i,r,o){return{restrict:"AE",scope:!0,compile:function(t,a){var s=a.translateValues?a.translateValues:void 0,l=a.translateInterpolation?a.translateInterpolation:void 0,c=t[0].outerHTML.match(/translate-value-+/i),u="^(.*)("+n.startSymbol()+".*"+n.endSymbol()+")(.*)";return function(t,d,f){if(t.interpolateParams={},t.preText="",t.postText="",f.$observe("translate",function(e){if(angular.equals(e,"")||!angular.isDefined(e)){var i=d.text().match(u);angular.isArray(i)?(t.preText=i[1],t.postText=i[3],t.translationId=n(i[2])(t.$parent)):t.translationId=d.text().replace(/^\s+|\s+$/g,"")}else t.translationId=e}),f.$observe("translateDefault",function(e){t.defaultText=e}),s&&f.$observe("translateValues",function(e){e&&t.$parent.$watch(function(){angular.extend(t.interpolateParams,r(e)(t.$parent))})}),c){for(var p in f)Object.prototype.hasOwnProperty.call(f,p)&&"translateValue"===p.substr(0,14)&&"translateValues"!==p&&function(e){f.$observe(e,function(n){t.interpolateParams[angular.lowercase(e.substr(14,1))+e.substr(15)]=n})}(p)}var h=function(t,n,r){r||void 0===n.defaultText||(t=n.defaultText),d.html(n.preText+t+n.postText);var o=e.isPostCompilingEnabled(),s=void 0!==a.translateCompile,l=s&&"false"!==a.translateCompile;(o&&!s||l)&&i(d.contents())(n)},g=function(){return s||c?function(){var n=function(){t.translationId&&t.interpolateParams&&e(t.translationId,t.interpolateParams,l).then(function(e){h(e,t,!0)},function(e){h(e,t,!1)})};t.$watch("interpolateParams",n,!0),t.$watch("translationId",n)}:function(){var n=t.$watch("translationId",function(i){t.translationId&&i&&e(i,{},l).then(function(e){h(e,t,!0),n()},function(e){h(e,t,!1),n()})},!0)}}(),m=o.$on("$translateChangeSuccess",g);g(),t.$on("$destroy",m)}}}}]),angular.module("pascalprecht.translate").directive("translateCloak",["$rootScope","$translate",function(e,t){return{compile:function(n){var i=e.$on("$translateChangeEnd",function(){n.removeClass(t.cloakClassName()),i(),i=null});n.addClass(t.cloakClassName())}}}]),angular.module("pascalprecht.translate").filter("translate",["$parse","$translate",function(e,t){var n=function(n,i,r){return angular.isObject(i)||(i=e(i)(this)),t.instant(n,i,r)};return n.$stateful=!0,n}]),function(e,t){"function"==typeof define&&define.amd?define([],function(){return t()}):"object"==typeof exports?module.exports=t():t()}(0,function(){function e(e,t){"use strict";return function(n){if(!(n&&(angular.isArray(n.files)||angular.isString(n.prefix)&&angular.isString(n.suffix))))throw new Error("Couldn't load static files, no files and prefix or suffix specified!");n.files||(n.files=[{prefix:n.prefix,suffix:n.suffix}]);for(var i=e.defer(),r=[],o=n.files.length,a=0;a<o;a++)r.push(function(i){if(!i||!angular.isString(i.prefix)||!angular.isString(i.suffix))throw new Error("Couldn't load static file, no prefix or suffix specified!");var r=e.defer();return t(angular.extend({url:[i.prefix,n.key,i.suffix].join(""),method:"GET",params:""},n.$http)).success(function(e){r.resolve(e)}).error(function(){r.reject(n.key)}),r.promise}({prefix:n.files[a].prefix,key:n.key,suffix:n.files[a].suffix}));return e.all(r).then(function(e){for(var t=e.length,n={},r=0;r<t;r++)for(var o in e[r])n[o]=e[r][o];i.resolve(n)},function(e){i.reject(e)}),i.promise}}return angular.module("pascalprecht.translate").factory("$translateStaticFilesLoader",e),e.$inject=["$q","$http"],e.displayName="$translateStaticFilesLoader","pascalprecht.translate"}),function(e,t){"function"==typeof define&&define.amd?define([],function(){return t()}):"object"==typeof exports?module.exports=t():t()}(0,function(){function e(e){"use strict";return{get:function(t){return e.get(t)},set:function(t,n){e.put(t,n)},put:function(t,n){e.put(t,n)}}}return angular.module("pascalprecht.translate").factory("$translateCookieStorage",e),e.$inject=["$cookieStore"],e.displayName="$translateCookieStorage","pascalprecht.translate"}),function(e,t,n){"use strict";function i(e,n,i,r,o,a){function s(e,n){return angular.element((n||t).querySelectorAll(e))}function l(e){return c[e]?c[e]:c[e]=n.get(e,{cache:a}).then(function(e){return e.data})}this.compile=function(t){t.template&&/\.html$/.test(t.template)&&(console.warn("Deprecated use of `template` option to pass a file. Please use the `templateUrl` option instead."),t.templateUrl=t.template,t.template="");var n=t.templateUrl,a=t.template||"",c=t.controller,u=t.controllerAs,d=angular.copy(t.resolve||{}),f=angular.copy(t.locals||{}),p=t.transformTemplate||angular.identity,h=t.bindToController;if(angular.forEach(d,function(e,t){angular.isString(e)?d[t]=i.get(e):d[t]=i.invoke(e)}),angular.extend(d,f),a)d.$template=e.when(a);else{if(!n)throw new Error("Missing `template` / `templateUrl` option.");d.$template=l(n)}return t.titleTemplate&&(d.$template=e.all([d.$template,l(t.titleTemplate)]).then(function(e){var t=angular.element(e[0]);return s('[ng-bind="title"]',t[0]).removeAttr("ng-bind").html(e[1]),t[0].outerHTML})),t.contentTemplate&&(d.$template=e.all([d.$template,l(t.contentTemplate)]).then(function(e){var n=angular.element(e[0]),i=s('[ng-bind="content"]',n[0]).removeAttr("ng-bind").html(e[1]);return t.templateUrl||i.next().remove(),n[0].outerHTML})),e.all(d).then(function(e){var n=p(e.$template);t.html&&(n=n.replace(/ng-bind="/gi,'ng-bind-html="'));var i=angular.element("<div>").html(n.trim()).contents(),a=r(i);return{locals:e,element:i,link:function(t){if(e.$scope=t,c){var n=o(c,e,!0);h&&angular.extend(n.instance,e);var r=angular.isObject(n)?n:n();i.data("$ngControllerController",r),i.children().data("$ngControllerController",r),u&&(t[u]=r)}return a.apply(null,arguments)}}})};var c={}}i.$inject=["$q","$http","$injector","$compile","$controller","$templateCache"],angular.module("mgcrea.ngStrap.tooltip",["mgcrea.ngStrap.core","mgcrea.ngStrap.helpers.dimensions"]).provider("$tooltip",function(){var e=this.defaults={animation:"am-fade",customClass:"",prefixClass:"tooltip",prefixEvent:"tooltip",container:!1,target:!1,placement:"top",templateUrl:"tooltip/tooltip.tpl.html",template:"",titleTemplate:!1,trigger:"hover focus",keyboard:!1,html:!1,show:!1,title:"",type:"",delay:0,autoClose:!1,bsEnabled:!0,viewport:{selector:"body",padding:0}};this.$get=["$window","$rootScope","$bsCompiler","$q","$templateCache","$http","$animate","$sce","dimensions","$$rAF","$timeout",function(n,i,r,o,a,s,l,c,u,d,f){function p(o,a){function s(){N.$emit(I.prefixEvent+".show",O)}function p(){if(N.$emit(I.prefixEvent+".hide",O),H===B){if(_&&"focus"===I.trigger)return o[0].blur();M()}}function $(){var e=I.trigger.split(" ");angular.forEach(e,function(e){"click"===e||"contextmenu"===e?o.on(e,O.toggle):"manual"!==e&&(o.on("hover"===e?"mouseenter":"focus",O.enter),o.on("hover"===e?"mouseleave":"blur",O.leave),"button"===j&&"hover"!==e&&o.on(m?"touchstart":"mousedown",O.$onFocusElementMouseDown))})}function y(){for(var e=I.trigger.split(" "),t=e.length;t--;){var n=e[t];"click"===n||"contextmenu"===n?o.off(n,O.toggle):"manual"!==n&&(o.off("hover"===n?"mouseenter":"focus",O.enter),o.off("hover"===n?"mouseleave":"blur",O.leave),"button"===j&&"hover"!==n&&o.off(m?"touchstart":"mousedown",O.$onFocusElementMouseDown))}}function b(){"focus"!==I.trigger?H.on("keyup",O.$onKeyUp):o.on("keyup",O.$onFocusKeyUp)}function w(){"focus"!==I.trigger?H.off("keyup",O.$onKeyUp):o.off("keyup",O.$onFocusKeyUp)}function x(){f(function(){H.on("click",k),v.on("click",O.hide),W=!0},0,!1)}function C(){W&&(H.off("click",k),v.off("click",O.hide),W=!1)}function k(e){e.stopPropagation()}function S(e){e=e||I.target||o;var i=e[0],r="BODY"===i.tagName,a=i.getBoundingClientRect(),s={};for(var l in a)s[l]=a[l];null===s.width&&(s=angular.extend({},s,{width:a.right-a.left,height:a.bottom-a.top}));var c=r?{top:0,left:0}:u.offset(i),d={scroll:r?t.documentElement.scrollTop||t.body.scrollTop:e.prop("scrollTop")||0},f=r?{width:t.documentElement.clientWidth,height:n.innerHeight}:null;return angular.extend({},s,d,f,c)}function E(e,t,n,i){var r,o=e.split("-");switch(o[0]){case"right":r={top:t.top+t.height/2-i/2,left:t.left+t.width};break;case"bottom":r={top:t.top+t.height,left:t.left+t.width/2-n/2};break;case"left":r={top:t.top+t.height/2-i/2,left:t.left-n};break;default:r={top:t.top-i,left:t.left+t.width/2-n/2}}if(!o[1])return r;if("top"===o[0]||"bottom"===o[0])switch(o[1]){case"left":r.left=t.left;break;case"right":r.left=t.left+t.width-n}else if("left"===o[0]||"right"===o[0])switch(o[1]){case"top":r.top=t.top-i+t.height;break;case"bottom":r.top=t.top}return r}function T(e,t){var n=H[0],i=n.offsetWidth,r=n.offsetHeight,o=parseInt(u.css(n,"margin-top"),10),a=parseInt(u.css(n,"margin-left"),10);isNaN(o)&&(o=0),isNaN(a)&&(a=0),e.top=e.top+o,e.left=e.left+a,u.setOffset(n,angular.extend({using:function(e){H.css({top:Math.round(e.top)+"px",left:Math.round(e.left)+"px",right:""})}},e),0);var s=n.offsetWidth,l=n.offsetHeight;if("top"===t&&l!==r&&(e.top=e.top+r-l),!/top-left|top-right|bottom-left|bottom-right/.test(t)){var c=D(t,e,s,l);if(c.left?e.left+=c.left:e.top+=c.top,u.setOffset(n,e),/top|right|bottom|left/.test(t)){var d=/top|bottom/.test(t);A(d?2*c.left-i+s:2*c.top-r+l,n[d?"offsetWidth":"offsetHeight"],d)}}}function D(e,t,n,i){var r={top:0,left:0};if(!O.$viewport)return r;var o=I.viewport&&I.viewport.padding||0,a=S(O.$viewport);if(/right|left/.test(e)){var s=t.top-o-a.scroll,l=t.top+o-a.scroll+i;s<a.top?r.top=a.top-s:l>a.top+a.height&&(r.top=a.top+a.height-l)}else{var c=t.left-o,u=t.left+o+n;c<a.left?r.left=a.left-c:u>a.right&&(r.left=a.left+a.width-u)}return r}function A(e,t,n){g(".tooltip-arrow, .arrow",H[0]).css(n?"left":"top",50*(1-e/t)+"%").css(n?"top":"left","")}function M(){clearTimeout(L),O.$isShown&&null!==H&&(I.autoClose&&C(),I.keyboard&&w()),U&&(U.$destroy(),U=null),H&&(H.remove(),H=O.$element=null)}var O={},I=O.$options=angular.extend({},e,a),P=O.$promise=r.compile(I),N=O.$scope=I.scope&&I.scope.$new()||i.$new(),j=o[0].nodeName.toLowerCase();if(I.delay&&angular.isString(I.delay)){var F=I.delay.split(",").map(parseFloat);I.delay=F.length>1?{show:F[0],hide:F[1]}:F[0]}O.$id=I.id||o.attr("id")||"",I.title&&(N.title=c.trustAsHtml(I.title)),N.$setEnabled=function(e){N.$$postDigest(function(){O.setEnabled(e)})},N.$hide=function(){N.$$postDigest(function(){O.hide()})},N.$show=function(){N.$$postDigest(function(){O.show()})},N.$toggle=function(){N.$$postDigest(function(){O.toggle()})},O.$isShown=N.$isShown=!1;var L,R,V,H,q,U;P.then(function(e){V=e,O.init()}),O.init=function(){I.delay&&angular.isNumber(I.delay)&&(I.delay={show:I.delay,hide:I.delay}),"self"===I.container?q=o:angular.isElement(I.container)?q=I.container:I.container&&(q=g(I.container)),$(),I.target&&(I.target=angular.isElement(I.target)?I.target:g(I.target)),I.show&&N.$$postDigest(function(){"focus"===I.trigger?o[0].focus():O.show()})},O.destroy=function(){y(),M(),N.$destroy()},O.enter=function(){if(clearTimeout(L),R="in",!I.delay||!I.delay.show)return O.show();L=setTimeout(function(){"in"===R&&O.show()},I.delay.show)},O.show=function(){if(I.bsEnabled&&!O.$isShown){N.$emit(I.prefixEvent+".show.before",O);var e,t;I.container?(e=q,t=q[0].lastChild?angular.element(q[0].lastChild):null):(e=null,t=o),H&&M(),U=O.$scope.$new(),H=O.$element=V.link(U,function(e,t){}),H.css({top:"-9999px",left:"-9999px",right:"auto",display:"block",visibility:"hidden"}),I.animation&&H.addClass(I.animation),I.type&&H.addClass(I.prefixClass+"-"+I.type),I.customClass&&H.addClass(I.customClass),t?t.after(H):e.prepend(H),O.$isShown=N.$isShown=!0,h(N),O.$applyPlacement(),angular.version.minor<=2?l.enter(H,e,t,s):l.enter(H,e,t).then(s),h(N),d(function(){H&&H.css({visibility:"visible"}),I.keyboard&&("focus"!==I.trigger&&O.focus(),b())}),I.autoClose&&x()}},O.leave=function(){if(clearTimeout(L),R="out",!I.delay||!I.delay.hide)return O.hide();L=setTimeout(function(){"out"===R&&O.hide()},I.delay.hide)};var _,B;O.hide=function(e){O.$isShown&&(N.$emit(I.prefixEvent+".hide.before",O),_=e,B=H,angular.version.minor<=2?l.leave(H,p):l.leave(H).then(p),O.$isShown=N.$isShown=!1,h(N),I.keyboard&&null!==H&&w(),I.autoClose&&null!==H&&C())},O.toggle=function(e){e&&e.preventDefault(),O.$isShown?O.leave():O.enter()},O.focus=function(){H[0].focus()},O.setEnabled=function(e){I.bsEnabled=e},O.setViewport=function(e){I.viewport=e},O.$applyPlacement=function(){if(H){var t=I.placement,n=/\s?auto?\s?/i,i=n.test(t);i&&(t=t.replace(n,"")||e.placement),H.addClass(I.placement);var r=S(),o=H.prop("offsetWidth"),a=H.prop("offsetHeight");if(O.$viewport=I.viewport&&g(I.viewport.selector||I.viewport),i){var s=t,l=S(O.$viewport);/bottom/.test(s)&&r.bottom+a>l.bottom?t=s.replace("bottom","top"):/top/.test(s)&&r.top-a<l.top&&(t=s.replace("top","bottom")),/left/.test(s)&&r.left-o<l.left?t=t.replace("left","right"):/right/.test(s)&&r.right+o>l.width&&(t=t.replace("right","left")),H.removeClass(s).addClass(t)}T(E(t,r,o,a),t)}},O.$onKeyUp=function(e){27===e.which&&O.$isShown&&(O.hide(),e.stopPropagation())},O.$onFocusKeyUp=function(e){27===e.which&&(o[0].blur(),e.stopPropagation())},O.$onFocusElementMouseDown=function(e){e.preventDefault(),e.stopPropagation(),O.$isShown?o[0].blur():o[0].focus()};var W=!1;return O}function h(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}function g(e,n){return angular.element((n||t).querySelectorAll(e))}var m="createTouch"in n.document,v=angular.element(n.document);return p}]}).directive("bsTooltip",["$window","$location","$sce","$tooltip","$$rAF",function(e,t,n,i,r){return{restrict:"EAC",scope:!0,link:function(e,t,o,a){var s,l={scope:e};angular.forEach(["template","templateUrl","controller","controllerAs","titleTemplate","placement","container","delay","trigger","html","animation","backdropAnimation","type","customClass","id"],function(e){angular.isDefined(o[e])&&(l[e]=o[e])});var c=/^(false|0|)$/i;angular.forEach(["html","container"],function(e){angular.isDefined(o[e])&&c.test(o[e])&&(l[e]=!1)});var u=t.attr("data-target");angular.isDefined(u)&&(c.test(u)?l.target=!1:l.target=u),e.hasOwnProperty("title")||(e.title=""),o.$observe("title",function(t){if(angular.isDefined(t)||!e.hasOwnProperty("title")){var i=e.title;e.title=n.trustAsHtml(t),angular.isDefined(i)&&r(function(){s&&s.$applyPlacement()})}}),o.$observe("disabled",function(e){e&&s.$isShown&&s.hide()}),o.bsTooltip&&e.$watch(o.bsTooltip,function(t,n){angular.isObject(t)?angular.extend(e,t):e.title=t,angular.isDefined(n)&&r(function(){s&&s.$applyPlacement()})},!0),o.bsShow&&e.$watch(o.bsShow,function(e,t){s&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(tooltip),?/i)),!0===e?s.show():s.hide())}),o.bsEnabled&&e.$watch(o.bsEnabled,function(e,t){s&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|1|,?(tooltip),?/i)),!1===e?s.setEnabled(!1):s.setEnabled(!0))}),o.viewport&&e.$watch(o.viewport,function(e){s&&angular.isDefined(e)&&s.setViewport(e)}),s=i(t,l),e.$on("$destroy",function(){s&&s.destroy(),l=null,s=null})}}}]),angular.module("mgcrea.ngStrap.typeahead",["mgcrea.ngStrap.tooltip","mgcrea.ngStrap.helpers.parseOptions"]).provider("$typeahead",function(){var e=this.defaults={animation:"am-fade",prefixClass:"typeahead",prefixEvent:"$typeahead",placement:"bottom-left",templateUrl:"typeahead/typeahead.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,minLength:1,filter:"bsAsyncFilter",limit:6,autoSelect:!1,comparator:"",trimValue:!0};this.$get=["$window","$rootScope","$tooltip","$$rAF","$timeout",function(t,n,i,r,o){function a(t,n,a){var l={},c=angular.extend({},e,a);l=i(t,c);var u=a.scope,d=l.$scope;d.$resetMatches=function(){d.$matches=[],d.$activeIndex=c.autoSelect?0:-1},d.$resetMatches(),d.$activate=function(e){d.$$postDigest(function(){l.activate(e)})},d.$select=function(e,t){d.$$postDigest(function(){l.select(e)})},d.$isVisible=function(){return l.$isVisible()},l.update=function(e){d.$matches=e,d.$activeIndex>=e.length&&(d.$activeIndex=c.autoSelect?0:-1),s(d),r(l.$applyPlacement)},l.activate=function(e){d.$activeIndex=e},l.select=function(e){if(-1!==e){var t=d.$matches[e].value;n.$setViewValue(t),n.$render(),d.$resetMatches(),u&&u.$digest(),d.$emit(c.prefixEvent+".select",t,e,l)}},l.$isVisible=function(){return c.minLength&&n?d.$matches.length&&angular.isString(n.$viewValue)&&n.$viewValue.length>=c.minLength:!!d.$matches.length},l.$getIndex=function(e){var t;for(t=d.$matches.length;t--&&!angular.equals(d.$matches[t].value,e););return t},l.$onMouseDown=function(e){e.preventDefault(),e.stopPropagation()},l.$onKeyDown=function(e){/(38|40|13)/.test(e.keyCode)&&(!l.$isVisible()||13===e.keyCode&&-1===d.$activeIndex||(e.preventDefault(),e.stopPropagation()),13===e.keyCode&&d.$matches.length?l.select(d.$activeIndex):38===e.keyCode&&d.$activeIndex>0?d.$activeIndex--:40===e.keyCode&&d.$activeIndex<d.$matches.length-1?d.$activeIndex++:angular.isUndefined(d.$activeIndex)&&(d.$activeIndex=0),d.$digest())};var f=l.show;l.show=function(){f(),o(function(){l.$element&&(l.$element.on("mousedown",l.$onMouseDown),c.keyboard&&t&&t.on("keydown",l.$onKeyDown))},0,!1)};var p=l.hide;return l.hide=function(){l.$element&&l.$element.off("mousedown",l.$onMouseDown),c.keyboard&&t&&t.off("keydown",l.$onKeyDown),c.autoSelect||l.activate(-1),p()},l}function s(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}return a.defaults=e,a}]}).filter("bsAsyncFilter",["$filter",function(e){return function(t,n,i){return t&&angular.isFunction(t.then)?t.then(function(t){return e("filter")(t,n,i)}):e("filter")(t,n,i)}}]).directive("bsTypeahead",["$window","$parse","$q","$typeahead","$parseOptions",function(e,t,n,i,r){var o=i.defaults;return{restrict:"EAC",require:"ngModel",link:function(e,t,n,a){t.off("change");var s={scope:e};angular.forEach(["template","templateUrl","controller","controllerAs","placement","container","delay","trigger","keyboard","html","animation","filter","limit","minLength","watchOptions","selectMode","autoSelect","comparator","id","prefixEvent","prefixClass"],function(e){angular.isDefined(n[e])&&(s[e]=n[e])});var l=/^(false|0|)$/i;angular.forEach(["html","container","trimValue","filter"],function(e){angular.isDefined(n[e])&&l.test(n[e])&&(s[e]=!1)}),t.attr("autocomplete")||t.attr("autocomplete","off");var c=angular.isDefined(s.filter)?s.filter:o.filter,u=s.limit||o.limit,d=s.comparator||o.comparator,f=n.bsOptions;c&&(f+=" | "+c+":$viewValue",d&&(f+=":"+d)),u&&(f+=" | limitTo:"+u);var p=r(f),h=i(t,a,s);if(s.watchOptions){var g=p.$match[7].replace(/\|.+/,"").replace(/\(.*\)/g,"").trim();e.$watchCollection(g,function(t,n){p.valuesFn(e,a).then(function(e){h.update(e),a.$render()})})}e.$watch(n.ngModel,function(t,n){e.$modelValue=t,p.valuesFn(e,a).then(function(e){if(s.selectMode&&!e.length&&t.length>0)return void a.$setViewValue(a.$viewValue.substring(0,a.$viewValue.length-1));e.length>u&&(e=e.slice(0,u)),h.update(e),a.$render()})}),a.$formatters.push(function(e){var t=p.displayValue(e);return t||(angular.isDefined(e)&&"object"!=typeof e?e:"")}),a.$render=function(){if(a.$isEmpty(a.$viewValue))return t.val("");var e=h.$getIndex(a.$modelValue),n=-1!==e?h.$scope.$matches[e].label:a.$viewValue;n=angular.isObject(n)?p.displayValue(n):n;var i=n?n.toString().replace(/<(?:.|\n)*?>/gm,""):"";t.val(!1===s.trimValue?i:i.trim())},e.$on("$destroy",function(){h&&h.destroy(),s=null,h=null})}}}]),angular.module("mgcrea.ngStrap.timepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.helpers.dateFormatter","mgcrea.ngStrap.tooltip"]).provider("$timepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"timepicker",placement:"bottom-left",templateUrl:"timepicker/timepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!0,timeType:"date",timeFormat:"shortTime",timezone:null,modelTimeFormat:null,autoclose:!1,minTime:-1/0,maxTime:1/0,length:5,hourStep:1,minuteStep:5,secondStep:5,roundDisplay:!1,iconUp:"glyphicon glyphicon-chevron-up",iconDown:"glyphicon glyphicon-chevron-down",arrowBehavior:"pager"};this.$get=["$window","$document","$rootScope","$sce","$dateFormatter","$tooltip","$timeout",function(t,n,i,r,o,a,s){function l(t,n,i){function r(e,n){var i=e+n;if(t[0].createTextRange){var r=t[0].createTextRange();r.collapse(!0),r.moveStart("character",e),r.moveEnd("character",i),r.select()}else t[0].setSelectionRange?t[0].setSelectionRange(e,i):angular.isUndefined(t[0].selectionStart)&&(t[0].selectionStart=e,t[0].selectionEnd=i)}function l(){t[0].focus()}var d=a(t,angular.extend({},e,i)),f=i.scope,p=d.$options,h=d.$scope,g=p.lang,m=function(e,t,n){return o.formatDate(e,t,g,n)},v=0,$=p.roundDisplay?function(e){var t=6e4*p.minuteStep;return new Date(Math.floor(e.getTime()/t)*t)}(new Date):new Date,y=n.$dateValue||$,b={hour:y.getHours(),meridian:y.getHours()<12,minute:y.getMinutes(),second:y.getSeconds(),millisecond:y.getMilliseconds()},w=o.getDatetimeFormat(p.timeFormat,g),x=o.hoursFormat(w),C=o.timeSeparator(w),k=o.minutesFormat(w),S=o.secondsFormat(w),E=o.showSeconds(w),T=o.showAM(w);h.$iconUp=p.iconUp,h.$iconDown=p.iconDown,h.$select=function(e,t){d.select(e,t)},h.$moveIndex=function(e,t){d.$moveIndex(e,t)},h.$switchMeridian=function(e){d.switchMeridian(e)},d.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())?(d.$date=e,angular.extend(b,{hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}),d.$build()):d.$isBuilt||d.$build()},d.select=function(e,t,i){n.$dateValue&&!isNaN(n.$dateValue.getTime())||(n.$dateValue=new Date(1970,0,1)),angular.isDate(e)||(e=new Date(e)),0===t?n.$dateValue.setHours(e.getHours()):1===t?n.$dateValue.setMinutes(e.getMinutes()):2===t&&n.$dateValue.setSeconds(e.getSeconds()),n.$setViewValue(angular.copy(n.$dateValue)),n.$render(),p.autoclose&&!i&&s(function(){d.hide(!0)})},d.switchMeridian=function(e){if(n.$dateValue&&!isNaN(n.$dateValue.getTime())){var t=(e||n.$dateValue).getHours();n.$dateValue.setHours(t<12?t+12:t-12),n.$setViewValue(angular.copy(n.$dateValue)),n.$render()}},d.$build=function(){var e,t,n=h.midIndex=parseInt(p.length/2,10),i=[];for(e=0;e<p.length;e++)t=new Date(1970,0,1,b.hour-(n-e)*p.hourStep),i.push({date:t,label:m(t,x),selected:d.$date&&d.$isSelected(t,0),disabled:d.$isDisabled(t,0)});var r,o=[];for(e=0;e<p.length;e++)r=new Date(1970,0,1,0,b.minute-(n-e)*p.minuteStep),o.push({date:r,label:m(r,k),selected:d.$date&&d.$isSelected(r,1),disabled:d.$isDisabled(r,1)});var a,s=[];for(e=0;e<p.length;e++)a=new Date(1970,0,1,0,0,b.second-(n-e)*p.secondStep),s.push({date:a,label:m(a,S),selected:d.$date&&d.$isSelected(a,2),disabled:d.$isDisabled(a,2)});var l=[];for(e=0;e<p.length;e++)E?l.push([i[e],o[e],s[e]]):l.push([i[e],o[e]]);h.rows=l,h.showSeconds=E,h.showAM=T,h.isAM=(d.$date||i[n].date).getHours()<12,h.timeSeparator=C,d.$isBuilt=!0},d.$isSelected=function(e,t){return!!d.$date&&(0===t?e.getHours()===d.$date.getHours():1===t?e.getMinutes()===d.$date.getMinutes():2===t?e.getSeconds()===d.$date.getSeconds():void 0)},d.$isDisabled=function(e,t){var n;return 0===t?n=e.getTime()+6e4*b.minute+1e3*b.second:1===t?n=e.getTime()+36e5*b.hour+1e3*b.second:2===t&&(n=e.getTime()+36e5*b.hour+6e4*b.minute),n<1*p.minTime||n>1*p.maxTime},h.$arrowAction=function(e,t){"picker"===p.arrowBehavior?d.$setTimeByStep(e,t):d.$moveIndex(e,t)},d.$setTimeByStep=function(e,t){var n=new Date(d.$date||y),i=n.getHours(),r=n.getMinutes(),o=n.getSeconds();0===t?n.setHours(i-parseInt(p.hourStep,10)*e):1===t?n.setMinutes(r-parseInt(p.minuteStep,10)*e):2===t&&n.setSeconds(o-parseInt(p.secondStep,10)*e),d.select(n,t,!0)},d.$moveIndex=function(e,t){var n;0===t?(n=new Date(1970,0,1,b.hour+e*p.length,b.minute,b.second),angular.extend(b,{hour:n.getHours()})):1===t?(n=new Date(1970,0,1,b.hour,b.minute+e*p.length*p.minuteStep,b.second),angular.extend(b,{minute:n.getMinutes()})):2===t&&(n=new Date(1970,0,1,b.hour,b.minute,b.second+e*p.length*p.secondStep),angular.extend(b,{second:n.getSeconds()})),d.$build()},d.$onMouseDown=function(e){if("input"!==e.target.nodeName.toLowerCase()&&e.preventDefault(),e.stopPropagation(),u){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},d.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return void d.hide(!0);var t=new Date(d.$date),n=t.getHours(),i=m(t,x).length,o=t.getMinutes(),a=m(t,k).length,s=t.getSeconds(),l=m(t,S).length,c=/(37|39)/.test(e.keyCode),u=2+1*E+1*T;c&&(37===e.keyCode?v=v<1?u-1:v-1:39===e.keyCode&&(v=v<u-1?v+1:0));var h=[0,i],g=0;38===e.keyCode&&(g=-1),40===e.keyCode&&(g=1);var $=2===v&&E,y=2===v&&!E||3===v&&E;0===v?(t.setHours(n+g*parseInt(p.hourStep,10)),i=m(t,x).length,h=[0,i]):1===v?(t.setMinutes(o+g*parseInt(p.minuteStep,10)),a=m(t,k).length,h=[i+1,a]):$?(t.setSeconds(s+g*parseInt(p.secondStep,10)),l=m(t,S).length,h=[i+1+a+1,l]):y&&(c||d.switchMeridian(),h=[i+1+a+1+(l+1)*E,2]),d.select(t,v,!0),r(h[0],h[1]),f.$digest()}};var D=d.init;d.init=function(){if(c&&p.useNative)return t.prop("type","time"),void t.css("-webkit-appearance","textfield");u&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",l)),D()};var A=d.destroy;d.destroy=function(){c&&p.useNative&&t.off("click",l),A()};var M=d.show;d.show=function(){!u&&t.attr("readonly")||t.attr("disabled")||(M(),s(function(){d.$element&&d.$element.on(u?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t&&t.on("keydown",d.$onKeyDown)},0,!1))};var O=d.hide;return d.hide=function(e){d.$isShown&&(d.$element&&d.$element.off(u?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t&&t.off("keydown",d.$onKeyDown),O(e))},d}var c=/(ip[ao]d|iphone|android)/gi.test(t.navigator.userAgent),u="createTouch"in t.document&&c;return e.lang||(e.lang=o.getDefaultLocale()),l.defaults=e,l}]}).directive("bsTimepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$timepicker",function(e,t,n,i,r,o){var a=o.defaults,s=/(ip[ao]d|iphone|android)/gi.test(e.navigator.userAgent);return{restrict:"EAC",require:"ngModel",link:function(e,t,n,l){function c(e){if(angular.isDate(e)){var t=isNaN(d.minTime)||new Date(e.getTime()).setFullYear(1970,0,1)>=d.minTime,n=isNaN(d.maxTime)||new Date(e.getTime()).setFullYear(1970,0,1)<=d.maxTime,i=t&&n;l.$setValidity("date",i),l.$setValidity("min",t),l.$setValidity("max",n),i&&(l.$dateValue=e)}}function u(){return!l.$dateValue||isNaN(l.$dateValue.getTime())?"":g(l.$dateValue,d.timeFormat)}var d={scope:e};angular.forEach(["template","templateUrl","controller","controllerAs","placement","container","delay","trigger","keyboard","html","animation","autoclose","timeType","timeFormat","timezone","modelTimeFormat","useNative","hourStep","minuteStep","secondStep","length","arrowBehavior","iconUp","iconDown","roundDisplay","id","prefixClass","prefixEvent"],function(e){angular.isDefined(n[e])&&(d[e]=n[e])});var f=/^(false|0|)$/i;angular.forEach(["html","container","autoclose","useNative","roundDisplay"],function(e){angular.isDefined(n[e])&&f.test(n[e])&&(d[e]=!1)}),s&&(d.useNative||a.useNative)&&(d.timeFormat="HH:mm");var p=o(t,l,d);d=p.$options;var h=d.lang,g=function(e,t,n){return i.formatDate(e,t,h,n)};n.bsShow&&e.$watch(n.bsShow,function(e,t){p&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(timepicker),?/i)),!0===e?p.show():p.hide())});var m=r({format:d.timeFormat,lang:h});angular.forEach(["minTime","maxTime"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){p.$options[e]=m.getTimeForAttribute(e,t),isNaN(p.$options[e])||p.$build(),c(l.$dateValue)})}),e.$watch(n.ngModel,function(e,t){p.update(l.$dateValue)},!0),l.$parsers.unshift(function(e){var t;if(!e)return l.$setValidity("date",!0),null;var n=angular.isDate(e)?e:m.parse(e,l.$dateValue);return!n||isNaN(n.getTime())?void l.$setValidity("date",!1):(c(n),"string"===d.timeType?(t=m.timezoneOffsetAdjust(n,d.timezone,!0),g(t,d.modelTimeFormat||d.timeFormat)):(t=m.timezoneOffsetAdjust(l.$dateValue,d.timezone,!0),"number"===d.timeType?t.getTime():"unix"===d.timeType?t.getTime()/1e3:"iso"===d.timeType?t.toISOString():new Date(t)))}),l.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?NaN:angular.isDate(e)?e:"string"===d.timeType?m.parse(e,null,d.modelTimeFormat):"unix"===d.timeType?new Date(1e3*e):new Date(e),l.$dateValue=m.timezoneOffsetAdjust(t,d.timezone),u()}),l.$render=function(){t.val(u())},e.$on("$destroy",function(){p&&p.destroy(),d=null,p=null})}}}]),angular.module("mgcrea.ngStrap.tab",[]).provider("$tab",function(){var e=this.defaults={animation:"am-fade",template:"tab/tab.tpl.html",navClass:"nav-tabs",activeClass:"active"},t=this.controller=function(t,n,i){var r=this;r.$options=angular.copy(e),angular.forEach(["animation","navClass","activeClass"],function(e){angular.isDefined(i[e])&&(r.$options[e]=i[e])}),t.$navClass=r.$options.navClass,t.$activeClass=r.$options.activeClass,r.$panes=t.$panes=[],r.$activePaneChangeListeners=r.$viewChangeListeners=[],r.$push=function(e){angular.isUndefined(r.$panes.$active)&&t.$setActive(e.name||0),r.$panes.push(e)},r.$remove=function(e){var t,n=r.$panes.indexOf(e),i=r.$panes.$active;t=angular.isString(i)?r.$panes.map(function(e){return e.name}).indexOf(i):r.$panes.$active,r.$panes.splice(n,1),n<t?t--:n===t&&t===r.$panes.length&&t--,t>=0&&t<r.$panes.length?r.$setActive(r.$panes[t].name||t):r.$setActive()},r.$setActive=t.$setActive=function(e){r.$panes.$active=e,r.$activePaneChangeListeners.forEach(function(e){e()})},r.$isActive=t.$isActive=function(e,t){return r.$panes.$active===e.name||r.$panes.$active===t}};this.$get=function(){var n={};return n.defaults=e,n.controller=t,n}}).directive("bsTabs",["$window","$animate","$tab","$parse",function(e,t,n,i){var r=n.defaults;return{require:["?ngModel","bsTabs"],transclude:!0,scope:!0,controller:["$scope","$element","$attrs",n.controller],templateUrl:function(e,t){return t.template||r.template},link:function(e,t,n,r){var o=r[0],a=r[1];if(o&&(a.$activePaneChangeListeners.push(function(){o.$setViewValue(a.$panes.$active)}),o.$formatters.push(function(e){return a.$setActive(e),e})),n.bsActivePane){var s=i(n.bsActivePane);a.$activePaneChangeListeners.push(function(){s.assign(e,a.$panes.$active)}),e.$watch(n.bsActivePane,function(e,t){a.$setActive(e)},!0)}}}}]).directive("bsPane",["$window","$animate","$sce",function(e,t,n){return{require:["^?ngModel","^bsTabs"],scope:!0,link:function(e,i,r,o){function a(){var n=s.$panes.indexOf(e);t[s.$isActive(e,n)?"addClass":"removeClass"](i,s.$options.activeClass)}var s=o[1];i.addClass("tab-pane"),r.$observe("title",function(t,i){e.title=n.trustAsHtml(t)}),e.name=r.name,s.$options.animation&&i.addClass(s.$options.animation),r.$observe("disabled",function(t,n){e.disabled=e.$eval(t)}),s.$push(e),e.$on("$destroy",function(){s.$remove(e)}),s.$activePaneChangeListeners.push(function(){a()}),a()}}}]),angular.module("mgcrea.ngStrap.select",["mgcrea.ngStrap.tooltip","mgcrea.ngStrap.helpers.parseOptions"]).provider("$select",function(){var e=this.defaults={animation:"am-fade",prefixClass:"select",prefixEvent:"$select",placement:"bottom-left",templateUrl:"select/select.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,multiple:!1,allNoneButtons:!1,sort:!0,caretHtml:'&nbsp;<span class="caret"></span>',placeholder:"Choose among the following...",allText:"All",noneText:"None",maxLength:3,maxLengthHtml:"selected",iconCheckmark:"glyphicon glyphicon-ok"};this.$get=["$window","$document","$rootScope","$tooltip","$timeout",function(t,n,i,r,o){function a(i,a,s){var c={},u=angular.extend({},e,s);c=r(i,u);var d=c.$scope;d.$matches=[],u.multiple?d.$activeIndex=[]:d.$activeIndex=-1,d.$isMultiple=u.multiple,d.$showAllNoneButtons=u.allNoneButtons&&u.multiple,d.$iconCheckmark=u.iconCheckmark,d.$allText=u.allText,d.$noneText=u.noneText,d.$activate=function(e){d.$$postDigest(function(){
+c.activate(e)})},d.$select=function(e,t){d.$$postDigest(function(){c.select(e)})},d.$isVisible=function(){return c.$isVisible()},d.$isActive=function(e){return c.$isActive(e)},d.$selectAll=function(){for(var e=0;e<d.$matches.length;e++)d.$isActive(e)||d.$select(e)},d.$selectNone=function(){for(var e=0;e<d.$matches.length;e++)d.$isActive(e)&&d.$select(e)},c.update=function(e){d.$matches=e,c.$updateActiveIndex()},c.activate=function(e){return u.multiple?(c.$isActive(e)?d.$activeIndex.splice(d.$activeIndex.indexOf(e),1):d.$activeIndex.push(e),u.sort&&d.$activeIndex.sort(function(e,t){return e-t})):d.$activeIndex=e,d.$activeIndex},c.select=function(e){var t=d.$matches[e].value;d.$apply(function(){c.activate(e),u.multiple?a.$setViewValue(d.$activeIndex.map(function(e){return angular.isUndefined(d.$matches[e])?null:d.$matches[e].value})):(a.$setViewValue(t),c.hide())}),d.$emit(u.prefixEvent+".select",t,e,c)},c.$updateActiveIndex=function(){u.multiple?angular.isArray(a.$modelValue)?d.$activeIndex=a.$modelValue.map(function(e){return c.$getIndex(e)}):d.$activeIndex=[]:angular.isDefined(a.$modelValue)&&d.$matches.length?d.$activeIndex=c.$getIndex(a.$modelValue):d.$activeIndex=-1},c.$isVisible=function(){return u.minLength&&a?d.$matches.length&&a.$viewValue.length>=u.minLength:d.$matches.length},c.$isActive=function(e){return u.multiple?-1!==d.$activeIndex.indexOf(e):d.$activeIndex===e},c.$getIndex=function(e){var t;for(t=d.$matches.length;t--&&!angular.equals(d.$matches[t].value,e););return t},c.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),l){angular.element(e.target).triggerHandler("click")}},c.$onKeyDown=function(e){if(/(9|13|38|40)/.test(e.keyCode))return 9!==e.keyCode&&(e.preventDefault(),e.stopPropagation()),u.multiple&&9===e.keyCode?c.hide():u.multiple||13!==e.keyCode&&9!==e.keyCode?void(u.multiple||(38===e.keyCode&&d.$activeIndex>0?d.$activeIndex--:38===e.keyCode&&d.$activeIndex<0?d.$activeIndex=d.$matches.length-1:40===e.keyCode&&d.$activeIndex<d.$matches.length-1?d.$activeIndex++:angular.isUndefined(d.$activeIndex)&&(d.$activeIndex=0),d.$digest())):c.select(d.$activeIndex)},c.$isIE=function(){var e=t.navigator.userAgent;return e.indexOf("MSIE ")>0||e.indexOf("Trident/")>0||e.indexOf("Edge/")>0},c.$selectScrollFix=function(e){"UL"===n[0].activeElement.tagName&&(e.preventDefault(),e.stopImmediatePropagation(),e.target.focus())};var f=c.show;c.show=function(){f(),u.multiple&&c.$element.addClass("select-multiple"),o(function(){c.$element.on(l?"touchstart":"mousedown",c.$onMouseDown),u.keyboard&&i.on("keydown",c.$onKeyDown)},0,!1)};var p=c.hide;return c.hide=function(){!u.multiple&&angular.isUndefined(a.$modelValue)&&(d.$activeIndex=-1),c.$element.off(l?"touchstart":"mousedown",c.$onMouseDown),u.keyboard&&i.off("keydown",c.$onKeyDown),p(!0)},c}var s=/(ip[ao]d|iphone|android)/gi.test(t.navigator.userAgent),l="createTouch"in t.document&&s;return a.defaults=e,a}]}).directive("bsSelect",["$window","$parse","$q","$select","$parseOptions",function(e,t,n,i,r){var o=i.defaults;return{restrict:"EAC",require:"ngModel",link:function(e,t,n,a){var s={scope:e,placeholder:o.placeholder};angular.forEach(["template","templateUrl","controller","controllerAs","placement","container","delay","trigger","keyboard","html","animation","placeholder","allNoneButtons","maxLength","maxLengthHtml","allText","noneText","iconCheckmark","autoClose","id","sort","caretHtml","prefixClass","prefixEvent"],function(e){angular.isDefined(n[e])&&(s[e]=n[e])});var l=/^(false|0|)$/i;angular.forEach(["html","container","allNoneButtons","sort"],function(e){angular.isDefined(n[e])&&l.test(n[e])&&(s[e]=!1)});var c=t.attr("data-multiple");if(angular.isDefined(c)&&(l.test(c)?s.multiple=!1:s.multiple=c),"select"===t[0].nodeName.toLowerCase()){var u=t;u.css("display","none"),t=angular.element('<button type="button" class="btn btn-default"></button>'),u.after(t)}var d=r(n.bsOptions),f=i(t,a,s);f.$isIE()&&t[0].addEventListener("blur",f.$selectScrollFix);var p=d.$match[7].replace(/\|.+/,"").trim();e.$watch(p,function(t,n){d.valuesFn(e,a).then(function(e){f.update(e),a.$render()})},!0),e.$watch(n.ngModel,function(e,t){f.$updateActiveIndex(),a.$render()},!0),a.$render=function(){var e,n;s.multiple&&angular.isArray(a.$modelValue)?(e=a.$modelValue.map(function(e){return-1!==(n=f.$getIndex(e))&&f.$scope.$matches[n].label}).filter(angular.isDefined),e=e.length>(s.maxLength||o.maxLength)?e.length+" "+(s.maxLengthHtml||o.maxLengthHtml):e.join(", ")):(n=f.$getIndex(a.$modelValue),e=-1!==n&&f.$scope.$matches[n].label),t.html((e||s.placeholder)+(s.caretHtml||o.caretHtml))},s.multiple&&(a.$isEmpty=function(e){return!e||0===e.length}),e.$on("$destroy",function(){f&&f.destroy(),s=null,f=null})}}}]),angular.module("mgcrea.ngStrap.scrollspy",["mgcrea.ngStrap.helpers.debounce","mgcrea.ngStrap.helpers.dimensions"]).provider("$scrollspy",function(){var e=this.$$spies={},n=this.defaults={debounce:150,throttle:100,offset:100};this.$get=["$window","$document","$rootScope","dimensions","debounce","throttle",function(i,r,o,a,s,l){function c(e,t){return e[0].nodeName&&e[0].nodeName.toLowerCase()===t.toLowerCase()}function u(r){var u=angular.extend({},n,r);u.element||(u.element=p);var h=c(u.element,"body"),g=h?d:u.element,m=h?"window":u.id;if(e[m])return e[m].$$count++,e[m];var v,$,y,b,w,x,C,k,S={},E=S.$trackedElements=[],T=[];return S.init=function(){this.$$count=1,b=s(this.checkPosition,u.debounce),w=l(this.checkPosition,u.throttle),g.on("click",this.checkPositionWithEventLoop),d.on("resize",b),g.on("scroll",w),x=s(this.checkOffsets,u.debounce),v=o.$on("$viewContentLoaded",x),$=o.$on("$includeContentLoaded",x),x(),m&&(e[m]=S)},S.destroy=function(){--this.$$count>0||(g.off("click",this.checkPositionWithEventLoop),d.off("resize",b),g.off("scroll",w),v(),$(),m&&delete e[m])},S.checkPosition=function(){if(T.length){if(k=(h?i.pageYOffset:g.prop("scrollTop"))||0,C=Math.max(i.innerHeight,f.prop("clientHeight")),k<T[0].offsetTop&&y!==T[0].target)return S.$activateElement(T[0]);for(var e=T.length;e--;)if(!angular.isUndefined(T[e].offsetTop)&&null!==T[e].offsetTop&&y!==T[e].target&&!(k<T[e].offsetTop||T[e+1]&&k>T[e+1].offsetTop))return S.$activateElement(T[e])}},S.checkPositionWithEventLoop=function(){setTimeout(S.checkPosition,1)},S.$activateElement=function(e){if(y){var t=S.$getTrackedElement(y);t&&(t.source.removeClass("active"),c(t.source,"li")&&c(t.source.parent().parent(),"li")&&t.source.parent().parent().removeClass("active"))}y=e.target,e.source.addClass("active"),c(e.source,"li")&&c(e.source.parent().parent(),"li")&&e.source.parent().parent().addClass("active")},S.$getTrackedElement=function(e){return E.filter(function(t){return t.target===e})[0]},S.checkOffsets=function(){angular.forEach(E,function(e){var n=t.querySelector(e.target);e.offsetTop=n?a.offset(n).top:null,u.offset&&null!==e.offsetTop&&(e.offsetTop-=1*u.offset)}),T=E.filter(function(e){return null!==e.offsetTop}).sort(function(e,t){return e.offsetTop-t.offsetTop}),b()},S.trackElement=function(e,t){E.push({target:e,source:t})},S.untrackElement=function(e,t){for(var n,i=E.length;i--;)if(E[i].target===e&&E[i].source===t){n=i;break}E.splice(n,1)},S.activate=function(e){E[e].addClass("active")},S.init(),S}var d=angular.element(i),f=angular.element(r.prop("documentElement")),p=angular.element(i.document.body);return u}]}).directive("bsScrollspy",["$rootScope","debounce","dimensions","$scrollspy",function(e,t,n,i){return{restrict:"EAC",link:function(e,t,n){var r={scope:e};angular.forEach(["offset","target"],function(e){angular.isDefined(n[e])&&(r[e]=n[e])});var o=i(r);o.trackElement(r.target,t),e.$on("$destroy",function(){o&&(o.untrackElement(r.target,t),o.destroy()),r=null,o=null})}}}]).directive("bsScrollspyList",["$rootScope","debounce","dimensions","$scrollspy",function(e,t,n,i){return{restrict:"A",compile:function(e,t){var n=e[0].querySelectorAll("li > a[href]");angular.forEach(n,function(e){var t=angular.element(e);t.parent().attr("bs-scrollspy","").attr("data-target",t.attr("href"))})}}}]),angular.module("mgcrea.ngStrap.popover",["mgcrea.ngStrap.tooltip"]).provider("$popover",function(){var e=this.defaults={animation:"am-fade",customClass:"",container:!1,target:!1,placement:"right",templateUrl:"popover/popover.tpl.html",contentTemplate:!1,trigger:"click",keyboard:!0,html:!1,title:"",content:"",delay:0,autoClose:!1};this.$get=["$tooltip",function(t){function n(n,i){var r=angular.extend({},e,i),o=t(n,r);return r.content&&(o.$scope.content=r.content),o}return n}]}).directive("bsPopover",["$window","$sce","$popover",function(e,t,n){var i=e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,r,o){var a,s={scope:e};angular.forEach(["template","templateUrl","controller","controllerAs","contentTemplate","placement","container","delay","trigger","html","animation","customClass","autoClose","id","prefixClass","prefixEvent"],function(e){angular.isDefined(o[e])&&(s[e]=o[e])});var l=/^(false|0|)$/i;angular.forEach(["html","container","autoClose"],function(e){angular.isDefined(o[e])&&l.test(o[e])&&(s[e]=!1)});var c=r.attr("data-target");angular.isDefined(c)&&(l.test(c)?s.target=!1:s.target=c),angular.forEach(["title","content"],function(n){o[n]&&o.$observe(n,function(r,o){e[n]=t.trustAsHtml(r),angular.isDefined(o)&&i(function(){a&&a.$applyPlacement()})})}),o.bsPopover&&e.$watch(o.bsPopover,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t,angular.isDefined(n)&&i(function(){a&&a.$applyPlacement()})},!0),o.bsShow&&e.$watch(o.bsShow,function(e,t){a&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(popover),?/i)),!0===e?a.show():a.hide())}),o.viewport&&e.$watch(o.viewport,function(e){a&&angular.isDefined(e)&&a.setViewport(e)}),a=n(r,s),e.$on("$destroy",function(){a&&a.destroy(),s=null,a=null})}}}]),angular.module("mgcrea.ngStrap.navbar",[]).provider("$navbar",function(){var e=this.defaults={activeClass:"active",routeAttr:"data-match-route",strict:!1};this.$get=function(){return{defaults:e}}}).directive("bsNavbar",["$window","$location","$navbar",function(e,t,n){var i=n.defaults;return{restrict:"A",link:function(e,n,r,o){var a=angular.copy(i);angular.forEach(Object.keys(i),function(e){angular.isDefined(r[e])&&(a[e]=r[e])}),e.$watch(function(){return t.path()},function(e,t){var i=n[0].querySelectorAll("li["+a.routeAttr+"]");angular.forEach(i,function(t){var n=angular.element(t),i=n.attr(a.routeAttr).replace("/","\\/");a.strict&&(i="^"+i+"$"),new RegExp(i,"i").test(e)?n.addClass(a.activeClass):n.removeClass(a.activeClass)})})}}}]),angular.module("mgcrea.ngStrap.dropdown",["mgcrea.ngStrap.tooltip"]).provider("$dropdown",function(){var e=this.defaults={animation:"am-fade",prefixClass:"dropdown",prefixEvent:"dropdown",placement:"bottom-left",templateUrl:"dropdown/dropdown.tpl.html",trigger:"click",container:!1,keyboard:!0,html:!1,delay:0};this.$get=["$window","$rootScope","$tooltip","$timeout",function(t,n,i,r){function o(t,o){function l(e){if(e.target!==t[0])return e.target!==t[0]&&c.hide()}var c={},u=angular.extend({},e,o);c.$scope=u.scope&&u.scope.$new()||n.$new(),c=i(t,u);var d=t.parent();c.$onKeyDown=function(e){if(/(38|40)/.test(e.keyCode)){e.preventDefault(),e.stopPropagation();var t=angular.element(c.$element[0].querySelectorAll("li:not(.divider) a"));if(t.length){var n;angular.forEach(t,function(e,t){s&&s.call(e,":focus")&&(n=t)}),38===e.keyCode&&n>0?n--:40===e.keyCode&&n<t.length-1?n++:angular.isUndefined(n)&&(n=0),t.eq(n)[0].focus()}}};var f=c.show;c.show=function(){f(),r(function(){u.keyboard&&c.$element&&c.$element.on("keydown",c.$onKeyDown),a.on("click",l)},0,!1),d.hasClass("dropdown")&&d.addClass("open")};var p=c.hide;c.hide=function(){c.$isShown&&(u.keyboard&&c.$element&&c.$element.off("keydown",c.$onKeyDown),a.off("click",l),d.hasClass("dropdown")&&d.removeClass("open"),p())};var h=c.destroy;return c.destroy=function(){a.off("click",l),h()},c}var a=angular.element(t.document.body),s=Element.prototype.matchesSelector||Element.prototype.webkitMatchesSelector||Element.prototype.mozMatchesSelector||Element.prototype.msMatchesSelector||Element.prototype.oMatchesSelector;return o}]}).directive("bsDropdown",["$window","$sce","$dropdown",function(e,t,n){return{restrict:"EAC",scope:!0,compile:function(e,t){if(!t.bsDropdown){for(var i=e[0].nextSibling;i&&1!==i.nodeType;)i=i.nextSibling;i&&i.className.split(" ").indexOf("dropdown-menu")>=0&&(t.template=i.outerHTML,t.templateUrl=void 0,i.parentNode.removeChild(i))}return function(e,i,r){var o={scope:e};angular.forEach(["template","templateUrl","controller","controllerAs","placement","container","delay","trigger","keyboard","html","animation","id","autoClose"],function(e){angular.isDefined(t[e])&&(o[e]=t[e])});var a=/^(false|0|)$/i;angular.forEach(["html","container"],function(e){angular.isDefined(r[e])&&a.test(r[e])&&(o[e]=!1)}),r.bsDropdown&&e.$watch(r.bsDropdown,function(t,n){e.content=t},!0);var s=n(i,o);r.bsShow&&e.$watch(r.bsShow,function(e,t){s&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(dropdown),?/i)),!0===e?s.show():s.hide())}),e.$on("$destroy",function(){s&&s.destroy(),o=null,s=null})}}}}]),angular.module("mgcrea.ngStrap.modal",["mgcrea.ngStrap.core","mgcrea.ngStrap.helpers.dimensions"]).provider("$modal",function(){var e=this.defaults={animation:"am-fade",backdropAnimation:"am-fade",customClass:"",prefixClass:"modal",prefixEvent:"modal",placement:"top",templateUrl:"modal/modal.tpl.html",template:"",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0,size:null};this.$get=["$window","$rootScope","$bsCompiler","$animate","$timeout","$sce","dimensions",function(n,i,r,o,a,s,l){function c(t){function n(){T.$emit(S.prefixEvent+".show",k)}function a(){T.$emit(S.prefixEvent+".hide",k),h.removeClass(S.prefixClass+"-open"),S.animation&&h.removeClass(S.prefixClass+"-with-"+S.animation)}function l(){S.backdrop&&(A.on("click",w),O.on("click",w),O.on("wheel",x))}function c(){S.backdrop&&(A.off("click",w),O.off("click",w),O.off("wheel",x))}function y(){S.keyboard&&A.on("keyup",k.$onKeyUp)}function b(){S.keyboard&&A.off("keyup",k.$onKeyUp)}function w(e){e.target===e.currentTarget&&("static"===S.backdrop?k.focus():k.hide())}function x(e){e.preventDefault()}function C(){k.$isShown&&null!==A&&(c(),b()),M&&(M.$destroy(),M=null),A&&(A.remove(),A=k.$element=null)}var k={},S=k.$options=angular.extend({},e,t),E=k.$promise=r.compile(S),T=k.$scope=S.scope&&S.scope.$new()||i.$new();S.element||S.container||(S.container="body"),k.$id=S.id||S.element&&S.element.attr("id")||"",f(["title","content"],function(e){S[e]&&(T[e]=s.trustAsHtml(S[e]))}),T.$hide=function(){T.$$postDigest(function(){k.hide()})},T.$show=function(){T.$$postDigest(function(){k.show()})},T.$toggle=function(){T.$$postDigest(function(){k.toggle()})},k.$isShown=T.$isShown=!1;var D,A,M,O=angular.element('<div class="'+S.prefixClass+'-backdrop"/>');return O.css({position:"fixed",top:"0px",left:"0px",bottom:"0px",right:"0px"}),E.then(function(e){D=e,k.init()}),k.init=function(){S.show&&T.$$postDigest(function(){k.show()})},k.destroy=function(){C(),O&&(O.remove(),O=null),T.$destroy()},k.show=function(){if(!k.$isShown){var e,t;if(angular.isElement(S.container)?(e=S.container,t=S.container[0].lastChild?angular.element(S.container[0].lastChild):null):S.container?(e=d(S.container),t=e[0]&&e[0].lastChild?angular.element(e[0].lastChild):null):(e=null,t=S.element),A&&C(),M=k.$scope.$new(),A=k.$element=D.link(M,function(e,t){}),S.backdrop&&(A.css({"z-index":m+20*g}),O.css({"z-index":v+20*g}),g++),!T.$emit(S.prefixEvent+".show.before",k).defaultPrevented){A.css({display:"block"}).addClass(S.placement),S.customClass&&A.addClass(S.customClass),S.size&&$[S.size]&&angular.element(d(".modal-dialog",A[0])).addClass($[S.size]),S.animation&&(S.backdrop&&O.addClass(S.backdropAnimation),A.addClass(S.animation)),S.backdrop&&o.enter(O,h,null),angular.version.minor<=2?o.enter(A,e,t,n):o.enter(A,e,t).then(n),k.$isShown=T.$isShown=!0,u(T);var i=A[0];p(function(){i.focus()}),h.addClass(S.prefixClass+"-open"),S.animation&&h.addClass(S.prefixClass+"-with-"+S.animation),l(),y()}}},k.hide=function(){k.$isShown&&(S.backdrop&&g--,T.$emit(S.prefixEvent+".hide.before",k).defaultPrevented||(angular.version.minor<=2?o.leave(A,a):o.leave(A).then(a),S.backdrop&&o.leave(O),k.$isShown=T.$isShown=!1,u(T),c(),b()))},k.toggle=function(){k.$isShown?k.hide():k.show()},k.focus=function(){A[0].focus()},k.$onKeyUp=function(e){27===e.which&&k.$isShown&&(k.hide(),e.stopPropagation())},k}function u(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}function d(e,n){return angular.element((n||t).querySelectorAll(e))}var f=angular.forEach,p=n.requestAnimationFrame||n.setTimeout,h=angular.element(n.document.body),g=0,m=1050,v=1040,$={lg:"modal-lg",sm:"modal-sm"};return c}]}).directive("bsModal",["$window","$sce","$modal",function(e,t,n){return{restrict:"EAC",scope:!0,link:function(e,i,r,o){var a={scope:e,element:i,show:!1};angular.forEach(["template","templateUrl","controller","controllerAs","contentTemplate","placement","backdrop","keyboard","html","container","animation","backdropAnimation","id","prefixEvent","prefixClass","customClass","modalClass","size"],function(e){angular.isDefined(r[e])&&(a[e]=r[e])}),a.modalClass&&(a.customClass=a.modalClass);var s=/^(false|0|)$/i;angular.forEach(["backdrop","keyboard","html","container"],function(e){angular.isDefined(r[e])&&s.test(r[e])&&(a[e]=!1)}),angular.forEach(["title","content"],function(n){r[n]&&r.$observe(n,function(i,r){e[n]=t.trustAsHtml(i)})}),r.bsModal&&e.$watch(r.bsModal,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var l=n(a);i.on(r.trigger||"click",l.toggle),e.$on("$destroy",function(){l&&l.destroy(),a=null,l=null})}}}]),angular.version.minor<3&&angular.version.dot<14&&angular.module("ng").factory("$$rAF",["$window","$timeout",function(e,t){var n=e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame,i=e.cancelAnimationFrame||e.webkitCancelAnimationFrame||e.mozCancelAnimationFrame||e.webkitCancelRequestAnimationFrame,r=!!n,o=r?function(e){var t=n(e);return function(){i(t)}}:function(e){var n=t(e,16.66,!1);return function(){t.cancel(n)}};return o.supported=r,o}]),angular.module("mgcrea.ngStrap.helpers.parseOptions",[]).provider("$parseOptions",function(){var e=this.defaults={regexp:/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/};this.$get=["$parse","$q",function(t,n){function i(i,r){function o(e,t){return e.map(function(e,n){var i,r,o={};return o[u]=e,i=c(t,o),r=p(t,o),{label:i,value:r,index:n}})}var a={},s=angular.extend({},e,r);a.$values=[];var l,c,u,d,f,p,h;return a.init=function(){a.$match=l=i.match(s.regexp),c=t(l[2]||l[1]),u=l[4]||l[6],d=l[5],f=t(l[3]||""),p=t(l[2]?l[1]:u),h=t(l[7])},a.valuesFn=function(e,t){return n.when(h(e,t)).then(function(t){return angular.isArray(t)||(t=[]),a.$values=t.length?o(t,e):[],a.$values})},a.displayValue=function(e){var t={};return t[u]=e,c(t)},a.init(),a}return i}]}),angular.module("mgcrea.ngStrap.helpers.dimensions",[]).factory("dimensions",function(){function t(e){var t=e.ownerDocument,r=e.offsetParent||t;if(i(r,"#document"))return t.documentElement;for(;r&&!i(r,"html")&&"static"===n.css(r,"position");)r=r.offsetParent;return r||t.documentElement}var n={},i=n.nodeName=function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()};return n.css=function(t,n,i){var r;return r=t.currentStyle?t.currentStyle[n]:e.getComputedStyle?e.getComputedStyle(t)[n]:t.style[n],!0===i?parseFloat(r)||0:r},n.offset=function(t){var n=t.getBoundingClientRect(),i=t.ownerDocument;return{width:n.width||t.offsetWidth,height:n.height||t.offsetHeight,top:n.top+(e.pageYOffset||i.documentElement.scrollTop)-(i.documentElement.clientTop||0),left:n.left+(e.pageXOffset||i.documentElement.scrollLeft)-(i.documentElement.clientLeft||0)}},n.setOffset=function(e,t,i){var r,o,a,s,l,c,u,d=n.css(e,"position"),f=angular.element(e),p={};"static"===d&&(e.style.position="relative"),l=n.offset(e),a=n.css(e,"top"),c=n.css(e,"left"),u=("absolute"===d||"fixed"===d)&&(a+c).indexOf("auto")>-1,u?(r=n.position(e),s=r.top,o=r.left):(s=parseFloat(a)||0,o=parseFloat(c)||0),angular.isFunction(t)&&(t=t.call(e,i,l)),null!==t.top&&(p.top=t.top-l.top+s),null!==t.left&&(p.left=t.left-l.left+o),"using"in t?t.using.call(f,p):f.css({top:p.top+"px",left:p.left+"px"})},n.position=function(e){var r,o,a={top:0,left:0};return"fixed"===n.css(e,"position")?o=e.getBoundingClientRect():(r=t(e),o=n.offset(e),i(r,"html")||(a=n.offset(r)),a.top+=n.css(r,"borderTopWidth",!0),a.left+=n.css(r,"borderLeftWidth",!0)),{width:e.offsetWidth,height:e.offsetHeight,top:o.top-a.top-n.css(e,"marginTop",!0),left:o.left-a.left-n.css(e,"marginLeft",!0)}},n.height=function(e,t){var i=e.offsetHeight;return t?i+=n.css(e,"marginTop",!0)+n.css(e,"marginBottom",!0):i-=n.css(e,"paddingTop",!0)+n.css(e,"paddingBottom",!0)+n.css(e,"borderTopWidth",!0)+n.css(e,"borderBottomWidth",!0),i},n.width=function(e,t){var i=e.offsetWidth;return t?i+=n.css(e,"marginLeft",!0)+n.css(e,"marginRight",!0):i-=n.css(e,"paddingLeft",!0)+n.css(e,"paddingRight",!0)+n.css(e,"borderLeftWidth",!0)+n.css(e,"borderRightWidth",!0),i},n}),angular.module("mgcrea.ngStrap.helpers.debounce",[]).factory("debounce",["$timeout",function(e){return function(t,n,i){var r=null;return function(){var o=this,a=arguments,s=i&&!r;return r&&e.cancel(r),r=e(function(){r=null,i||t.apply(o,a)},n,!1),s&&t.apply(o,a),r}}}]).factory("throttle",["$timeout",function(e){return function(t,n,i){var r=null;return i||(i={}),function(){var o=this,a=arguments;r||(!1!==i.leading&&t.apply(o,a),r=e(function(){r=null,!1!==i.trailing&&t.apply(o,a)},n,!1))}}}]),angular.module("mgcrea.ngStrap.helpers.dateParser",[]).provider("$dateParser",["$localeProvider",function(e){function t(){this.year=1970,this.month=0,this.day=1,this.hours=0,this.minutes=0,this.seconds=0,this.milliseconds=0}function n(){}function i(e){return!isNaN(parseFloat(e))&&isFinite(e)}function r(e,t){for(var n=e.length,i=t.toString().toLowerCase(),r=0;r<n;r++)if(e[r].toLowerCase()===i)return r;return-1}t.prototype.setMilliseconds=function(e){this.milliseconds=e},t.prototype.setSeconds=function(e){this.seconds=e},t.prototype.setMinutes=function(e){this.minutes=e},t.prototype.setHours=function(e){this.hours=e},t.prototype.getHours=function(){return this.hours},t.prototype.setDate=function(e){this.day=e},t.prototype.setMonth=function(e){this.month=e},t.prototype.setFullYear=function(e){this.year=e},t.prototype.fromDate=function(e){return this.year=e.getFullYear(),this.month=e.getMonth(),this.day=e.getDate(),this.hours=e.getHours(),this.minutes=e.getMinutes(),this.seconds=e.getSeconds(),this.milliseconds=e.getMilliseconds(),this},t.prototype.toDate=function(){return new Date(this.year,this.month,this.day,this.hours,this.minutes,this.seconds,this.milliseconds)};var o=t.prototype,a=this.defaults={format:"shortDate",strict:!1};this.$get=["$locale","dateFilter",function(e,s){return function(l){function c(e){return h(u(e))}function u(e){var t=d(e),n=t.replace(/''/g,"\\'"),i=/('(?:\\'|.)*?')/,r=n.split(i),o=Object.keys(w),a=[];return angular.forEach(r,function(e){if(f(e))e=p(e);else for(var t=0;t<o.length;t++)e=e.split(o[t]).join("${"+t+"}");a.push(e)}),a.join("")}function d(e){return e.replace(/\\/g,"[\\\\]").replace(/-/g,"[-]").replace(/\./g,"[.]").replace(/\*/g,"[*]").replace(/\+/g,"[+]").replace(/\?/g,"[?]").replace(/\$/g,"[$]").replace(/\^/g,"[^]").replace(/\//g,"[/]").replace(/\\s/g,"[\\s]")}function f(e){return/^'.*'$/.test(e)}function p(e){return e.replace(/^'(.*)'$/,"$1")}function h(e){for(var t=Object.keys(w),n=e,i=0;i<t.length;i++)n=n.split("${"+i+"}").join("("+w[t[i]]+")");return new RegExp("^"+n+"$",["i"])}function g(e){return m(u(e))}function m(e){for(var t,n,i,r,o=Object.keys(w),a=new RegExp("\\${(\\d+)}","g"),s=[];null!==(t=a.exec(e));)n=t[1],i=o[n],r=x[i],s.push(r);return s}var v,$,y=angular.extend({},a,l),b={},w={sss:"[0-9]{3}",ss:"[0-5][0-9]",s:y.strict?"[1-5]?[0-9]":"[0-9]|[0-5][0-9]",mm:"[0-5][0-9]",m:y.strict?"[1-5]?[0-9]":"[0-9]|[0-5][0-9]",HH:"[01][0-9]|2[0-3]",H:y.strict?"1?[0-9]|2[0-3]":"[01]?[0-9]|2[0-3]",hh:"[0][1-9]|[1][012]",h:y.strict?"[1-9]|1[012]":"0?[1-9]|1[012]",a:"AM|PM",EEEE:e.DATETIME_FORMATS.DAY.join("|"),EEE:e.DATETIME_FORMATS.SHORTDAY.join("|"),dd:"0[1-9]|[12][0-9]|3[01]",d:y.strict?"[1-9]|[1-2][0-9]|3[01]":"0?[1-9]|[1-2][0-9]|3[01]",MMMM:e.DATETIME_FORMATS.MONTH.join("|"),MMM:e.DATETIME_FORMATS.SHORTMONTH.join("|"),MM:"0[1-9]|1[012]",M:y.strict?"[1-9]|1[012]":"0?[1-9]|1[012]",yyyy:"[1]{1}[0-9]{3}|[2]{1}[0-9]{3}",yy:"[0-9]{2}",y:y.strict?"-?(0|[1-9][0-9]{0,3})":"-?0*[0-9]{1,4}"},x={sss:o.setMilliseconds,ss:o.setSeconds,s:o.setSeconds,mm:o.setMinutes,m:o.setMinutes,HH:o.setHours,H:o.setHours,hh:o.setHours,h:o.setHours,EEEE:n,EEE:n,dd:o.setDate,d:o.setDate,a:function(e){var t=this.getHours()%12;return this.setHours(e.match(/pm/i)?t+12:t)},MMMM:function(t){return this.setMonth(r(e.DATETIME_FORMATS.MONTH,t))},MMM:function(t){return this.setMonth(r(e.DATETIME_FORMATS.SHORTMONTH,t))},MM:function(e){return this.setMonth(1*e-1)},M:function(e){return this.setMonth(1*e-1)},yyyy:o.setFullYear,yy:function(e){return this.setFullYear(2e3+1*e)},y:function(e){return 1*e<=50&&2===e.length?this.setFullYear(2e3+1*e):this.setFullYear(1*e)}};return b.init=function(){b.$format=e.DATETIME_FORMATS[y.format]||y.format,v=c(b.$format),$=g(b.$format)},b.isValid=function(e){return angular.isDate(e)?!isNaN(e.getTime()):v.test(e)},b.parse=function(n,i,r,o){r&&(r=e.DATETIME_FORMATS[r]||r),angular.isDate(n)&&(n=s(n,r||b.$format,o));var a=r?c(r):v,l=r?g(r):$,u=a.exec(n);if(!u)return!1;for(var d=i&&!isNaN(i.getTime())?(new t).fromDate(i):(new t).fromDate(new Date(1970,0,1,0)),f=0;f<u.length-1;f++)l[f]&&l[f].call(d,u[f+1]);var p=d.toDate();return parseInt(d.day,10)===p.getDate()&&p},b.getDateForAttribute=function(e,t){var n;if("today"===t){var r=new Date;n=new Date(r.getFullYear(),r.getMonth(),r.getDate()+("maxDate"===e?1:0),0,0,0,"minDate"===e?0:-1)}else n=angular.isString(t)&&t.match(/^".+"$/)?new Date(t.substr(1,t.length-2)):i(t)?new Date(parseInt(t,10)):angular.isString(t)&&0===t.length?"minDate"===e?-1/0:1/0:new Date(t);return n},b.getTimeForAttribute=function(e,t){return"now"===t?(new Date).setFullYear(1970,0,1):angular.isString(t)&&t.match(/^".+"$/)?new Date(t.substr(1,t.length-2)).setFullYear(1970,0,1):i(t)?new Date(parseInt(t,10)).setFullYear(1970,0,1):angular.isString(t)&&0===t.length?"minTime"===e?-1/0:1/0:b.parse(t,new Date(1970,0,1,0))},b.daylightSavingAdjust=function(e){return e?(e.setHours(e.getHours()>12?e.getHours()+2:0),e):null},b.timezoneOffsetAdjust=function(e,t,n){return e?(t&&"UTC"===t&&(e=new Date(e.getTime()),e.setMinutes(e.getMinutes()+(n?-1:1)*e.getTimezoneOffset())),e):null},b.init(),b}}]}]),angular.module("mgcrea.ngStrap.helpers.dateFormatter",[]).service("$dateFormatter",["$locale","dateFilter",function(e,t){function n(e){return/(h+)([:\.])?(m+)([:\.])?(s*)[ ]?(a?)/i.exec(e).slice(1)}this.getDefaultLocale=function(){return e.id},this.getDatetimeFormat=function(t,n){return e.DATETIME_FORMATS[t]||t},this.weekdaysShort=function(t){return e.DATETIME_FORMATS.SHORTDAY},this.hoursFormat=function(e){return n(e)[0]},this.minutesFormat=function(e){return n(e)[2]},this.secondsFormat=function(e){return n(e)[4]},this.timeSeparator=function(e){return n(e)[1]},this.showSeconds=function(e){return!!n(e)[4]},this.showAM=function(e){return!!n(e)[5]},this.formatDate=function(e,n,i,r){return t(e,n,r)}}]),angular.module("mgcrea.ngStrap.core",[]).service("$bsCompiler",i),angular.module("mgcrea.ngStrap.datepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.helpers.dateFormatter","mgcrea.ngStrap.tooltip"]).provider("$datepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"datepicker",placement:"bottom-left",templateUrl:"datepicker/datepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!1,dateType:"date",dateFormat:"shortDate",timezone:null,modelDateFormat:null,dayFormat:"dd",monthFormat:"MMM",yearFormat:"yyyy",monthTitleFormat:"MMMM yyyy",yearTitleFormat:"yyyy",strictFormat:!1,autoclose:!1,minDate:-1/0,maxDate:1/0,startView:0,minView:0,startWeek:0,daysOfWeekDisabled:"",iconLeft:"glyphicon glyphicon-chevron-left",iconRight:"glyphicon glyphicon-chevron-right"};this.$get=["$window","$document","$rootScope","$sce","$dateFormatter","datepickerViews","$tooltip","$timeout",function(t,n,i,r,o,a,s,l){function c(t,n,i){function r(e){e.selected=c.$isSelected(e.date)}function o(){t[0].focus()}var c=s(t,angular.extend({},e,i)),f=i.scope,p=c.$options,h=c.$scope;p.startView&&(p.startView-=p.minView);var g=a(c);c.$views=g.views;var m=g.viewDate;h.$mode=p.startView,h.$iconLeft=p.iconLeft,h.$iconRight=p.iconRight;var v=c.$views[h.$mode];h.$select=function(e){c.select(e)},h.$selectPane=function(e){c.$selectPane(e)},h.$toggleMode=function(){c.setMode((h.$mode+1)%c.$views.length)},c.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())&&(c.$date=e,v.update.call(v,e)),c.$build(!0)},c.updateDisabledDates=function(e){p.disabledDateRanges=e;for(var t=0,n=h.rows.length;t<n;t++)angular.forEach(h.rows[t],c.$setDisabledEl)},c.select=function(e,t){angular.isDate(n.$dateValue)||(n.$dateValue=new Date(e)),!h.$mode||t?(n.$setViewValue(angular.copy(e)),n.$render(),p.autoclose&&!t&&l(function(){c.hide(!0)})):(angular.extend(m,{year:e.getFullYear(),month:e.getMonth(),date:e.getDate()}),c.setMode(h.$mode-1),c.$build())},c.setMode=function(e){h.$mode=e,v=c.$views[h.$mode],c.$build()},c.$build=function(e){!0===e&&v.built||(!1!==e||v.built)&&v.build.call(v)},c.$updateSelected=function(){for(var e=0,t=h.rows.length;e<t;e++)angular.forEach(h.rows[e],r)},c.$isSelected=function(e){return v.isSelected(e)},c.$setDisabledEl=function(e){e.disabled=v.isDisabled(e.date)},c.$selectPane=function(e){var t=v.steps,n=new Date(Date.UTC(m.year+(t.year||0)*e,m.month+(t.month||0)*e,1));angular.extend(m,{year:n.getUTCFullYear(),month:n.getUTCMonth(),date:n.getUTCDate()}),c.$build()},c.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),d){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},c.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return void(h.$mode?h.$apply(function(){c.setMode(h.$mode-1)}):c.hide(!0));v.onKeyDown(e),f.$digest()}};var $=c.init;c.init=function(){if(u&&p.useNative)return t.prop("type","date"),void t.css("-webkit-appearance","textfield");d&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",o)),$()};var y=c.destroy;c.destroy=function(){u&&p.useNative&&t.off("click",o),y()};var b=c.show;c.show=function(){!d&&t.attr("readonly")||t.attr("disabled")||(b(),l(function(){c.$isShown&&(c.$element.on(d?"touchstart":"mousedown",c.$onMouseDown),p.keyboard&&t.on("keydown",c.$onKeyDown))},0,!1))};var w=c.hide;return c.hide=function(e){c.$isShown&&(c.$element.off(d?"touchstart":"mousedown",c.$onMouseDown),p.keyboard&&t.off("keydown",c.$onKeyDown),w(e))},c}var u=/(ip[ao]d|iphone|android)/gi.test(t.navigator.userAgent),d="createTouch"in t.document&&u;return e.lang||(e.lang=o.getDefaultLocale()),c.defaults=e,c}]}).directive("bsDatepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$datepicker",function(e,t,n,i,r,o){var a=/(ip[ao]d|iphone|android)/gi.test(e.navigator.userAgent);return{restrict:"EAC",require:"ngModel",link:function(e,t,n,s){function l(e){return e&&e.length?e:null}function c(e){if(angular.isDate(e)){var t=isNaN(p.$options.minDate)||e.getTime()>=p.$options.minDate,n=isNaN(p.$options.maxDate)||e.getTime()<=p.$options.maxDate,i=t&&n;s.$setValidity("date",i),s.$setValidity("min",t),s.$setValidity("max",n),i&&(s.$dateValue=e)}}
+function u(){return!s.$dateValue||isNaN(s.$dateValue.getTime())?"":g(s.$dateValue,d.dateFormat)}var d={scope:e};angular.forEach(["template","templateUrl","controller","controllerAs","placement","container","delay","trigger","html","animation","autoclose","dateType","dateFormat","timezone","modelDateFormat","dayFormat","strictFormat","startWeek","startDate","useNative","lang","startView","minView","iconLeft","iconRight","daysOfWeekDisabled","id","prefixClass","prefixEvent"],function(e){angular.isDefined(n[e])&&(d[e]=n[e])});var f=/^(false|0|)$/i;angular.forEach(["html","container","autoclose","useNative"],function(e){angular.isDefined(n[e])&&f.test(n[e])&&(d[e]=!1)});var p=o(t,s,d);d=p.$options,a&&d.useNative&&(d.dateFormat="yyyy-MM-dd");var h=d.lang,g=function(e,t){return i.formatDate(e,t,h)},m=r({format:d.dateFormat,lang:h,strict:d.strictFormat});n.bsShow&&e.$watch(n.bsShow,function(e,t){p&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(datepicker),?/i)),!0===e?p.show():p.hide())}),angular.forEach(["minDate","maxDate"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){p.$options[e]=m.getDateForAttribute(e,t),isNaN(p.$options[e])||p.$build(!1),c(s.$dateValue)})}),angular.isDefined(n.dateFormat)&&n.$observe("dateFormat",function(e){p.$options.dateFormat=e}),e.$watch(n.ngModel,function(e,t){p.update(s.$dateValue)},!0),angular.isDefined(n.disabledDates)&&e.$watch(n.disabledDates,function(e,t){e=l(e),t=l(t),e&&p.updateDisabledDates(e)}),s.$parsers.unshift(function(e){var t;if(!e)return s.$setValidity("date",!0),null;var n=m.parse(e,s.$dateValue);return!n||isNaN(n.getTime())?void s.$setValidity("date",!1):(c(n),"string"===d.dateType?(t=m.timezoneOffsetAdjust(n,d.timezone,!0),g(t,d.modelDateFormat||d.dateFormat)):(t=m.timezoneOffsetAdjust(s.$dateValue,d.timezone,!0),"number"===d.dateType?t.getTime():"unix"===d.dateType?t.getTime()/1e3:"iso"===d.dateType?t.toISOString():new Date(t)))}),s.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?NaN:angular.isDate(e)?e:"string"===d.dateType?m.parse(e,null,d.modelDateFormat):"unix"===d.dateType?new Date(1e3*e):new Date(e),s.$dateValue=m.timezoneOffsetAdjust(t,d.timezone),u()}),s.$render=function(){t.val(u())},e.$on("$destroy",function(){p&&p.destroy(),d=null,p=null})}}}]).provider("datepickerViews",function(){function e(e,t){for(var n=[];e.length>0;)n.push(e.splice(0,t));return n}function t(e,t){return(e%t+t)%t}this.$get=["$dateFormatter","$dateParser","$sce",function(n,i,r){return function(o){var a=o.$scope,s=o.$options,l=s.lang,c=function(e,t){return n.formatDate(e,t,l)},u=i({format:s.dateFormat,lang:l,strict:s.strictFormat}),d=n.weekdaysShort(l),f=d.slice(s.startWeek).concat(d.slice(0,s.startWeek)),p=r.trustAsHtml('<th class="dow text-center">'+f.join('</th><th class="dow text-center">')+"</th>"),h=o.$date||(s.startDate?u.getDateForAttribute("startDate",s.startDate):new Date),g={year:h.getFullYear(),month:h.getMonth(),date:h.getDate()},m=[{format:s.dayFormat,split:7,steps:{month:1},update:function(e,t){!this.built||t||e.getFullYear()!==g.year||e.getMonth()!==g.month?(angular.extend(g,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$build()):e.getDate()===g.date&&1!==e.getDate()||(g.date=o.$date.getDate(),o.$updateSelected())},build:function(){var n=new Date(g.year,g.month,1),i=n.getTimezoneOffset(),r=new Date(+n-864e5*t(n.getDay()-s.startWeek,7)),l=r.getTimezoneOffset(),d=u.timezoneOffsetAdjust(new Date,s.timezone).toDateString();l!==i&&(r=new Date(+r+6e4*(l-i)));for(var f,h=[],m=0;m<42;m++)f=u.daylightSavingAdjust(new Date(r.getFullYear(),r.getMonth(),r.getDate()+m)),h.push({date:f,isToday:f.toDateString()===d,label:c(f,this.format),selected:o.$date&&this.isSelected(f),muted:f.getMonth()!==g.month,disabled:this.isDisabled(f)});a.title=c(n,s.monthTitleFormat),a.showLabels=!0,a.labels=p,a.rows=e(h,this.split),this.built=!0},isSelected:function(e){return o.$date&&e.getFullYear()===o.$date.getFullYear()&&e.getMonth()===o.$date.getMonth()&&e.getDate()===o.$date.getDate()},isDisabled:function(e){var t=e.getTime();if(t<s.minDate||t>s.maxDate)return!0;if(-1!==s.daysOfWeekDisabled.indexOf(e.getDay()))return!0;if(s.disabledDateRanges)for(var n=0;n<s.disabledDateRanges.length;n++)if(t>=s.disabledDateRanges[n].start&&t<=s.disabledDateRanges[n].end)return!0;return!1},onKeyDown:function(e){if(o.$date){var t,n=o.$date.getTime();37===e.keyCode?t=new Date(n-864e5):38===e.keyCode?t=new Date(n-6048e5):39===e.keyCode?t=new Date(n+864e5):40===e.keyCode&&(t=new Date(n+6048e5)),this.isDisabled(t)||o.select(t,!0)}}},{name:"month",format:s.monthFormat,split:4,steps:{year:1},update:function(e,t){this.built&&e.getFullYear()===g.year?e.getMonth()!==g.month&&(angular.extend(g,{month:o.$date.getMonth(),date:o.$date.getDate()}),o.$updateSelected()):(angular.extend(g,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$build())},build:function(){for(var t,n=[],i=0;i<12;i++)t=new Date(g.year,i,1),n.push({date:t,label:c(t,this.format),selected:o.$isSelected(t),disabled:this.isDisabled(t)});a.title=c(t,s.yearTitleFormat),a.showLabels=!1,a.rows=e(n,this.split),this.built=!0},isSelected:function(e){return o.$date&&e.getFullYear()===o.$date.getFullYear()&&e.getMonth()===o.$date.getMonth()},isDisabled:function(e){return+new Date(e.getFullYear(),e.getMonth()+1,0)<s.minDate||e.getTime()>s.maxDate},onKeyDown:function(e){if(o.$date){var t=o.$date.getMonth(),n=new Date(o.$date);37===e.keyCode?n.setMonth(t-1):38===e.keyCode?n.setMonth(t-4):39===e.keyCode?n.setMonth(t+1):40===e.keyCode&&n.setMonth(t+4),this.isDisabled(n)||o.select(n,!0)}}},{name:"year",format:s.yearFormat,split:4,steps:{year:12},update:function(e,t){!this.built||t||parseInt(e.getFullYear()/20,10)!==parseInt(g.year/20,10)?(angular.extend(g,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$build()):e.getFullYear()!==g.year&&(angular.extend(g,{year:o.$date.getFullYear(),month:o.$date.getMonth(),date:o.$date.getDate()}),o.$updateSelected())},build:function(){for(var t,n=g.year-g.year%(3*this.split),i=[],r=0;r<12;r++)t=new Date(n+r,0,1),i.push({date:t,label:c(t,this.format),selected:o.$isSelected(t),disabled:this.isDisabled(t)});a.title=i[0].label+"-"+i[i.length-1].label,a.showLabels=!1,a.rows=e(i,this.split),this.built=!0},isSelected:function(e){return o.$date&&e.getFullYear()===o.$date.getFullYear()},isDisabled:function(e){return+new Date(e.getFullYear()+1,0,0)<s.minDate||e.getTime()>s.maxDate},onKeyDown:function(e){if(o.$date){var t=o.$date.getFullYear(),n=new Date(o.$date);37===e.keyCode?n.setYear(t-1):38===e.keyCode?n.setYear(t-4):39===e.keyCode?n.setYear(t+1):40===e.keyCode&&n.setYear(t+4),this.isDisabled(n)||o.select(n,!0)}}}];return{views:s.minView?Array.prototype.slice.call(m,s.minView):m,viewDate:g}}}]}),angular.module("mgcrea.ngStrap.collapse",[]).provider("$collapse",function(){var e=this.defaults={animation:"am-collapse",disallowToggle:!1,activeClass:"in",startCollapsed:!1,allowMultiple:!1},t=this.controller=function(t,n,i){function r(e){for(var t=l.$targets.$active,n=0;n<t.length;n++)e<t[n]&&(t[n]=t[n]-1),t[n]===l.$targets.length&&(t[n]=l.$targets.length-1)}function o(e){return-1!==l.$targets.$active.indexOf(e)}function a(e){var t=l.$targets.$active.indexOf(e);-1!==t&&l.$targets.$active.splice(t,1)}function s(e){l.$options.allowMultiple||l.$targets.$active.splice(0,1),-1===l.$targets.$active.indexOf(e)&&l.$targets.$active.push(e)}var l=this;l.$options=angular.copy(e),angular.forEach(["animation","disallowToggle","activeClass","startCollapsed","allowMultiple"],function(e){angular.isDefined(i[e])&&(l.$options[e]=i[e])});var c=/^(false|0|)$/i;angular.forEach(["disallowToggle","startCollapsed","allowMultiple"],function(e){angular.isDefined(i[e])&&c.test(i[e])&&(l.$options[e]=!1)}),l.$toggles=[],l.$targets=[],l.$viewChangeListeners=[],l.$registerToggle=function(e){l.$toggles.push(e)},l.$registerTarget=function(e){l.$targets.push(e)},l.$unregisterToggle=function(e){var t=l.$toggles.indexOf(e);l.$toggles.splice(t,1)},l.$unregisterTarget=function(e){var t=l.$targets.indexOf(e);l.$targets.splice(t,1),l.$options.allowMultiple&&a(e),r(t),l.$viewChangeListeners.forEach(function(e){e()})},l.$targets.$active=l.$options.startCollapsed?[]:[0],l.$setActive=t.$setActive=function(e){angular.isArray(e)?l.$targets.$active=e:!l.$options.disallowToggle&&o(e)?a(e):s(e),l.$viewChangeListeners.forEach(function(e){e()})},l.$activeIndexes=function(){return l.$options.allowMultiple?l.$targets.$active:1===l.$targets.$active.length?l.$targets.$active[0]:-1}};this.$get=function(){var n={};return n.defaults=e,n.controller=t,n}}).directive("bsCollapse",["$window","$animate","$collapse",function(e,t,n){return{require:["?ngModel","bsCollapse"],controller:["$scope","$element","$attrs",n.controller],link:function(e,t,n,i){var r=i[0],o=i[1];r&&(o.$viewChangeListeners.push(function(){r.$setViewValue(o.$activeIndexes())}),r.$formatters.push(function(e){if(angular.isArray(e))o.$setActive(e);else{var t=o.$activeIndexes();angular.isArray(t)?-1===t.indexOf(1*e)&&o.$setActive(1*e):t!==1*e&&o.$setActive(1*e)}return e}))}}}]).directive("bsCollapseToggle",function(){return{require:["^?ngModel","^bsCollapse"],link:function(e,t,n,i){var r=i[1];t.attr("data-toggle","collapse"),r.$registerToggle(t),e.$on("$destroy",function(){r.$unregisterToggle(t)}),t.on("click",function(){if(!n.disabled){var i=n.bsCollapseToggle&&"bs-collapse-toggle"!==n.bsCollapseToggle?n.bsCollapseToggle:r.$toggles.indexOf(t);r.$setActive(1*i),e.$apply()}})}}}).directive("bsCollapseTarget",["$animate",function(e){return{require:["^?ngModel","^bsCollapse"],link:function(t,n,i,r){function o(){var t=a.$targets.indexOf(n),i=a.$activeIndexes(),r="removeClass";angular.isArray(i)?-1!==i.indexOf(t)&&(r="addClass"):t===i&&(r="addClass"),e[r](n,a.$options.activeClass)}var a=r[1];n.addClass("collapse"),a.$options.animation&&n.addClass(a.$options.animation),a.$registerTarget(n),t.$on("$destroy",function(){a.$unregisterTarget(n)}),a.$viewChangeListeners.push(function(){o()}),o()}}}]),angular.module("mgcrea.ngStrap.button",[]).provider("$button",function(){var e=this.defaults={activeClass:"active",toggleEvent:"click"};this.$get=function(){return{defaults:e}}}).directive("bsCheckboxGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="checkbox"]');angular.forEach(n,function(e){var n=angular.element(e);n.attr("bs-checkbox",""),n.attr("ng-model",t.ngModel+"."+n.attr("value"))})}}}).directive("bsCheckbox",["$button","$$rAF",function(e,t){var n=e.defaults,i=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,r,o,a){var s=n,l="INPUT"===r[0].nodeName,c=l?r.parent():r,u=!angular.isDefined(o.trueValue)||o.trueValue;i.test(o.trueValue)&&(u=e.$eval(o.trueValue));var d=!!angular.isDefined(o.falseValue)&&o.falseValue;i.test(o.falseValue)&&(d=e.$eval(o.falseValue));var f="boolean"!=typeof u||"boolean"!=typeof d;f&&(a.$parsers.push(function(e){return e?u:d}),a.$formatters.push(function(e){return angular.equals(e,u)}),e.$watch(o.ngModel,function(e,t){a.$render()})),a.$render=function(){var e=angular.equals(a.$modelValue,u);t(function(){l&&(r[0].checked=e),c.toggleClass(s.activeClass,e)})},r.bind(s.toggleEvent,function(){e.$apply(function(){l||a.$setViewValue(!c.hasClass("active")),f||a.$render()})})}}}]).directive("bsRadioGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="radio"]');angular.forEach(n,function(e){angular.element(e).attr("bs-radio",""),angular.element(e).attr("ng-model",t.ngModel)})}}}).directive("bsRadio",["$button","$$rAF",function(e,t){var n=e.defaults,i=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,r,o,a){var s,l=n,c="INPUT"===r[0].nodeName,u=c?r.parent():r;o.$observe("value",function(t){s="boolean"!=typeof t&&i.test(t)?e.$eval(t):t,a.$render()}),a.$render=function(){var e=angular.equals(a.$modelValue,s);t(function(){c&&(r[0].checked=e),u.toggleClass(l.activeClass,e)})},r.bind(l.toggleEvent,function(){e.$apply(function(){a.$setViewValue(s),a.$render()})})}}}]),angular.module("mgcrea.ngStrap.alert",["mgcrea.ngStrap.modal"]).provider("$alert",function(){var e=this.defaults={animation:"am-fade",prefixClass:"alert",prefixEvent:"alert",placement:null,templateUrl:"alert/alert.tpl.html",container:!1,element:null,backdrop:!1,keyboard:!0,show:!0,duration:!1,type:!1,dismissable:!0};this.$get=["$modal","$timeout",function(t,n){function i(i){var r={},o=angular.extend({},e,i);r=t(o),r.$scope.dismissable=!!o.dismissable,o.type&&(r.$scope.type=o.type);var a=r.show;return o.duration&&(r.show=function(){a(),n(function(){r.hide()},1e3*o.duration)}),r}return i}]}).directive("bsAlert",["$window","$sce","$alert",function(e,t,n){return{restrict:"EAC",scope:!0,link:function(e,i,r,o){var a={scope:e,element:i,show:!1};angular.forEach(["template","templateUrl","controller","controllerAs","placement","keyboard","html","container","animation","duration","dismissable"],function(e){angular.isDefined(r[e])&&(a[e]=r[e])});var s=/^(false|0|)$/i;angular.forEach(["keyboard","html","container","dismissable"],function(e){angular.isDefined(r[e])&&s.test(r[e])&&(a[e]=!1)}),e.hasOwnProperty("title")||(e.title=""),angular.forEach(["title","content","type"],function(n){r[n]&&r.$observe(n,function(i,r){e[n]=t.trustAsHtml(i)})}),r.bsAlert&&e.$watch(r.bsAlert,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var l=n(a);i.on(r.trigger||"click",l.toggle),e.$on("$destroy",function(){l&&l.destroy(),a=null,l=null})}}}]),angular.module("mgcrea.ngStrap.aside",["mgcrea.ngStrap.modal"]).provider("$aside",function(){var e=this.defaults={animation:"am-fade-and-slide-right",prefixClass:"aside",prefixEvent:"aside",placement:"right",templateUrl:"aside/aside.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=["$modal",function(t){function n(n){var i=angular.extend({},e,n);return t(i)}return n}]}).directive("bsAside",["$window","$sce","$aside",function(e,t,n){return{restrict:"EAC",scope:!0,link:function(e,i,r,o){var a={scope:e,element:i,show:!1};angular.forEach(["template","templateUrl","controller","controllerAs","contentTemplate","placement","backdrop","keyboard","html","container","animation"],function(e){angular.isDefined(r[e])&&(a[e]=r[e])});var s=/^(false|0|)$/i;angular.forEach(["backdrop","keyboard","html","container"],function(e){angular.isDefined(r[e])&&s.test(r[e])&&(a[e]=!1)}),angular.forEach(["title","content"],function(n){r[n]&&r.$observe(n,function(i,r){e[n]=t.trustAsHtml(i)})}),r.bsAside&&e.$watch(r.bsAside,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var l=n(a);i.on(r.trigger||"click",l.toggle),e.$on("$destroy",function(){l&&l.destroy(),a=null,l=null})}}}]),angular.module("mgcrea.ngStrap.affix",["mgcrea.ngStrap.helpers.dimensions","mgcrea.ngStrap.helpers.debounce"]).provider("$affix",function(){var e=this.defaults={offsetTop:"auto",inlineStyles:!0};this.$get=["$window","debounce","dimensions",function(t,n,i){function r(r,s){function l(e,t,n){var i=c(),r=u();return i<=v?"top":null!==e&&i+e<=t.top?"middle":null!==$&&t.top+n+g>=r-$?"bottom":"middle"}function c(){return p[0]===t?t.pageYOffset:p[0].scrollTop}function u(){return p[0]===t?t.document.body.scrollHeight:p[0].scrollHeight}var d={},f=angular.extend({},e,s),p=f.target,h=!1,g=0,m=0,v=0,$=0,y=null,b=null,w=r.parent();if(f.offsetParent)if(f.offsetParent.match(/^\d+$/))for(var x=0;x<1*f.offsetParent-1;x++)w=w.parent();else w=angular.element(f.offsetParent);return d.init=function(){this.$parseOffsets(),m=i.offset(r[0]).top+g,h=!r[0].style.width,p.on("scroll",this.checkPosition),p.on("click",this.checkPositionWithEventLoop),a.on("resize",this.$debouncedOnResize),this.checkPosition(),this.checkPositionWithEventLoop()},d.destroy=function(){p.off("scroll",this.checkPosition),p.off("click",this.checkPositionWithEventLoop),a.off("resize",this.$debouncedOnResize)},d.checkPositionWithEventLoop=function(){setTimeout(d.checkPosition,1)},d.checkPosition=function(){var e=c(),t=i.offset(r[0]),n=i.height(r[0]),a=l(b,t,n);y!==a&&(y=a,"top"===a?(b=null,h&&r.css("width",""),f.inlineStyles&&(r.css("position",f.offsetParent?"":"relative"),r.css("top",""))):"bottom"===a?(b=f.offsetUnpin?-1*f.offsetUnpin:t.top-e,h&&r.css("width",""),f.inlineStyles&&(r.css("position",f.offsetParent?"":"relative"),r.css("top",f.offsetParent?"":o[0].offsetHeight-$-n-m+"px"))):(b=null,h&&r.css("width",r[0].offsetWidth+"px"),f.inlineStyles&&(r.css("position","fixed"),r.css("top",g+"px"))),r.removeClass("affix affix-top affix-bottom").addClass("affix"+("middle"!==a?"-"+a:"")))},d.$onResize=function(){d.$parseOffsets(),d.checkPosition()},d.$debouncedOnResize=n(d.$onResize,50),d.$parseOffsets=function(){var e=r.css("position");f.inlineStyles&&r.css("position",f.offsetParent?"":"relative"),f.offsetTop&&("auto"===f.offsetTop&&(f.offsetTop="+0"),f.offsetTop.match(/^[-+]\d+$/)?(g=1*-f.offsetTop,v=f.offsetParent?i.offset(w[0]).top+1*f.offsetTop:i.offset(r[0]).top-i.css(r[0],"marginTop",!0)+1*f.offsetTop):v=1*f.offsetTop),f.offsetBottom&&($=f.offsetParent&&f.offsetBottom.match(/^[-+]\d+$/)?u()-(i.offset(w[0]).top+i.height(w[0]))+1*f.offsetBottom+1:1*f.offsetBottom),f.inlineStyles&&r.css("position",e)},d.init(),d}var o=angular.element(t.document.body),a=angular.element(t);return r}]}).directive("bsAffix",["$affix","$window",function(e,t){return{restrict:"EAC",require:"^?bsAffixTarget",link:function(n,i,r,o){var a={scope:n,target:o?o.$element:angular.element(t)};angular.forEach(["offsetTop","offsetBottom","offsetParent","offsetUnpin","inlineStyles"],function(e){if(angular.isDefined(r[e])){var t=r[e];/true/i.test(t)&&(t=!0),/false/i.test(t)&&(t=!1),a[e]=t}});var s=e(i,a);n.$on("$destroy",function(){s&&s.destroy(),a=null,s=null})}}}]).directive("bsAffixTarget",function(){return{controller:["$element",function(e){this.$element=e}]}}),angular.module("mgcrea.ngStrap",["mgcrea.ngStrap.modal","mgcrea.ngStrap.aside","mgcrea.ngStrap.alert","mgcrea.ngStrap.button","mgcrea.ngStrap.select","mgcrea.ngStrap.datepicker","mgcrea.ngStrap.timepicker","mgcrea.ngStrap.navbar","mgcrea.ngStrap.tooltip","mgcrea.ngStrap.popover","mgcrea.ngStrap.dropdown","mgcrea.ngStrap.typeahead","mgcrea.ngStrap.scrollspy","mgcrea.ngStrap.affix","mgcrea.ngStrap.tab","mgcrea.ngStrap.collapse"])}(window,document),function(e,t,n){"use strict";angular.module("mgcrea.ngStrap.aside").run(["$templateCache",function(e){e.put("aside/aside.tpl.html",'<div class="aside" tabindex="-1" role="dialog"><div class="aside-dialog"><div class="aside-content"><div class="aside-header" ng-show="title"><button type="button" class="close" ng-click="$hide()">&times;</button><h4 class="aside-title" ng-bind="title"></h4></div><div class="aside-body" ng-bind="content"></div><div class="aside-footer"><button type="button" class="btn btn-default" ng-click="$hide()">Close</button></div></div></div></div>')}]),angular.module("mgcrea.ngStrap.alert").run(["$templateCache",function(e){e.put("alert/alert.tpl.html",'<div class="alert" ng-class="[type ? \'alert-\' + type : null]"><button type="button" class="close" ng-if="dismissable" ng-click="$hide()">&times;</button> <strong ng-bind="title"></strong>&nbsp;<span ng-bind-html="content"></span></div>')}]),angular.module("mgcrea.ngStrap.datepicker").run(["$templateCache",function(e){e.put("datepicker/datepicker.tpl.html",'<div class="dropdown-menu datepicker" ng-class="\'datepicker-mode-\' + $mode" style="max-width: 320px"><table style="table-layout: fixed; height: 100%; width: 100%"><thead><tr class="text-center"><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$selectPane(-1)"><i class="{{$iconLeft}}"></i></button></th><th colspan="{{ rows[0].length - 2 }}"><button tabindex="-1" type="button" class="btn btn-default btn-block text-strong" ng-click="$toggleMode()"><strong style="text-transform: capitalize" ng-bind="title"></strong></button></th><th><button tabindex="-1" type="button" class="btn btn-default pull-right" ng-click="$selectPane(+1)"><i class="{{$iconRight}}"></i></button></th></tr><tr ng-if="showLabels" ng-bind-html="labels"></tr></thead><tbody><tr ng-repeat="(i, row) in rows" height="{{ 100 / rows.length }}%"><td class="text-center" ng-repeat="(j, el) in row"><button tabindex="-1" type="button" class="btn btn-default" style="width: 100%" ng-class="{\'btn-primary\': el.selected, \'btn-info btn-today\': el.isToday && !el.selected}" ng-click="$select(el.date)" ng-disabled="el.disabled"><span ng-class="{\'text-muted\': el.muted}" ng-bind="el.label"></span></button></td></tr></tbody></table></div>')}]),angular.module("mgcrea.ngStrap.modal").run(["$templateCache",function(e){e.put("modal/modal.tpl.html",'<div class="modal" tabindex="-1" role="dialog" aria-hidden="true"><div class="modal-dialog"><div class="modal-content"><div class="modal-header" ng-show="title"><button type="button" class="close" aria-label="Close" ng-click="$hide()"><span aria-hidden="true">&times;</span></button><h4 class="modal-title" ng-bind="title"></h4></div><div class="modal-body" ng-bind="content"></div><div class="modal-footer"><button type="button" class="btn btn-default" ng-click="$hide()">Close</button></div></div></div></div>')}]),angular.module("mgcrea.ngStrap.dropdown").run(["$templateCache",function(e){e.put("dropdown/dropdown.tpl.html",'<ul tabindex="-1" class="dropdown-menu" role="menu" ng-show="content && content.length"><li role="presentation" ng-class="{divider: item.divider, active: item.active}" ng-repeat="item in content"><a role="menuitem" tabindex="-1" ng-href="{{item.href}}" ng-if="!item.divider && item.href" target="{{item.target || \'\'}}" ng-bind="item.text"></a> <a role="menuitem" tabindex="-1" href="javascript:void(0)" ng-if="!item.divider && item.click" ng-click="$eval(item.click);$hide()" ng-bind="item.text"></a></li></ul>')}]),angular.module("mgcrea.ngStrap.popover").run(["$templateCache",function(e){e.put("popover/popover.tpl.html",'<div class="popover" tabindex="-1"><div class="arrow"></div><h3 class="popover-title" ng-bind="title" ng-show="title"></h3><div class="popover-content" ng-bind="content"></div></div>')}]),angular.module("mgcrea.ngStrap.select").run(["$templateCache",function(e){e.put("select/select.tpl.html",'<ul tabindex="-1" class="select dropdown-menu" ng-show="$isVisible()" role="select"><li ng-if="$showAllNoneButtons"><div class="btn-group" style="margin-bottom: 5px; margin-left: 5px"><button type="button" class="btn btn-default btn-xs" ng-click="$selectAll()">{{$allText}}</button> <button type="button" class="btn btn-default btn-xs" ng-click="$selectNone()">{{$noneText}}</button></div></li><li role="presentation" ng-repeat="match in $matches" ng-class="{active: $isActive($index)}"><a style="cursor: default" role="menuitem" tabindex="-1" ng-click="$select($index, $event)"><i class="{{$iconCheckmark}} pull-right" ng-if="$isMultiple && $isActive($index)"></i> <span ng-bind="match.label"></span></a></li></ul>')}]),angular.module("mgcrea.ngStrap.tab").run(["$templateCache",function(e){e.put("tab/tab.tpl.html",'<ul class="nav" ng-class="$navClass" role="tablist"><li role="presentation" ng-repeat="$pane in $panes track by $index" ng-class="[ $isActive($pane, $index) ? $activeClass : \'\', $pane.disabled ? \'disabled\' : \'\' ]"><a role="tab" data-toggle="tab" ng-click="!$pane.disabled && $setActive($pane.name || $index)" data-index="{{ $index }}" ng-bind-html="$pane.title" aria-controls="$pane.title"></a></li></ul><div ng-transclude class="tab-content"></div>')}]),angular.module("mgcrea.ngStrap.timepicker").run(["$templateCache",function(e){e.put("timepicker/timepicker.tpl.html",'<div class="dropdown-menu timepicker" style="min-width: 0px;width: auto"><table height="100%"><thead><tr class="text-center"><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(-1, 0)"><i class="{{ $iconUp }}"></i></button></th><th>&nbsp;</th><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(-1, 1)"><i class="{{ $iconUp }}"></i></button></th><th ng-if="showSeconds">&nbsp;</th><th ng-if="showSeconds"><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(-1, 2)"><i class="{{ $iconUp }}"></i></button></th></tr></thead><tbody><tr ng-repeat="(i, row) in rows"><td class="text-center"><button tabindex="-1" style="width: 100%" type="button" class="btn btn-default" ng-class="{\'btn-primary\': row[0].selected}" ng-click="$select(row[0].date, 0)" ng-disabled="row[0].disabled"><span ng-class="{\'text-muted\': row[0].muted}" ng-bind="row[0].label"></span></button></td><td><span ng-bind="i == midIndex ? timeSeparator : \' \'"></span></td><td class="text-center"><button tabindex="-1" ng-if="row[1].date" style="width: 100%" type="button" class="btn btn-default" ng-class="{\'btn-primary\': row[1].selected}" ng-click="$select(row[1].date, 1)" ng-disabled="row[1].disabled"><span ng-class="{\'text-muted\': row[1].muted}" ng-bind="row[1].label"></span></button></td><td ng-if="showSeconds"><span ng-bind="i == midIndex ? timeSeparator : \' \'"></span></td><td ng-if="showSeconds" class="text-center"><button tabindex="-1" ng-if="row[2].date" style="width: 100%" type="button" class="btn btn-default" ng-class="{\'btn-primary\': row[2].selected}" ng-click="$select(row[2].date, 2)" ng-disabled="row[2].disabled"><span ng-class="{\'text-muted\': row[2].muted}" ng-bind="row[2].label"></span></button></td><td ng-if="showAM">&nbsp;</td><td ng-if="showAM"><button tabindex="-1" ng-show="i == midIndex - !isAM * 1" style="width: 100%" type="button" ng-class="{\'btn-primary\': !!isAM}" class="btn btn-default" ng-click="$switchMeridian()" ng-disabled="el.disabled">AM</button> <button tabindex="-1" ng-show="i == midIndex + 1 - !isAM * 1" style="width: 100%" type="button" ng-class="{\'btn-primary\': !isAM}" class="btn btn-default" ng-click="$switchMeridian()" ng-disabled="el.disabled">PM</button></td></tr></tbody><tfoot><tr class="text-center"><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(1, 0)"><i class="{{ $iconDown }}"></i></button></th><th>&nbsp;</th><th><button tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(1, 1)"><i class="{{ $iconDown }}"></i></button></th><th ng-if="showSeconds">&nbsp;</th><th ng-if="showSeconds"><button ng-if="showSeconds" tabindex="-1" type="button" class="btn btn-default pull-left" ng-click="$arrowAction(1, 2)"><i class="{{ $iconDown }}"></i></button></th></tr></tfoot></table></div>')}]),angular.module("mgcrea.ngStrap.typeahead").run(["$templateCache",function(e){e.put("typeahead/typeahead.tpl.html",'<ul tabindex="-1" class="typeahead dropdown-menu" ng-show="$isVisible()" role="select"><li role="presentation" ng-repeat="match in $matches" ng-class="{active: $index == $activeIndex}"><a role="menuitem" tabindex="-1" ng-click="$select($index, $event)" ng-bind="match.label"></a></li></ul>')}]),angular.module("mgcrea.ngStrap.tooltip").run(["$templateCache",function(e){e.put("tooltip/tooltip.tpl.html",'<div class="tooltip in" ng-show="title"><div class="tooltip-arrow"></div><div class="tooltip-inner" ng-bind="title"></div></div>')}])}(window,document),function(){"use strict";angular.module("toaster",["ngAnimate"]).constant("toasterConfig",{limit:0,"tap-to-dismiss":!0,"close-button":!1,"newest-on-top":!0,"time-out":5e3,"icon-classes":{error:"toast-error",info:"toast-info",wait:"toast-wait",success:"toast-success",warning:"toast-warning"},"body-output-type":"","body-template":"toasterBodyTmpl.html","icon-class":"toast-info","position-class":"toast-top-right","title-class":"toast-title","message-class":"toast-message","prevent-duplicates":!1,"mouseover-timer-stop":!0}).service("toaster",["$rootScope","toasterConfig",function(e,t){this.pop=function(t,n,i,r,o,a,s,l){if(angular.isObject(t)){var c=t;this.toast={type:c.type,title:c.title,body:c.body,timeout:c.timeout,bodyOutputType:c.bodyOutputType,clickHandler:c.clickHandler,showCloseButton:c.showCloseButton},s=c.toasterId}else this.toast={type:t,title:n,body:i,timeout:r,bodyOutputType:o,clickHandler:a,showCloseButton:l};e.$emit("toaster-newToast",s)},this.clear=function(){e.$emit("toaster-clearToasts")};for(var n in t["icon-classes"])this[n]=function(e){return function(t,n,i,r,o,a,s){angular.isString(t)?this.pop(e,t,n,i,r,o,a,s):this.pop(angular.extend(t,{type:e}))}}(n)}]).factory("toasterEventRegistry",["$rootScope",function(e){var t,n=null,i=null,r=[],o=[];return t={setup:function(){n||(n=e.$on("toaster-newToast",function(e,t){for(var n=0,i=r.length;n<i;n++)r[n](e,t)})),i||(i=e.$on("toaster-clearToasts",function(e){for(var t=0,n=o.length;t<n;t++)o[t](e)}))},subscribeToNewToastEvent:function(e){r.push(e)},subscribeToClearToastsEvent:function(e){o.push(e)},unsubscribeToNewToastEvent:function(e){var t=r.indexOf(e);t>=0&&r.splice(t,1),0===r.length&&(n(),n=null)},unsubscribeToClearToastsEvent:function(e){var t=o.indexOf(e);t>=0&&o.splice(t,1),0===o.length&&(i(),i=null)}},{setup:t.setup,subscribeToNewToastEvent:t.subscribeToNewToastEvent,subscribeToClearToastsEvent:t.subscribeToClearToastsEvent,unsubscribeToNewToastEvent:t.unsubscribeToNewToastEvent,unsubscribeToClearToastsEvent:t.unsubscribeToClearToastsEvent}}]).directive("toasterContainer",["$parse","$rootScope","$interval","$sce","toasterConfig","toaster","toasterEventRegistry",function(e,t,n,i,r,o,a){return{replace:!0,restrict:"EA",scope:!0,link:function(t,s,l){function c(e,i){e.timeoutPromise=n(function(){t.removeToast(e.id)},i,1)}function u(n){if(n.type=p["icon-classes"][n.type],n.type||(n.type=p["icon-class"]),!(!0===p["prevent-duplicates"]&&t.toasters.length>0&&t.toasters[t.toasters.length-1].body===n.body)){n.id=++h;var r=p["close-button"];if("boolean"==typeof n.showCloseButton);else if("boolean"==typeof r)n.showCloseButton=r;else if("object"==typeof r){var o=r[n.type];void 0!==o&&null!==o&&(n.showCloseButton=o)}else n.showCloseButton=!1;switch(n.bodyOutputType=n.bodyOutputType||p["body-output-type"],n.bodyOutputType){case"trustedHtml":n.html=i.trustAsHtml(n.body);break;case"template":n.bodyTemplate=n.body||p["body-template"];break;case"templateWithData":var a=e(n.body||p["body-template"]),s=a(t);n.bodyTemplate=s.template,n.data=s.data}t.configureTimer(n),!0===p["newest-on-top"]?(t.toasters.unshift(n),p.limit>0&&t.toasters.length>p.limit&&t.toasters.pop()):(t.toasters.push(n),p.limit>0&&t.toasters.length>p.limit&&t.toasters.shift())}}function d(e){var i=t.toasters[e];i&&(i.timeoutPromise&&n.cancel(i.timeoutPromise),t.toasters.splice(e,1))}function f(){for(var e=t.toasters.length;e>=0;e--)d(e)}var p,h=0;p=angular.extend({},r,t.$eval(l.toasterOptions)),t.config={toasterId:p["toaster-id"],position:p["position-class"],title:p["title-class"],message:p["message-class"],tap:p["tap-to-dismiss"],closeButton:p["close-button"],animation:p["animation-class"],mouseoverTimer:p["mouseover-timer-stop"]},t.$on("$destroy",function(){a.unsubscribeToNewToastEvent(t._onNewToast),a.unsubscribeToClearToastsEvent(t._onClearToasts)}),t.configureTimer=function(e){var t=angular.isNumber(e.timeout)?e.timeout:p["time-out"];t>0&&c(e,t)},t.removeToast=function(e){var n,i;for(n=0,i=t.toasters.length;n<i;n++)if(t.toasters[n].id===e){d(n);break}},t.toasters=[],t._onNewToast=function(e,n){(void 0===t.config.toasterId&&void 0===n||void 0!==n&&n===t.config.toasterId)&&u(o.toast)},t._onClearToasts=function(e){f()},a.setup(),a.subscribeToNewToastEvent(t._onNewToast),a.subscribeToClearToastsEvent(t._onClearToasts)},controller:["$scope","$element","$attrs",function(e,t,i){e.stopTimer=function(t){
+!0===e.config.mouseoverTimer&&t.timeoutPromise&&(n.cancel(t.timeoutPromise),t.timeoutPromise=null)},e.restartTimer=function(t){!0===e.config.mouseoverTimer?t.timeoutPromise||e.configureTimer(t):null===t.timeoutPromise&&e.removeToast(t.id)},e.click=function(t){if(!0===e.config.tap||!0===t.showCloseButton){var n=!0;t.clickHandler&&(angular.isFunction(t.clickHandler)?n=t.clickHandler(t,t.showCloseButton):angular.isFunction(e.$parent.$eval(t.clickHandler))?n=e.$parent.$eval(t.clickHandler)(t,t.showCloseButton):console.log("TOAST-NOTE: Your click handler is not inside a parent scope of toaster-container.")),n&&e.removeToast(t.id)}}}],template:'<div id="toast-container" ng-class="[config.position, config.animation]"><div ng-repeat="toaster in toasters" class="toast" ng-class="toaster.type" ng-click="click(toaster)" ng-mouseover="stopTimer(toaster)" ng-mouseout="restartTimer(toaster)"><button type="button" class="toast-close-button" ng-show="toaster.showCloseButton" ng-click="click(toaster)">&times;</button><div ng-class="config.title">{{toaster.title}}</div><div ng-class="config.message" ng-switch on="toaster.bodyOutputType"><div ng-switch-when="trustedHtml" ng-bind-html="toaster.html"></div><div ng-switch-when="template"><div ng-include="toaster.bodyTemplate"></div></div><div ng-switch-when="templateWithData"><div ng-include="toaster.bodyTemplate"></div></div><div ng-switch-default >{{toaster.body}}</div></div></div></div>'}}])}(window,document),function(e,t){"use strict";if("function"!=typeof define||!define.amd)return t(e);define(["angular"],function(e){return t(e)})}(window.angular||null,function(e){"use strict";var t=e.module("ngTable",[]);return t.value("ngTableDefaults",{params:{},settings:{}}),t.factory("NgTableParams",["$q","$log","ngTableDefaults",function(t,n,i){var r=function(e){return!isNaN(parseFloat(e))&&isFinite(e)};return function(o,a){var s=this,l=function(){u.debugMode&&n.debug&&n.debug.apply(this,arguments)};this.data=[],this.parameters=function(t,n){if(n=n||!1,e.isDefined(t)){for(var i in t){var o=t[i];if(n&&i.indexOf("[")>=0){for(var a=i.split(/\[(.*)\]/).reverse(),s="",u=0,d=a.length;u<d;u++){var f=a[u];if(""!==f){var p=o;o={},o[s=f]=r(p)?parseFloat(p):p}}"sorting"===s&&(c[s]={}),c[s]=e.extend(c[s]||{},o[s])}else c[i]=r(t[i])?parseFloat(t[i]):t[i]}return l("ngTable: set parameters",c),this}return c},this.settings=function(t){return e.isDefined(t)?(e.isArray(t.data)&&(t.total=t.data.length),u=e.extend(u,t),l("ngTable: set settings",u),this):u},this.page=function(t){return e.isDefined(t)?this.parameters({page:t}):c.page},this.total=function(t){return e.isDefined(t)?this.settings({total:t}):u.total},this.count=function(t){return e.isDefined(t)?this.parameters({count:t,page:1}):c.count},this.filter=function(t){return e.isDefined(t)?this.parameters({filter:t,page:1}):c.filter},this.sorting=function(t){if(2==arguments.length){var n={};return n[t]=arguments[1],this.parameters({sorting:n}),this}return e.isDefined(t)?this.parameters({sorting:t}):c.sorting},this.isSortBy=function(t,n){return e.isDefined(c.sorting[t])&&e.equals(c.sorting[t],n)},this.orderBy=function(){var e=[];for(var t in c.sorting)e.push(("asc"===c.sorting[t]?"+":"-")+t);return e},this.getData=function(t,n){return e.isArray(this.data)&&e.isObject(n)?t.resolve(this.data.slice((n.page()-1)*n.count(),n.page()*n.count())):t.resolve([]),t.promise},this.getGroups=function(n,i){var r=t.defer();return r.promise.then(function(t){var r={};e.forEach(t,function(t){var n=e.isFunction(i)?i(t):t[i];r[n]=r[n]||{data:[]},r[n].value=n,r[n].data.push(t)});var o=[];for(var a in r)o.push(r[a]);l("ngTable: refresh groups",o),n.resolve(o)}),this.getData(r,s)},this.generatePagesArray=function(e,t,n){var i,r,o,a,s,l;if(i=11,l=[],(s=Math.ceil(t/n))>1){l.push({type:"prev",number:Math.max(1,e-1),active:e>1}),l.push({type:"first",number:1,active:e>1,current:1===e}),o=Math.round((i-5)/2),a=Math.max(2,e-o),r=Math.min(s-1,e+2*o-(e-a)),a=Math.max(2,a-(2*o-(r-a)));for(var c=a;c<=r;)c===a&&2!==c||c===r&&c!==s-1?l.push({type:"more",active:!1}):l.push({type:"page",number:c,active:e!==c,current:e===c}),c++;l.push({type:"last",number:s,active:e!==s,current:e===s}),l.push({type:"next",number:Math.min(s,e+1),active:e<s})}return l},this.url=function(t){t=t||!1;var n=t?[]:{};for(var i in c)if(c.hasOwnProperty(i)){var r=c[i],o=encodeURIComponent(i);if("object"==typeof r){for(var a in r)if(!e.isUndefined(r[a])&&""!==r[a]){var s=o+"["+encodeURIComponent(a)+"]";t?n.push(s+"="+r[a]):n[s]=r[a]}}else e.isFunction(r)||e.isUndefined(r)||""===r||(t?n.push(o+"="+encodeURIComponent(r)):n[o]=encodeURIComponent(r))}return n},this.reload=function(){var e=t.defer(),n=this,i=null;if(u.$scope)return u.$loading=!0,i=u.groupBy?u.getGroups(e,u.groupBy,this):u.getData(e,this),l("ngTable: reload data"),i||(i=e.promise),i.then(function(e){return u.$loading=!1,l("ngTable: current scope",u.$scope),u.groupBy?(n.data=e,u.$scope&&(u.$scope.$groups=e)):(n.data=e,u.$scope&&(u.$scope.$data=e)),u.$scope&&(u.$scope.pages=n.generatePagesArray(n.page(),n.total(),n.count())),u.$scope.$emit("ngTableAfterReloadData"),e})},this.reloadPages=function(){var e=this;u.$scope.pages=e.generatePagesArray(e.page(),e.total(),e.count())};var c=this.$params={page:1,count:1,filter:{},sorting:{},group:{},groupBy:null};e.extend(c,i.params);var u={$scope:null,$loading:!1,data:null,total:0,defaultSort:"desc",filterDelay:750,counts:[10,25,50,100],sortingIndicator:"span",getGroups:this.getGroups,getData:this.getData};return e.extend(u,i.settings),this.settings(a),this.parameters(o,!0),this}}]),t.factory("ngTableParams",["NgTableParams",function(e){return e}]),t.controller("ngTableController",["$scope","NgTableParams","$timeout","$parse","$compile","$attrs","$element","ngTableColumn",function(t,n,i,r,o,a,s,l){function c(){t.params.$params.page=1}var u=!0;t.$filterRow={},t.$loading=!1,t.hasOwnProperty("params")||(t.params=new n,t.params.isNullInstance=!0),t.params.settings().$scope=t;var d=function(){var e=0;return function(t,n){i.cancel(e),e=i(t,n)}}();t.$watch("params.$params",function(n,i){if(n!==i){if(t.params.settings().$scope=t,e.equals(n.filter,i.filter))t.params.reload();else{var r=u?e.noop:c;d(function(){r(),t.params.reload()},t.params.settings().filterDelay)}t.params.isNullInstance||(u=!1)}},!0),this.compileDirectiveTemplates=function(){if(!s.hasClass("ng-table")){t.templates={header:a.templateHeader?a.templateHeader:"ng-table/header.html",pagination:a.templatePagination?a.templatePagination:"ng-table/pager.html"},s.addClass("ng-table");var n=null;0===s.find("> thead").length&&(n=e.element(document.createElement("thead")).attr("ng-include","templates.header"),s.prepend(n));var i=e.element(document.createElement("div")).attr({"ng-table-pagination":"params","template-url":"templates.pagination"});s.after(i),n&&o(n)(t),o(i)(t)}},this.loadFilterData=function(n){e.forEach(n,function(n){var i;return i=n.filterData(t,{$column:n}),i?e.isObject(i)&&e.isObject(i.promise)?(delete n.filterData,i.promise.then(function(t){e.isArray(t)||e.isFunction(t)||e.isObject(t)?e.isArray(t)&&t.unshift({title:"-",id:""}):t=[],n.data=t})):n.data=i:void delete n.filterData})},this.buildColumns=function(e){return e.map(function(e){return l.buildColumn(e,t)})},this.setupBindingsToInternalScope=function(n){var i=r(n);t.$watch(i,function(n){e.isUndefined(n)||(t.paramsModel=i,t.params=n)},!1),a.showFilter&&t.$parent.$watch(a.showFilter,function(e){t.show_filter=e}),a.disableFilter&&t.$parent.$watch(a.disableFilter,function(e){t.$filterRow.disabled=e})},t.sortBy=function(e,n){var i=e.sortable&&e.sortable();if(i){var r=t.params.settings().defaultSort,o="asc"===r?"desc":"asc",a=t.params.sorting()&&t.params.sorting()[i]&&t.params.sorting()[i]===r,s=n.ctrlKey||n.metaKey?t.params.sorting():{};s[i]=a?o:r,t.params.parameters({sorting:s})}}}]),t.factory("ngTableColumn",[function(){function t(t,i){var r=Object.create(t);for(var o in n)void 0===r[o]&&(r[o]=n[o]),e.isFunction(r[o])||function(e){r[e]=function(){return t[e]}}(o),function(e){var n=r[e];r[e]=function(){return 0===arguments.length?n.call(t,i):n.apply(t,arguments)}}(o);return r}var n={class:function(){return""},filter:function(){return!1},filterData:e.noop,headerTemplateURL:function(){return!1},headerTitle:function(){return""},sortable:function(){return!1},show:function(){return!0},title:function(){return""},titleAlt:function(){return""}};return{buildColumn:t}}]),t.directive("ngTable",["$q","$parse",function(t,n){return{restrict:"A",priority:1001,scope:!0,controller:"ngTableController",compile:function(t){var i=[],r=0,o=null;if(e.forEach(e.element(t.find("tr")),function(t){t=e.element(t),t.hasClass("ng-table-group")||o||(o=t)}),o)return e.forEach(o.find("td"),function(t){var o=e.element(t);if(!o.attr("ignore-cell")||"true"!==o.attr("ignore-cell")){var a=function(e){return o.attr("x-data-"+e)||o.attr("data-"+e)||o.attr(e)},s=function(t){var r=a(t);if(r)return function(t,o){return n(r)(t,e.extend(o||{},{$columns:i}))}},l=a("title-alt")||a("title");l&&o.attr("data-title-text","{{"+l+"}}"),i.push({id:r++,title:s("title"),titleAlt:s("title-alt"),headerTitle:s("header-title"),sortable:s("sortable"),class:s("header-class"),filter:s("filter"),headerTemplateURL:s("header"),filterData:s("filter-data"),show:o.attr("ng-show")?function(e){return n(o.attr("ng-show"))(e)}:void 0})}}),function(e,t,n,r){e.$columns=i=r.buildColumns(i),r.setupBindingsToInternalScope(n.ngTable),r.loadFilterData(i),r.compileDirectiveTemplates()}}}}]),t.directive("ngTableDynamic",["$parse",function(t){function n(e){if(!e||e.indexOf(" with ")>-1){var t=e.split(/\s+with\s+/);return{tableParams:t[0],columns:t[1]}}throw new Error("Parse error (expected example: ng-table-dynamic='tableParams with cols')")}return{restrict:"A",priority:1001,scope:!0,controller:"ngTableController",compile:function(i){var r;if(e.forEach(e.element(i.find("tr")),function(t){t=e.element(t),t.hasClass("ng-table-group")||r||(r=t)}),r)return e.forEach(r.find("td"),function(t){var n=e.element(t);(function(e){return n.attr("x-data-"+e)||n.attr("data-"+e)||n.attr(e)})("title")||n.attr("data-title-text","{{$columns[$index].titleAlt(this) || $columns[$index].title(this)}}"),n.attr("ng-show")||n.attr("ng-show","$columns[$index].show(this)")}),function(e,i,r,o){var a=n(r.ngTableDynamic),s=t(a.columns)(e)||[];e.$columns=o.buildColumns(s),o.setupBindingsToInternalScope(a.tableParams),o.loadFilterData(e.$columns),o.compileDirectiveTemplates()}}}}]),t.directive("ngTablePagination",["$compile",function(t){return{restrict:"A",scope:{params:"=ngTablePagination",templateUrl:"="},replace:!1,link:function(n,i,r){n.params.settings().$scope.$on("ngTableAfterReloadData",function(){n.pages=n.params.generatePagesArray(n.params.page(),n.params.total(),n.params.count())},!0),n.$watch("templateUrl",function(r){if(!e.isUndefined(r)){var o=e.element(document.createElement("div"));o.attr({"ng-include":"templateUrl"}),i.append(o),t(o)(n)}})}}}]),e.module("ngTable").run(["$templateCache",function(e){e.put("ng-table/filters/select-multiple.html",'<select ng-options="data.id as data.title for data in $column.data" ng-disabled="$filterRow.disabled" multiple ng-multiple="true" ng-model="params.filter()[name]" ng-show="filter==\'select-multiple\'" class="filter filter-select-multiple form-control" name="{{name}}"> </select>'),e.put("ng-table/filters/select.html",'<select ng-options="data.id as data.title for data in $column.data" ng-disabled="$filterRow.disabled" ng-model="params.filter()[name]" ng-show="filter==\'select\'" class="filter filter-select form-control" name="{{name}}"> </select>'),e.put("ng-table/filters/text.html",'<input type="text" name="{{name}}" ng-disabled="$filterRow.disabled" ng-model="params.filter()[name]" ng-if="filter==\'text\'" class="input-filter form-control"/>'),e.put("ng-table/header.html",'<tr> <th title="{{$column.headerTitle(this)}}" ng-repeat="$column in $columns" ng-class="{ \'sortable\': $column.sortable(this), \'sort-asc\': params.sorting()[$column.sortable(this)]==\'asc\', \'sort-desc\': params.sorting()[$column.sortable(this)]==\'desc\' }" ng-click="sortBy($column, $event)" ng-show="$column.show(this)" ng-init="template=$column.headerTemplateURL(this)" class="header {{$column.class(this)}}"> <div ng-if="!template" ng-show="!template" class="ng-table-header" ng-class="{\'sort-indicator\': params.settings().sortingIndicator==\'div\'}"> <span ng-bind="$column.title(this)" ng-class="{\'sort-indicator\': params.settings().sortingIndicator==\'span\'}"></span> </div> <div ng-if="template" ng-show="template" ng-include="template"></div> </th> </tr> <tr ng-show="show_filter" class="ng-table-filters"> <th data-title-text="{{$column.titleAlt(this) || $column.title(this)}}" ng-repeat="$column in $columns" ng-show="$column.show(this)" class="filter"> <div ng-repeat="(name, filter) in $column.filter(this)"> <div ng-if="filter.indexOf(\'/\') !==-1" ng-include="filter"></div> <div ng-if="filter.indexOf(\'/\')===-1" ng-include="\'ng-table/filters/\' + filter + \'.html\'"></div> </div> </th> </tr> '),e.put("ng-table/pager.html",'<div class="ng-cloak ng-table-pager" ng-if="params.data.length"> <div ng-if="params.settings().counts.length" class="ng-table-counts btn-group pull-right"> <button ng-repeat="count in params.settings().counts" type="button" ng-class="{\'active\':params.count()==count}" ng-click="params.count(count)" class="btn btn-default"> <span ng-bind="count"></span> </button> </div> <ul class="pagination ng-table-pagination"> <li ng-class="{\'disabled\': !page.active && !page.current, \'active\': page.current}" ng-repeat="page in pages" ng-switch="page.type"> <a ng-switch-when="prev" ng-click="params.page(page.number)" href="">&laquo;</a> <a ng-switch-when="first" ng-click="params.page(page.number)" href=""><span ng-bind="page.number"></span></a> <a ng-switch-when="page" ng-click="params.page(page.number)" href=""><span ng-bind="page.number"></span></a> <a ng-switch-when="more" ng-click="params.page(page.number)" href="">&#8230;</a> <a ng-switch-when="last" ng-click="params.page(page.number)" href=""><span ng-bind="page.number"></span></a> <a ng-switch-when="next" ng-click="params.page(page.number)" href="">&raquo;</a> </li> </ul> </div> ')}]),t}),function(e){void 0===e.fn.each2&&e.extend(e.fn,{each2:function(t){for(var n=e([0]),i=-1,r=this.length;++i<r&&(n.context=n[0]=this[i])&&!1!==t.call(n[0],i,n););return this}})}(jQuery),function(e,t){"use strict";function n(t){var n=e(document.createTextNode(""));t.before(n),n.before(t),n.remove()}function i(e){function t(e){return H[e]||e}return e.replace(/[^\u0000-\u007E]/g,t)}function r(e,t){for(var n=0,i=t.length;n<i;n+=1)if(a(e,t[n]))return n;return-1}function o(){var t=e(V);t.appendTo("body");var n={width:t.width()-t[0].clientWidth,height:t.height()-t[0].clientHeight};return t.remove(),n}function a(e,n){return e===n||e!==t&&n!==t&&(null!==e&&null!==n&&(e.constructor===String?e+""==n+"":n.constructor===String&&n+""==e+""))}function s(t,n){var i,r,o;if(null===t||t.length<1)return[];for(i=t.split(n),r=0,o=i.length;r<o;r+=1)i[r]=e.trim(i[r]);return i}function l(e){return e.outerWidth(!1)-e.width()}function c(n){var i="keyup-change-value";n.on("keydown",function(){e.data(n,i)===t&&e.data(n,i,n.val())}),n.on("keyup",function(){var r=e.data(n,i);r!==t&&n.val()!==r&&(e.removeData(n,i),n.trigger("keyup-change"))})}function u(n){n.on("mousemove",function(n){var i=R;i!==t&&i.x===n.pageX&&i.y===n.pageY||e(n.target).trigger("mousemove-filtered",n)})}function d(e,n,i){i=i||t;var r;return function(){var t=arguments;window.clearTimeout(r),r=window.setTimeout(function(){n.apply(i,t)},e)}}function f(e,t){var n=d(e,function(e){t.trigger("scroll-debounced",e)});t.on("scroll",function(e){r(e.target,t.get())>=0&&n(e)})}function p(e){e[0]!==document.activeElement&&window.setTimeout(function(){var t,n=e[0],i=e.val().length;e.focus(),(n.offsetWidth>0||n.offsetHeight>0)&&n===document.activeElement&&(n.setSelectionRange?n.setSelectionRange(i,i):n.createTextRange&&(t=n.createTextRange(),t.collapse(!1),t.select()))},0)}function h(t){t=e(t)[0];var n=0,i=0;if("selectionStart"in t)n=t.selectionStart,i=t.selectionEnd-n;else if("selection"in document){t.focus();var r=document.selection.createRange();i=document.selection.createRange().text.length,r.moveStart("character",-t.value.length),n=r.text.length-i}return{offset:n,length:i}}function g(e){e.preventDefault(),e.stopPropagation()}function m(e){e.preventDefault(),e.stopImmediatePropagation()}function v(t){if(!j){var n=t[0].currentStyle||window.getComputedStyle(t[0],null);j=e(document.createElement("div")).css({position:"absolute",left:"-10000px",top:"-10000px",display:"none",fontSize:n.fontSize,fontFamily:n.fontFamily,fontStyle:n.fontStyle,fontWeight:n.fontWeight,letterSpacing:n.letterSpacing,textTransform:n.textTransform,whiteSpace:"nowrap"}),j.attr("class","select2-sizer"),e("body").append(j)}return j.text(t.val()),j.width()}function $(t,n,i){var r,o,a=[];r=e.trim(t.attr("class")),r&&(r=""+r,e(r.split(/\s+/)).each2(function(){0===this.indexOf("select2-")&&a.push(this)})),r=e.trim(n.attr("class")),r&&(r=""+r,e(r.split(/\s+/)).each2(function(){0!==this.indexOf("select2-")&&(o=i(this))&&a.push(o)})),t.attr("class",a.join(" "))}function y(e,t,n,r){var o=i(e.toUpperCase()).indexOf(i(t.toUpperCase())),a=t.length;if(o<0)return void n.push(r(e));n.push(r(e.substring(0,o))),n.push("<span class='select2-match'>"),n.push(r(e.substring(o,o+a))),n.push("</span>"),n.push(r(e.substring(o+a,e.length)))}function b(e){var t={"\\":"&#92;","&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#47;"};return String(e).replace(/[&<>"'\/\\]/g,function(e){return t[e]})}function w(n){var i,r=null,o=n.quietMillis||100,a=n.url,s=this;return function(l){window.clearTimeout(i),i=window.setTimeout(function(){var i=n.data,o=a,c=n.transport||e.fn.select2.ajaxDefaults.transport,u={type:n.type||"GET",cache:n.cache||!1,jsonpCallback:n.jsonpCallback||t,dataType:n.dataType||"json"},d=e.extend({},e.fn.select2.ajaxDefaults.params,u);i=i?i.call(s,l.term,l.page,l.context):null,o="function"==typeof o?o.call(s,l.term,l.page,l.context):o,r&&"function"==typeof r.abort&&r.abort(),n.params&&(e.isFunction(n.params)?e.extend(d,n.params.call(s)):e.extend(d,n.params)),e.extend(d,{url:o,dataType:n.dataType,data:i,success:function(e){var t=n.results(e,l.page,l);l.callback(t)},error:function(e,t,n){var i={hasError:!0,jqXHR:e,textStatus:t,errorThrown:n};l.callback(i)}}),r=c.call(s,d)},o)}}function x(t){var n,i,r=t,o=function(e){return""+e.text};e.isArray(r)&&(i=r,r={results:i}),!1===e.isFunction(r)&&(i=r,r=function(){return i});var a=r();return a.text&&(o=a.text,e.isFunction(o)||(n=a.text,o=function(e){return e[n]})),function(t){var n,i=t.term,a={results:[]};if(""===i)return void t.callback(r());n=function(r,a){var s,l;if(r=r[0],r.children){s={};for(l in r)r.hasOwnProperty(l)&&(s[l]=r[l]);s.children=[],e(r.children).each2(function(e,t){n(t,s.children)}),(s.children.length||t.matcher(i,o(s),r))&&a.push(s)}else t.matcher(i,o(r),r)&&a.push(r)},e(r().results).each2(function(e,t){n(t,a.results)}),t.callback(a)}}function C(n){var i=e.isFunction(n);return function(r){var o=r.term,a={results:[]},s=i?n(r):n;e.isArray(s)&&(e(s).each(function(){var e=this.text!==t,n=e?this.text:this;(""===o||r.matcher(o,n))&&a.results.push(e?this:{id:this,text:this})}),r.callback(a))}}function k(t,n){if(e.isFunction(t))return!0;if(!t)return!1;if("string"==typeof t)return!0;throw new Error(n+" must be a string, function, or falsy value")}function S(t,n){if(e.isFunction(t)){var i=Array.prototype.slice.call(arguments,2);return t.apply(n,i)}return t}function E(t){var n=0;return e.each(t,function(e,t){t.children?n+=E(t.children):n++}),n}function T(e,n,i,r){var o,s,l,c,u,d=e,f=!1;if(!r.createSearchChoice||!r.tokenSeparators||r.tokenSeparators.length<1)return t;for(;;){for(s=-1,l=0,c=r.tokenSeparators.length;l<c&&(u=r.tokenSeparators[l],!((s=e.indexOf(u))>=0));l++);if(s<0)break;if(o=e.substring(0,s),e=e.substring(s+u.length),o.length>0&&(o=r.createSearchChoice.call(this,o,n))!==t&&null!==o&&r.id(o)!==t&&null!==r.id(o)){for(f=!1,l=0,c=n.length;l<c;l++)if(a(r.id(o),r.id(n[l]))){f=!0;break}f||i(o)}}return d!==e?e:void 0}function D(){var t=this;e.each(arguments,function(e,n){t[n].remove(),t[n]=null})}function A(t,n){var i=function(){};return i.prototype=new t,i.prototype.constructor=i,i.prototype.parent=t.prototype,i.prototype=e.extend(i.prototype,n),i}if(window.Select2===t){var M,O,I,P,N,j,F,L,R={x:0,y:0},M={TAB:9,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,SHIFT:16,CTRL:17,ALT:18,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,BACKSPACE:8,DELETE:46,isArrow:function(e){switch(e=e.which?e.which:e){case M.LEFT:case M.RIGHT:case M.UP:case M.DOWN:return!0}return!1},isControl:function(e){switch(e.which){case M.SHIFT:case M.CTRL:case M.ALT:return!0}return!!e.metaKey},isFunctionKey:function(e){return(e=e.which?e.which:e)>=112&&e<=123}},V="<div class='select2-measure-scrollbar'></div>",H={"Ⓐ":"A","A":"A","À":"A","Á":"A","Â":"A","Ầ":"A","Ấ":"A","Ẫ":"A","Ẩ":"A","Ã":"A","Ā":"A","Ă":"A","Ằ":"A","Ắ":"A","Ẵ":"A","Ẳ":"A","Ȧ":"A","Ǡ":"A","Ä":"A","Ǟ":"A","Ả":"A","Å":"A","Ǻ":"A","Ǎ":"A","Ȁ":"A","Ȃ":"A","Ạ":"A","Ậ":"A","Ặ":"A","Ḁ":"A","Ą":"A","Ⱥ":"A","Ɐ":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ⓑ":"B","B":"B","Ḃ":"B","Ḅ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ɓ":"B","Ⓒ":"C","C":"C","Ć":"C","Ĉ":"C","Ċ":"C","Č":"C","Ç":"C","Ḉ":"C","Ƈ":"C","Ȼ":"C","Ꜿ":"C","Ⓓ":"D","D":"D","Ḋ":"D","Ď":"D","Ḍ":"D","Ḑ":"D","Ḓ":"D","Ḏ":"D","Đ":"D","Ƌ":"D","Ɗ":"D","Ɖ":"D","Ꝺ":"D","DZ":"DZ","DŽ":"DZ","Dz":"Dz","Dž":"Dz","Ⓔ":"E","E":"E","È":"E","É":"E","Ê":"E","Ề":"E","Ế":"E","Ễ":"E","Ể":"E","Ẽ":"E","Ē":"E","Ḕ":"E","Ḗ":"E","Ĕ":"E","Ė":"E","Ë":"E","Ẻ":"E","Ě":"E","Ȅ":"E","Ȇ":"E","Ẹ":"E","Ệ":"E","Ȩ":"E","Ḝ":"E","Ę":"E","Ḙ":"E","Ḛ":"E","Ɛ":"E","Ǝ":"E","Ⓕ":"F","F":"F","Ḟ":"F","Ƒ":"F","Ꝼ":"F","Ⓖ":"G","G":"G","Ǵ":"G","Ĝ":"G","Ḡ":"G","Ğ":"G","Ġ":"G","Ǧ":"G","Ģ":"G","Ǥ":"G","Ɠ":"G","Ꞡ":"G","Ᵹ":"G","Ꝿ":"G","Ⓗ":"H","H":"H","Ĥ":"H","Ḣ":"H","Ḧ":"H","Ȟ":"H","Ḥ":"H","Ḩ":"H","Ḫ":"H","Ħ":"H","Ⱨ":"H","Ⱶ":"H","Ɥ":"H","Ⓘ":"I","I":"I","Ì":"I","Í":"I","Î":"I","Ĩ":"I","Ī":"I","Ĭ":"I","İ":"I","Ï":"I","Ḯ":"I","Ỉ":"I","Ǐ":"I","Ȉ":"I","Ȋ":"I","Ị":"I","Į":"I","Ḭ":"I","Ɨ":"I","Ⓙ":"J","J":"J","Ĵ":"J","Ɉ":"J","Ⓚ":"K","K":"K","Ḱ":"K","Ǩ":"K","Ḳ":"K","Ķ":"K","Ḵ":"K","Ƙ":"K","Ⱪ":"K","Ꝁ":"K","Ꝃ":"K","Ꝅ":"K","Ꞣ":"K","Ⓛ":"L","L":"L","Ŀ":"L","Ĺ":"L","Ľ":"L","Ḷ":"L","Ḹ":"L","Ļ":"L","Ḽ":"L","Ḻ":"L","Ł":"L","Ƚ":"L","Ɫ":"L","Ⱡ":"L","Ꝉ":"L","Ꝇ":"L","Ꞁ":"L","LJ":"LJ","Lj":"Lj","Ⓜ":"M","M":"M","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ɯ":"M","Ⓝ":"N","N":"N","Ǹ":"N","Ń":"N","Ñ":"N","Ṅ":"N","Ň":"N","Ṇ":"N","Ņ":"N","Ṋ":"N","Ṉ":"N","Ƞ":"N","Ɲ":"N","Ꞑ":"N","Ꞥ":"N","NJ":"NJ","Nj":"Nj","Ⓞ":"O","O":"O","Ò":"O","Ó":"O","Ô":"O","Ồ":"O","Ố":"O","Ỗ":"O","Ổ":"O","Õ":"O","Ṍ":"O","Ȭ":"O","Ṏ":"O","Ō":"O","Ṑ":"O","Ṓ":"O","Ŏ":"O","Ȯ":"O","Ȱ":"O","Ö":"O","Ȫ":"O","Ỏ":"O","Ő":"O","Ǒ":"O","Ȍ":"O","Ȏ":"O","Ơ":"O","Ờ":"O","Ớ":"O","Ỡ":"O","Ở":"O","Ợ":"O","Ọ":"O","Ộ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Ɔ":"O","Ɵ":"O","Ꝋ":"O","Ꝍ":"O","Ƣ":"OI","Ꝏ":"OO","Ȣ":"OU","Ⓟ":"P","P":"P","Ṕ":"P","Ṗ":"P","Ƥ":"P","Ᵽ":"P","Ꝑ":"P","Ꝓ":"P","Ꝕ":"P","Ⓠ":"Q","Q":"Q","Ꝗ":"Q","Ꝙ":"Q","Ɋ":"Q","Ⓡ":"R","R":"R","Ŕ":"R","Ṙ":"R","Ř":"R","Ȑ":"R","Ȓ":"R","Ṛ":"R","Ṝ":"R","Ŗ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꝛ":"R","Ꞧ":"R","Ꞃ":"R","Ⓢ":"S","S":"S","ẞ":"S","Ś":"S","Ṥ":"S","Ŝ":"S","Ṡ":"S","Š":"S","Ṧ":"S","Ṣ":"S","Ṩ":"S","Ș":"S","Ş":"S","Ȿ":"S","Ꞩ":"S","Ꞅ":"S","Ⓣ":"T","T":"T","Ṫ":"T","Ť":"T","Ṭ":"T","Ț":"T","Ţ":"T","Ṱ":"T","Ṯ":"T","Ŧ":"T","Ƭ":"T","Ʈ":"T","Ⱦ":"T","Ꞇ":"T","Ꜩ":"TZ","Ⓤ":"U","U":"U","Ù":"U","Ú":"U","Û":"U","Ũ":"U","Ṹ":"U","Ū":"U","Ṻ":"U","Ŭ":"U","Ü":"U","Ǜ":"U","Ǘ":"U","Ǖ":"U","Ǚ":"U","Ủ":"U","Ů":"U","Ű":"U","Ǔ":"U","Ȕ":"U","Ȗ":"U","Ư":"U","Ừ":"U","Ứ":"U","Ữ":"U","Ử":"U","Ự":"U","Ụ":"U","Ṳ":"U","Ų":"U","Ṷ":"U","Ṵ":"U","Ʉ":"U","Ⓥ":"V","V":"V","Ṽ":"V","Ṿ":"V","Ʋ":"V","Ꝟ":"V","Ʌ":"V","Ꝡ":"VY","Ⓦ":"W","W":"W","Ẁ":"W","Ẃ":"W","Ŵ":"W","Ẇ":"W","Ẅ":"W","Ẉ":"W","Ⱳ":"W","Ⓧ":"X","X":"X","Ẋ":"X","Ẍ":"X","Ⓨ":"Y","Y":"Y","Ỳ":"Y","Ý":"Y","Ŷ":"Y","Ỹ":"Y","Ȳ":"Y","Ẏ":"Y","Ÿ":"Y","Ỷ":"Y","Ỵ":"Y","Ƴ":"Y","Ɏ":"Y","Ỿ":"Y","Ⓩ":"Z","Z":"Z","Ź":"Z","Ẑ":"Z","Ż":"Z","Ž":"Z","Ẓ":"Z","Ẕ":"Z","Ƶ":"Z","Ȥ":"Z","Ɀ":"Z","Ⱬ":"Z","Ꝣ":"Z","ⓐ":"a","a":"a","ẚ":"a","à":"a","á":"a","â":"a","ầ":"a","ấ":"a","ẫ":"a","ẩ":"a","ã":"a","ā":"a","ă":"a","ằ":"a","ắ":"a","ẵ":"a","ẳ":"a","ȧ":"a","ǡ":"a","ä":"a","ǟ":"a","ả":"a","å":"a","ǻ":"a","ǎ":"a","ȁ":"a","ȃ":"a","ạ":"a","ậ":"a","ặ":"a","ḁ":"a","ą":"a","ⱥ":"a","ɐ":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ⓑ":"b","b":"b","ḃ":"b","ḅ":"b","ḇ":"b","ƀ":"b","ƃ":"b","ɓ":"b","ⓒ":"c","c":"c","ć":"c","ĉ":"c","ċ":"c","č":"c","ç":"c","ḉ":"c","ƈ":"c","ȼ":"c","ꜿ":"c","ↄ":"c","ⓓ":"d","d":"d","ḋ":"d","ď":"d","ḍ":"d","ḑ":"d","ḓ":"d","ḏ":"d","đ":"d","ƌ":"d","ɖ":"d","ɗ":"d","ꝺ":"d","dz":"dz","dž":"dz","ⓔ":"e","e":"e","è":"e","é":"e","ê":"e","ề":"e","ế":"e","ễ":"e","ể":"e","ẽ":"e","ē":"e","ḕ":"e","ḗ":"e","ĕ":"e","ė":"e","ë":"e","ẻ":"e","ě":"e","ȅ":"e","ȇ":"e","ẹ":"e","ệ":"e","ȩ":"e","ḝ":"e","ę":"e","ḙ":"e","ḛ":"e","ɇ":"e","ɛ":"e","ǝ":"e","ⓕ":"f","f":"f","ḟ":"f","ƒ":"f","ꝼ":"f","ⓖ":"g","g":"g","ǵ":"g","ĝ":"g","ḡ":"g","ğ":"g","ġ":"g","ǧ":"g","ģ":"g","ǥ":"g","ɠ":"g","ꞡ":"g","ᵹ":"g","ꝿ":"g","ⓗ":"h","h":"h","ĥ":"h","ḣ":"h","ḧ":"h","ȟ":"h","ḥ":"h","ḩ":"h","ḫ":"h","ẖ":"h","ħ":"h","ⱨ":"h","ⱶ":"h","ɥ":"h","ƕ":"hv","ⓘ":"i","i":"i","ì":"i","í":"i","î":"i","ĩ":"i","ī":"i","ĭ":"i","ï":"i","ḯ":"i","ỉ":"i","ǐ":"i","ȉ":"i","ȋ":"i","ị":"i","į":"i","ḭ":"i","ɨ":"i","ı":"i","ⓙ":"j","j":"j","ĵ":"j","ǰ":"j","ɉ":"j","ⓚ":"k","k":"k","ḱ":"k","ǩ":"k","ḳ":"k","ķ":"k","ḵ":"k","ƙ":"k","ⱪ":"k","ꝁ":"k","ꝃ":"k","ꝅ":"k","ꞣ":"k","ⓛ":"l","l":"l","ŀ":"l","ĺ":"l","ľ":"l","ḷ":"l","ḹ":"l","ļ":"l","ḽ":"l","ḻ":"l","ſ":"l","ł":"l","ƚ":"l","ɫ":"l","ⱡ":"l","ꝉ":"l","ꞁ":"l","ꝇ":"l","lj":"lj","ⓜ":"m","m":"m","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ɯ":"m","ⓝ":"n","n":"n","ǹ":"n","ń":"n","ñ":"n","ṅ":"n","ň":"n","ṇ":"n","ņ":"n","ṋ":"n","ṉ":"n","ƞ":"n","ɲ":"n","ʼn":"n","ꞑ":"n","ꞥ":"n","nj":"nj","ⓞ":"o","o":"o","ò":"o","ó":"o","ô":"o","ồ":"o","ố":"o","ỗ":"o","ổ":"o","õ":"o","ṍ":"o","ȭ":"o","ṏ":"o","ō":"o","ṑ":"o","ṓ":"o","ŏ":"o","ȯ":"o","ȱ":"o","ö":"o","ȫ":"o","ỏ":"o","ő":"o","ǒ":"o","ȍ":"o","ȏ":"o","ơ":"o","ờ":"o","ớ":"o","ỡ":"o","ở":"o","ợ":"o","ọ":"o","ộ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","ɔ":"o","ꝋ":"o","ꝍ":"o","ɵ":"o","ƣ":"oi","ȣ":"ou","ꝏ":"oo","ⓟ":"p","p":"p","ṕ":"p","ṗ":"p","ƥ":"p","ᵽ":"p","ꝑ":"p","ꝓ":"p","ꝕ":"p","ⓠ":"q","q":"q","ɋ":"q","ꝗ":"q","ꝙ":"q","ⓡ":"r","r":"r","ŕ":"r","ṙ":"r","ř":"r","ȑ":"r","ȓ":"r","ṛ":"r","ṝ":"r","ŗ":"r","ṟ":"r","ɍ":"r","ɽ":"r","ꝛ":"r","ꞧ":"r","ꞃ":"r","ⓢ":"s","s":"s","ß":"s","ś":"s","ṥ":"s","ŝ":"s","ṡ":"s","š":"s","ṧ":"s","ṣ":"s","ṩ":"s","ș":"s","ş":"s","ȿ":"s","ꞩ":"s","ꞅ":"s","ẛ":"s","ⓣ":"t","t":"t","ṫ":"t","ẗ":"t","ť":"t","ṭ":"t","ț":"t","ţ":"t","ṱ":"t","ṯ":"t","ŧ":"t","ƭ":"t","ʈ":"t","ⱦ":"t","ꞇ":"t","ꜩ":"tz","ⓤ":"u","u":"u","ù":"u","ú":"u","û":"u","ũ":"u","ṹ":"u","ū":"u","ṻ":"u","ŭ":"u","ü":"u","ǜ":"u","ǘ":"u","ǖ":"u","ǚ":"u","ủ":"u","ů":"u","ű":"u","ǔ":"u","ȕ":"u","ȗ":"u","ư":"u","ừ":"u","ứ":"u","ữ":"u","ử":"u","ự":"u","ụ":"u","ṳ":"u","ų":"u","ṷ":"u","ṵ":"u","ʉ":"u","ⓥ":"v","v":"v","ṽ":"v","ṿ":"v","ʋ":"v","ꝟ":"v","ʌ":"v","ꝡ":"vy","ⓦ":"w","w":"w","ẁ":"w","ẃ":"w","ŵ":"w","ẇ":"w","ẅ":"w","ẘ":"w","ẉ":"w","ⱳ":"w","ⓧ":"x","x":"x","ẋ":"x","ẍ":"x","ⓨ":"y","y":"y","ỳ":"y","ý":"y","ŷ":"y","ỹ":"y","ȳ":"y","ẏ":"y","ÿ":"y","ỷ":"y","ẙ":"y","ỵ":"y","ƴ":"y","ɏ":"y","ỿ":"y","ⓩ":"z","z":"z","ź":"z","ẑ":"z","ż":"z","ž":"z","ẓ":"z","ẕ":"z","ƶ":"z","ȥ":"z","ɀ":"z","ⱬ":"z","ꝣ":"z","Ά":"Α","Έ":"Ε","Ή":"Η","Ί":"Ι","Ϊ":"Ι","Ό":"Ο","Ύ":"Υ","Ϋ":"Υ","Ώ":"Ω","ά":"α","έ":"ε","ή":"η","ί":"ι","ϊ":"ι","ΐ":"ι","ό":"ο","ύ":"υ","ϋ":"υ","ΰ":"υ","ω":"ω","ς":"σ"};F=e(document),N=function(){var e=1;return function(){return e++}}(),O=A(Object,{bind:function(e){var t=this;return function(){e.apply(t,arguments)}},init:function(n){var i,r;this.opts=n=this.prepareOpts(n),this.id=n.id,n.element.data("select2")!==t&&null!==n.element.data("select2")&&n.element.data("select2").destroy(),this.container=this.createContainer(),this.liveRegion=e("<span>",{role:"status","aria-live":"polite"}).addClass("select2-hidden-accessible").appendTo(document.body),this.containerId="s2id_"+(n.element.attr("id")||"autogen"+N()),this.containerEventName=this.containerId.replace(/([.])/g,"_").replace(/([;&,\-\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g,"\\$1"),this.container.attr("id",this.containerId),this.container.attr("title",n.element.attr("title")),this.body=e("body"),$(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.attr("style",n.element.attr("style")),this.container.css(S(n.containerCss,this.opts.element)),this.container.addClass(S(n.containerCssClass,this.opts.element)),this.elementTabIndex=this.opts.element.attr("tabindex"),this.opts.element.data("select2",this).attr("tabindex","-1").before(this.container).on("click.select2",g),this.container.data("select2",this),this.dropdown=this.container.find(".select2-drop"),$(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(S(n.dropdownCssClass,this.opts.element)),this.dropdown.data("select2",this),this.dropdown.on("click",g),this.results=i=this.container.find(".select2-results"),this.search=r=this.container.find("input.select2-input"),this.queryCount=0,this.resultsPage=0,this.context=null,this.initContainer(),this.container.on("click",g),u(this.results),this.dropdown.on("mousemove-filtered",".select2-results",this.bind(this.highlightUnderEvent)),this.dropdown.on("touchstart touchmove touchend",".select2-results",this.bind(function(e){this._touchEvent=!0,this.highlightUnderEvent(e)})),this.dropdown.on("touchmove",".select2-results",this.bind(this.touchMoved)),this.dropdown.on("touchstart touchend",".select2-results",this.bind(this.clearTouchMoved)),this.dropdown.on("click",this.bind(function(e){this._touchEvent&&(this._touchEvent=!1,this.selectHighlighted())})),f(80,this.results),this.dropdown.on("scroll-debounced",".select2-results",this.bind(this.loadMoreIfNeeded)),e(this.container).on("change",".select2-input",function(e){e.stopPropagation()}),e(this.dropdown).on("change",".select2-input",function(e){e.stopPropagation()}),e.fn.mousewheel&&i.mousewheel(function(e,t,n,r){var o=i.scrollTop();r>0&&o-r<=0?(i.scrollTop(0),g(e)):r<0&&i.get(0).scrollHeight-i.scrollTop()+r<=i.height()&&(i.scrollTop(i.get(0).scrollHeight-i.height()),g(e))}),c(r),r.on("keyup-change input paste",this.bind(this.updateResults)),r.on("focus",function(){r.addClass("select2-focused")}),r.on("blur",function(){r.removeClass("select2-focused")}),this.dropdown.on("mouseup",".select2-results",this.bind(function(t){e(t.target).closest(".select2-result-selectable").length>0&&(this.highlightUnderEvent(t),this.selectHighlighted(t))})),this.dropdown.on("click mouseup mousedown touchstart touchend focusin",function(e){e.stopPropagation()}),this.nextSearchTerm=t,e.isFunction(this.opts.initSelection)&&(this.initSelection(),this.monitorSource()),null!==n.maximumInputLength&&this.search.attr("maxlength",n.maximumInputLength);var a=n.element.prop("disabled");a===t&&(a=!1),this.enable(!a);var s=n.element.prop("readonly");s===t&&(s=!1),this.readonly(s),L=L||o(),this.autofocus=n.element.prop("autofocus"),n.element.prop("autofocus",!1),this.autofocus&&this.focus(),this.search.attr("placeholder",n.searchInputPlaceholder)},destroy:function(){var e=this.opts.element,n=e.data("select2"),i=this;this.close(),e.length&&e[0].detachEvent&&e.each(function(){this.detachEvent("onpropertychange",i._sync)}),this.propertyObserver&&(this.propertyObserver.disconnect(),this.propertyObserver=null),this._sync=null,n!==t&&(n.container.remove(),n.liveRegion.remove(),n.dropdown.remove(),e.removeClass("select2-offscreen").removeData("select2").off(".select2").prop("autofocus",this.autofocus||!1),this.elementTabIndex?e.attr({tabindex:this.elementTabIndex}):e.removeAttr("tabindex"),e.show()),
+D.call(this,"container","liveRegion","dropdown","results","search")},optionToData:function(e){return e.is("option")?{id:e.prop("value"),text:e.text(),element:e.get(),css:e.attr("class"),disabled:e.prop("disabled"),locked:a(e.attr("locked"),"locked")||a(e.data("locked"),!0)}:e.is("optgroup")?{text:e.attr("label"),children:[],element:e.get(),css:e.attr("class")}:void 0},prepareOpts:function(n){var i,r,o,l,c=this;if(i=n.element,"select"===i.get(0).tagName.toLowerCase()&&(this.select=r=n.element),r&&e.each(["id","multiple","ajax","query","createSearchChoice","initSelection","data","tags"],function(){if(this in n)throw new Error("Option '"+this+"' is not allowed for Select2 when attached to a <select> element.")}),n=e.extend({},{populateResults:function(i,r,o){var a,s=this.opts.id,l=this.liveRegion;(a=function(i,r,u){var d,f,p,h,g,m,v,$,y,b;i=n.sortResults(i,r,o);var w=[];for(d=0,f=i.length;d<f;d+=1)p=i[d],g=!0===p.disabled,h=!g&&s(p)!==t,m=p.children&&p.children.length>0,v=e("<li></li>"),v.addClass("select2-results-dept-"+u),v.addClass("select2-result"),v.addClass(h?"select2-result-selectable":"select2-result-unselectable"),g&&v.addClass("select2-disabled"),m&&v.addClass("select2-result-with-children"),v.addClass(c.opts.formatResultCssClass(p)),v.attr("role","presentation"),$=e(document.createElement("div")),$.addClass("select2-result-label"),$.attr("id","select2-result-label-"+N()),$.attr("role","option"),b=n.formatResult(p,$,o,c.opts.escapeMarkup),b!==t&&($.html(b),v.append($)),m&&(y=e("<ul></ul>"),y.addClass("select2-result-sub"),a(p.children,y,u+1),v.append(y)),v.data("select2-data",p),w.push(v[0]);r.append(w),l.text(n.formatMatches(i.length))})(r,i,0)}},e.fn.select2.defaults,n),"function"!=typeof n.id&&(o=n.id,n.id=function(e){return e[o]}),e.isArray(n.element.data("select2Tags"))){if("tags"in n)throw"tags specified as both an attribute 'data-select2-tags' and in options of Select2 "+n.element.attr("id");n.tags=n.element.data("select2Tags")}if(r?(n.query=this.bind(function(e){var n,r,o,a={results:[],more:!1},s=e.term;o=function(t,n){var i;t.is("option")?e.matcher(s,t.text(),t)&&n.push(c.optionToData(t)):t.is("optgroup")&&(i=c.optionToData(t),t.children().each2(function(e,t){o(t,i.children)}),i.children.length>0&&n.push(i))},n=i.children(),this.getPlaceholder()!==t&&n.length>0&&(r=this.getPlaceholderOption())&&(n=n.not(r)),n.each2(function(e,t){o(t,a.results)}),e.callback(a)}),n.id=function(e){return e.id}):"query"in n||("ajax"in n?(l=n.element.data("ajax-url"),l&&l.length>0&&(n.ajax.url=l),n.query=w.call(n.element,n.ajax)):"data"in n?n.query=x(n.data):"tags"in n&&(n.query=C(n.tags),n.createSearchChoice===t&&(n.createSearchChoice=function(t){return{id:e.trim(t),text:e.trim(t)}}),n.initSelection===t&&(n.initSelection=function(t,i){var r=[];e(s(t.val(),n.separator)).each(function(){var t={id:this,text:this},i=n.tags;e.isFunction(i)&&(i=i()),e(i).each(function(){if(a(this.id,t.id))return t=this,!1}),r.push(t)}),i(r)}))),"function"!=typeof n.query)throw"query function not defined for Select2 "+n.element.attr("id");if("top"===n.createSearchChoicePosition)n.createSearchChoicePosition=function(e,t){e.unshift(t)};else if("bottom"===n.createSearchChoicePosition)n.createSearchChoicePosition=function(e,t){e.push(t)};else if("function"!=typeof n.createSearchChoicePosition)throw"invalid createSearchChoicePosition option must be 'top', 'bottom' or a custom function";return n},monitorSource:function(){var n,i=this.opts.element,r=this;i.on("change.select2",this.bind(function(e){!0!==this.opts.element.data("select2-change-triggered")&&this.initSelection()})),this._sync=this.bind(function(){var e=i.prop("disabled");e===t&&(e=!1),this.enable(!e);var n=i.prop("readonly");n===t&&(n=!1),this.readonly(n),$(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.addClass(S(this.opts.containerCssClass,this.opts.element)),$(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(S(this.opts.dropdownCssClass,this.opts.element))}),i.length&&i[0].attachEvent&&i.each(function(){this.attachEvent("onpropertychange",r._sync)}),(n=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver)!==t&&(this.propertyObserver&&(delete this.propertyObserver,this.propertyObserver=null),this.propertyObserver=new n(function(t){e.each(t,r._sync)}),this.propertyObserver.observe(i.get(0),{attributes:!0,subtree:!1}))},triggerSelect:function(t){var n=e.Event("select2-selecting",{val:this.id(t),object:t,choice:t});return this.opts.element.trigger(n),!n.isDefaultPrevented()},triggerChange:function(t){t=t||{},t=e.extend({},t,{type:"change",val:this.val()}),this.opts.element.data("select2-change-triggered",!0),this.opts.element.trigger(t),this.opts.element.data("select2-change-triggered",!1),this.opts.element.click(),this.opts.blurOnChange&&this.opts.element.blur()},isInterfaceEnabled:function(){return!0===this.enabledInterface},enableInterface:function(){var e=this._enabled&&!this._readonly,t=!e;return e!==this.enabledInterface&&(this.container.toggleClass("select2-container-disabled",t),this.close(),this.enabledInterface=e,!0)},enable:function(e){e===t&&(e=!0),this._enabled!==e&&(this._enabled=e,this.opts.element.prop("disabled",!e),this.enableInterface())},disable:function(){this.enable(!1)},readonly:function(e){e===t&&(e=!1),this._readonly!==e&&(this._readonly=e,this.opts.element.prop("readonly",e),this.enableInterface())},opened:function(){return!!this.container&&this.container.hasClass("select2-dropdown-open")},positionDropdown:function(){var t,n,i,r,o,a=this.dropdown,s=this.container.offset(),l=this.container.outerHeight(!1),c=this.container.outerWidth(!1),u=a.outerHeight(!1),d=e(window),f=d.width(),p=d.height(),h=d.scrollLeft()+f,g=d.scrollTop()+p,m=s.top+l,v=s.left,$=m+u<=g,y=s.top-u>=d.scrollTop(),b=a.outerWidth(!1),w=v+b<=h,x=a.hasClass("select2-drop-above");x?(n=!0,!y&&$&&(i=!0,n=!1)):(n=!1,!$&&y&&(i=!0,n=!0)),i&&(a.hide(),s=this.container.offset(),l=this.container.outerHeight(!1),c=this.container.outerWidth(!1),u=a.outerHeight(!1),h=d.scrollLeft()+f,g=d.scrollTop()+p,m=s.top+l,v=s.left,b=a.outerWidth(!1),w=v+b<=h,a.show(),this.focusSearch()),this.opts.dropdownAutoWidth?(o=e(".select2-results",a)[0],a.addClass("select2-drop-auto-width"),a.css("width",""),b=a.outerWidth(!1)+(o.scrollHeight===o.clientHeight?0:L.width),b>c?c=b:b=c,u=a.outerHeight(!1),w=v+b<=h):this.container.removeClass("select2-drop-auto-width"),"static"!==this.body.css("position")&&(t=this.body.offset(),m-=t.top,v-=t.left),w||(v=s.left+this.container.outerWidth(!1)-b),r={left:v,width:c},n?(r.top=s.top-u,r.bottom="auto",this.container.addClass("select2-drop-above"),a.addClass("select2-drop-above")):(r.top=m,r.bottom="auto",this.container.removeClass("select2-drop-above"),a.removeClass("select2-drop-above")),r=e.extend(r,S(this.opts.dropdownCss,this.opts.element)),a.css(r)},shouldOpen:function(){var t;return!this.opened()&&(!1!==this._enabled&&!0!==this._readonly&&(t=e.Event("select2-opening"),this.opts.element.trigger(t),!t.isDefaultPrevented()))},clearDropdownAlignmentPreference:function(){this.container.removeClass("select2-drop-above"),this.dropdown.removeClass("select2-drop-above")},open:function(){return!!this.shouldOpen()&&(this.opening(),F.on("mousemove.select2Event",function(e){R.x=e.pageX,R.y=e.pageY}),!0)},opening:function(){var t,i=this.containerEventName,r="scroll."+i,o="resize."+i,a="orientationchange."+i;this.container.addClass("select2-dropdown-open").addClass("select2-container-active"),this.clearDropdownAlignmentPreference(),this.dropdown[0]!==this.body.children().last()[0]&&this.dropdown.detach().appendTo(this.body),t=e("#select2-drop-mask"),0==t.length&&(t=e(document.createElement("div")),t.attr("id","select2-drop-mask").attr("class","select2-drop-mask"),t.hide(),t.appendTo(this.body),t.on("mousedown touchstart click",function(i){n(t);var r,o=e("#select2-drop");o.length>0&&(r=o.data("select2"),r.opts.selectOnBlur&&r.selectHighlighted({noFocus:!0}),r.close(),i.preventDefault(),i.stopPropagation())})),this.dropdown.prev()[0]!==t[0]&&this.dropdown.before(t),e("#select2-drop").removeAttr("id"),this.dropdown.attr("id","select2-drop"),t.show(),this.positionDropdown(),this.dropdown.show(),this.positionDropdown(),this.dropdown.addClass("select2-drop-active");var s=this;this.container.parents().add(window).each(function(){e(this).on(o+" "+r+" "+a,function(e){s.opened()&&s.positionDropdown()})})},close:function(){if(this.opened()){var t=this.containerEventName,n="scroll."+t,i="resize."+t,r="orientationchange."+t;this.container.parents().add(window).each(function(){e(this).off(n).off(i).off(r)}),this.clearDropdownAlignmentPreference(),e("#select2-drop-mask").hide(),this.dropdown.removeAttr("id"),this.dropdown.hide(),this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active"),this.results.empty(),F.off("mousemove.select2Event"),this.clearSearch(),this.search.removeClass("select2-active"),this.opts.element.trigger(e.Event("select2-close"))}},externalSearch:function(e){this.open(),this.search.val(e),this.updateResults(!1)},clearSearch:function(){},getMaximumSelectionSize:function(){return S(this.opts.maximumSelectionSize,this.opts.element)},ensureHighlightVisible:function(){var t,n,i,r,o,a,s,l,c=this.results;if(!((n=this.highlight())<0)){if(0==n)return void c.scrollTop(0);t=this.findHighlightableChoices().find(".select2-result-label"),i=e(t[n]),l=(i.offset()||{}).top||0,r=l+i.outerHeight(!0),n===t.length-1&&(s=c.find("li.select2-more-results"),s.length>0&&(r=s.offset().top+s.outerHeight(!0))),o=c.offset().top+c.outerHeight(!0),r>o&&c.scrollTop(c.scrollTop()+(r-o)),a=l-c.offset().top,a<0&&"none"!=i.css("display")&&c.scrollTop(c.scrollTop()+a)}},findHighlightableChoices:function(){return this.results.find(".select2-result-selectable:not(.select2-disabled):not(.select2-selected)")},moveHighlight:function(t){for(var n=this.findHighlightableChoices(),i=this.highlight();i>-1&&i<n.length;){i+=t;var r=e(n[i]);if(r.hasClass("select2-result-selectable")&&!r.hasClass("select2-disabled")&&!r.hasClass("select2-selected")){this.highlight(i);break}}},highlight:function(t){var n,i,o=this.findHighlightableChoices();if(0===arguments.length)return r(o.filter(".select2-highlighted")[0],o.get());t>=o.length&&(t=o.length-1),t<0&&(t=0),this.removeHighlight(),n=e(o[t]),n.addClass("select2-highlighted"),this.search.attr("aria-activedescendant",n.find(".select2-result-label").attr("id")),this.ensureHighlightVisible(),this.liveRegion.text(n.text()),(i=n.data("select2-data"))&&this.opts.element.trigger({type:"select2-highlight",val:this.id(i),choice:i})},removeHighlight:function(){this.results.find(".select2-highlighted").removeClass("select2-highlighted")},touchMoved:function(){this._touchMoved=!0},clearTouchMoved:function(){this._touchMoved=!1},countSelectableResults:function(){return this.findHighlightableChoices().length},highlightUnderEvent:function(t){var n=e(t.target).closest(".select2-result-selectable");if(n.length>0&&!n.is(".select2-highlighted")){var i=this.findHighlightableChoices();this.highlight(i.index(n))}else 0==n.length&&this.removeHighlight()},loadMoreIfNeeded:function(){var e=this.results,t=e.find("li.select2-more-results"),n=this.resultsPage+1,i=this,r=this.search.val(),o=this.context;0!==t.length&&t.offset().top-e.offset().top-e.height()<=this.opts.loadMorePadding&&(t.addClass("select2-active"),this.opts.query({element:this.opts.element,term:r,page:n,context:o,matcher:this.opts.matcher,callback:this.bind(function(a){i.opened()&&(i.opts.populateResults.call(this,e,a.results,{term:r,page:n,context:o}),i.postprocessResults(a,!1,!1),!0===a.more?(t.detach().appendTo(e).text(S(i.opts.formatLoadMore,i.opts.element,n+1)),window.setTimeout(function(){i.loadMoreIfNeeded()},10)):t.remove(),i.positionDropdown(),i.resultsPage=n,i.context=a.context,this.opts.element.trigger({type:"select2-loaded",items:a}))})}))},tokenize:function(){},updateResults:function(n){function i(){c.removeClass("select2-active"),f.positionDropdown(),u.find(".select2-no-results,.select2-selection-limit,.select2-searching").length?f.liveRegion.text(u.text()):f.liveRegion.text(f.opts.formatMatches(u.find(".select2-result-selectable").length))}function r(e){u.html(e),i()}var o,s,l,c=this.search,u=this.results,d=this.opts,f=this,p=c.val(),h=e.data(this.container,"select2-last-term");if((!0===n||!h||!a(p,h))&&(e.data(this.container,"select2-last-term",p),!0===n||!1!==this.showSearchInput&&this.opened())){l=++this.queryCount;var g=this.getMaximumSelectionSize();if(g>=1&&(o=this.data(),e.isArray(o)&&o.length>=g&&k(d.formatSelectionTooBig,"formatSelectionTooBig")))return void r("<li class='select2-selection-limit'>"+S(d.formatSelectionTooBig,d.element,g)+"</li>");if(c.val().length<d.minimumInputLength)return r(k(d.formatInputTooShort,"formatInputTooShort")?"<li class='select2-no-results'>"+S(d.formatInputTooShort,d.element,c.val(),d.minimumInputLength)+"</li>":""),void(n&&this.showSearch&&this.showSearch(!0));if(d.maximumInputLength&&c.val().length>d.maximumInputLength)return void r(k(d.formatInputTooLong,"formatInputTooLong")?"<li class='select2-no-results'>"+S(d.formatInputTooLong,d.element,c.val(),d.maximumInputLength)+"</li>":"");d.formatSearching&&0===this.findHighlightableChoices().length&&r("<li class='select2-searching'>"+S(d.formatSearching,d.element)+"</li>"),c.addClass("select2-active"),this.removeHighlight(),s=this.tokenize(),s!=t&&null!=s&&c.val(s),this.resultsPage=1,d.query({element:d.element,term:c.val(),page:this.resultsPage,context:null,matcher:d.matcher,callback:this.bind(function(o){var s;if(l==this.queryCount){if(!this.opened())return void this.search.removeClass("select2-active");if(o.hasError!==t&&k(d.formatAjaxError,"formatAjaxError"))return void r("<li class='select2-ajax-error'>"+S(d.formatAjaxError,d.element,o.jqXHR,o.textStatus,o.errorThrown)+"</li>");if(this.context=o.context===t?null:o.context,this.opts.createSearchChoice&&""!==c.val()&&(s=this.opts.createSearchChoice.call(f,c.val(),o.results))!==t&&null!==s&&f.id(s)!==t&&null!==f.id(s)&&0===e(o.results).filter(function(){return a(f.id(this),f.id(s))}).length&&this.opts.createSearchChoicePosition(o.results,s),0===o.results.length&&k(d.formatNoMatches,"formatNoMatches"))return void r("<li class='select2-no-results'>"+S(d.formatNoMatches,d.element,c.val())+"</li>");u.empty(),f.opts.populateResults.call(this,u,o.results,{term:c.val(),page:this.resultsPage,context:null}),!0===o.more&&k(d.formatLoadMore,"formatLoadMore")&&(u.append("<li class='select2-more-results'>"+d.escapeMarkup(S(d.formatLoadMore,d.element,this.resultsPage))+"</li>"),window.setTimeout(function(){f.loadMoreIfNeeded()},10)),this.postprocessResults(o,n),i(),this.opts.element.trigger({type:"select2-loaded",items:o})}})})}},cancel:function(){this.close()},blur:function(){this.opts.selectOnBlur&&this.selectHighlighted({noFocus:!0}),this.close(),this.container.removeClass("select2-container-active"),this.search[0]===document.activeElement&&this.search.blur(),this.clearSearch(),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus")},focusSearch:function(){p(this.search)},selectHighlighted:function(e){if(this._touchMoved)return void this.clearTouchMoved();var t=this.highlight(),n=this.results.find(".select2-highlighted"),i=n.closest(".select2-result").data("select2-data");i?(this.highlight(t),this.onSelect(i,e)):e&&e.noFocus&&this.close()},getPlaceholder:function(){var e;return this.opts.element.attr("placeholder")||this.opts.element.attr("data-placeholder")||this.opts.element.data("placeholder")||this.opts.placeholder||((e=this.getPlaceholderOption())!==t?e.text():t)},getPlaceholderOption:function(){if(this.select){var n=this.select.children("option").first();if(this.opts.placeholderOption!==t)return"first"===this.opts.placeholderOption&&n||"function"==typeof this.opts.placeholderOption&&this.opts.placeholderOption(this.select);if(""===e.trim(n.text())&&""===n.val())return n}},initContainerWidth:function(){function n(){var n,i,r,o,a,s;if("off"===this.opts.width)return null;if("element"===this.opts.width)return 0===this.opts.element.outerWidth(!1)?"auto":this.opts.element.outerWidth(!1)+"px";if("copy"===this.opts.width||"resolve"===this.opts.width){if((n=this.opts.element.attr("style"))!==t)for(i=n.split(";"),o=0,a=i.length;o<a;o+=1)if(s=i[o].replace(/\s/g,""),null!==(r=s.match(/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i))&&r.length>=1)return r[1];return"resolve"===this.opts.width?(n=this.opts.element.css("width"),n.indexOf("%")>0?n:0===this.opts.element.outerWidth(!1)?"auto":this.opts.element.outerWidth(!1)+"px"):null}return e.isFunction(this.opts.width)?this.opts.width():this.opts.width}var i=n.call(this);null!==i&&this.container.css("width",i)}}),I=A(O,{createContainer:function(){return e(document.createElement("div")).attr({class:"select2-container"}).html(["<a href='javascript:void(0)' class='select2-choice' tabindex='-1'>"," <span class='select2-chosen'>&#160;</span><abbr class='select2-search-choice-close'></abbr>"," <span class='select2-arrow' role='presentation'><b role='presentation'></b></span>","</a>","<label for='' class='select2-offscreen'></label>","<input class='select2-focusser select2-offscreen' type='text' aria-haspopup='true' role='button' />","<div class='select2-drop select2-display-none'>"," <div class='select2-search'>"," <label for='' class='select2-offscreen'></label>"," <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input' role='combobox' aria-expanded='true'"," aria-autocomplete='list' />"," </div>"," <ul class='select2-results' role='listbox'>"," </ul>","</div>"].join(""))},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.focusser.prop("disabled",!this.isInterfaceEnabled())},opening:function(){var n,i,r;this.opts.minimumResultsForSearch>=0&&this.showSearch(!0),this.parent.opening.apply(this,arguments),!1!==this.showSearchInput&&this.search.val(this.focusser.val()),this.opts.shouldFocusInput(this)&&(this.search.focus(),n=this.search.get(0),n.createTextRange?(i=n.createTextRange(),i.collapse(!1),i.select()):n.setSelectionRange&&(r=this.search.val().length,n.setSelectionRange(r,r))),""===this.search.val()&&this.nextSearchTerm!=t&&(this.search.val(this.nextSearchTerm),this.search.select()),this.focusser.prop("disabled",!0).val(""),this.updateResults(!0),this.opts.element.trigger(e.Event("select2-open"))},close:function(){this.opened()&&(this.parent.close.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},focus:function(){this.opened()?this.close():(this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus())},isFocused:function(){return this.container.hasClass("select2-container-active")},cancel:function(){this.parent.cancel.apply(this,arguments),this.focusser.prop("disabled",!1),this.opts.shouldFocusInput(this)&&this.focusser.focus()},destroy:function(){e("label[for='"+this.focusser.attr("id")+"']").attr("for",this.opts.element.attr("id")),this.parent.destroy.apply(this,arguments),D.call(this,"selection","focusser")},initContainer:function(){var t,i,r=this.container,o=this.dropdown,a=N();this.opts.minimumResultsForSearch<0?this.showSearch(!1):this.showSearch(!0),this.selection=t=r.find(".select2-choice"),this.focusser=r.find(".select2-focusser"),t.find(".select2-chosen").attr("id","select2-chosen-"+a),this.focusser.attr("aria-labelledby","select2-chosen-"+a),this.results.attr("id","select2-results-"+a),this.search.attr("aria-owns","select2-results-"+a),this.focusser.attr("id","s2id_autogen"+a),i=e("label[for='"+this.opts.element.attr("id")+"']"),this.focusser.prev().text(i.text()).attr("for",this.focusser.attr("id"));var s=this.opts.element.attr("title");this.opts.element.attr("title",s||i.text()),this.focusser.attr("tabindex",this.elementTabIndex),this.search.attr("id",this.focusser.attr("id")+"_search"),this.search.prev().text(e("label[for='"+this.focusser.attr("id")+"']").text()).attr("for",this.search.attr("id")),this.search.on("keydown",this.bind(function(e){if(this.isInterfaceEnabled()&&229!=e.keyCode){if(e.which===M.PAGE_UP||e.which===M.PAGE_DOWN)return void g(e);switch(e.which){case M.UP:case M.DOWN:return this.moveHighlight(e.which===M.UP?-1:1),void g(e);case M.ENTER:return this.selectHighlighted(),void g(e);case M.TAB:return void this.selectHighlighted({noFocus:!0});case M.ESC:return this.cancel(e),void g(e)}}})),this.search.on("blur",this.bind(function(e){document.activeElement===this.body.get(0)&&window.setTimeout(this.bind(function(){this.opened()&&this.search.focus()}),0)})),this.focusser.on("keydown",this.bind(function(e){if(this.isInterfaceEnabled()&&e.which!==M.TAB&&!M.isControl(e)&&!M.isFunctionKey(e)&&e.which!==M.ESC){if(!1===this.opts.openOnEnter&&e.which===M.ENTER)return void g(e);if(e.which==M.DOWN||e.which==M.UP||e.which==M.ENTER&&this.opts.openOnEnter){if(e.altKey||e.ctrlKey||e.shiftKey||e.metaKey)return;return this.open(),void g(e)}return e.which==M.DELETE||e.which==M.BACKSPACE?(this.opts.allowClear&&this.clear(),void g(e)):void 0}})),c(this.focusser),this.focusser.on("keyup-change input",this.bind(function(e){if(this.opts.minimumResultsForSearch>=0){if(e.stopPropagation(),this.opened())return;this.open()}})),t.on("mousedown touchstart","abbr",this.bind(function(e){this.isInterfaceEnabled()&&(this.clear(),m(e),this.close(),this.selection.focus())})),t.on("mousedown touchstart",this.bind(function(i){n(t),this.container.hasClass("select2-container-active")||this.opts.element.trigger(e.Event("select2-focus")),this.opened()?this.close():this.isInterfaceEnabled()&&this.open(),g(i)})),o.on("mousedown touchstart",this.bind(function(){this.opts.shouldFocusInput(this)&&this.search.focus()})),t.on("focus",this.bind(function(e){g(e)})),this.focusser.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(e.Event("select2-focus")),this.container.addClass("select2-container-active")})).on("blur",this.bind(function(){this.opened()||(this.container.removeClass("select2-container-active"),this.opts.element.trigger(e.Event("select2-blur")))})),this.search.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(e.Event("select2-focus")),this.container.addClass("select2-container-active")})),this.initContainerWidth(),this.opts.element.addClass("select2-offscreen"),this.setPlaceholder()},clear:function(t){var n=this.selection.data("select2-data");if(n){var i=e.Event("select2-clearing");if(this.opts.element.trigger(i),i.isDefaultPrevented())return;var r=this.getPlaceholderOption();this.opts.element.val(r?r.val():""),this.selection.find(".select2-chosen").empty(),this.selection.removeData("select2-data"),this.setPlaceholder(),!1!==t&&(this.opts.element.trigger({type:"select2-removed",val:this.id(n),choice:n}),this.triggerChange({removed:n}))}},initSelection:function(){if(this.isPlaceholderOptionSelected())this.updateSelection(null),this.close(),this.setPlaceholder();else{var e=this;this.opts.initSelection.call(null,this.opts.element,function(n){n!==t&&null!==n&&(e.updateSelection(n),e.close(),e.setPlaceholder(),e.nextSearchTerm=e.opts.nextSearchTerm(n,e.search.val()))})}},isPlaceholderOptionSelected:function(){var e;return this.getPlaceholder()!==t&&((e=this.getPlaceholderOption())!==t&&e.prop("selected")||""===this.opts.element.val()||this.opts.element.val()===t||null===this.opts.element.val())},prepareOpts:function(){var t=this.parent.prepareOpts.apply(this,arguments),n=this;return"select"===t.element.get(0).tagName.toLowerCase()?t.initSelection=function(e,t){var i=e.find("option").filter(function(){return this.selected&&!this.disabled});t(n.optionToData(i))}:"data"in t&&(t.initSelection=t.initSelection||function(n,i){var r=n.val(),o=null;t.query({matcher:function(e,n,i){var s=a(r,t.id(i));return s&&(o=i),s},callback:e.isFunction(i)?function(){i(o)}:e.noop})}),t},getPlaceholder:function(){return this.select&&this.getPlaceholderOption()===t?t:this.parent.getPlaceholder.apply(this,arguments)},setPlaceholder:function(){var e=this.getPlaceholder();if(this.isPlaceholderOptionSelected()&&e!==t){if(this.select&&this.getPlaceholderOption()===t)return;this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(e)),this.selection.addClass("select2-default"),this.container.removeClass("select2-allowclear")}},postprocessResults:function(e,t,n){var i=0,r=this;if(this.findHighlightableChoices().each2(function(e,t){if(a(r.id(t.data("select2-data")),r.opts.element.val()))return i=e,!1}),!1!==n&&(!0===t&&i>=0?this.highlight(i):this.highlight(0)),!0===t){var o=this.opts.minimumResultsForSearch;o>=0&&this.showSearch(E(e.results)>=o)}},showSearch:function(t){this.showSearchInput!==t&&(this.showSearchInput=t,this.dropdown.find(".select2-search").toggleClass("select2-search-hidden",!t),this.dropdown.find(".select2-search").toggleClass("select2-offscreen",!t),e(this.dropdown,this.container).toggleClass("select2-with-searchbox",t))},onSelect:function(e,t){if(this.triggerSelect(e)){var n=this.opts.element.val(),i=this.data();this.opts.element.val(this.id(e)),this.updateSelection(e),this.opts.element.trigger({type:"select2-selected",val:this.id(e),choice:e}),this.nextSearchTerm=this.opts.nextSearchTerm(e,this.search.val()),this.close(),t&&t.noFocus||!this.opts.shouldFocusInput(this)||this.focusser.focus(),a(n,this.id(e))||this.triggerChange({added:e,removed:i})}},updateSelection:function(e){var n,i,r=this.selection.find(".select2-chosen");this.selection.data("select2-data",e),r.empty(),null!==e&&(n=this.opts.formatSelection(e,r,this.opts.escapeMarkup)),n!==t&&r.append(n),i=this.opts.formatSelectionCssClass(e,r),i!==t&&r.addClass(i),this.selection.removeClass("select2-default"),this.opts.allowClear&&this.getPlaceholder()!==t&&this.container.addClass("select2-allowclear")},val:function(){var e,n=!1,i=null,r=this,o=this.data();if(0===arguments.length)return this.opts.element.val();if(e=arguments[0],arguments.length>1&&(n=arguments[1]),this.select)this.select.val(e).find("option").filter(function(){return this.selected}).each2(function(e,t){return i=r.optionToData(t),!1}),this.updateSelection(i),this.setPlaceholder(),n&&this.triggerChange({added:i,removed:o});else{if(!e&&0!==e)return void this.clear(n);if(this.opts.initSelection===t)throw new Error("cannot call val() if initSelection() is not defined");this.opts.element.val(e),this.opts.initSelection(this.opts.element,function(e){r.opts.element.val(e?r.id(e):""),r.updateSelection(e),r.setPlaceholder(),n&&r.triggerChange({added:e,removed:o})})}},clearSearch:function(){this.search.val(""),this.focusser.val("")},data:function(e){var n,i=!1;if(0===arguments.length)return n=this.selection.data("select2-data"),n==t&&(n=null),n;arguments.length>1&&(i=arguments[1]),e?(n=this.data(),this.opts.element.val(e?this.id(e):""),this.updateSelection(e),i&&this.triggerChange({added:e,removed:n})):this.clear(i)}}),P=A(O,{createContainer:function(){return e(document.createElement("div")).attr({class:"select2-container select2-container-multi"}).html(["<ul class='select2-choices'>"," <li class='select2-search-field'>"," <label for='' class='select2-offscreen'></label>"," <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>"," </li>","</ul>","<div class='select2-drop select2-drop-multi select2-display-none'>"," <ul class='select2-results'>"," </ul>","</div>"].join(""))},prepareOpts:function(){var t=this.parent.prepareOpts.apply(this,arguments),n=this;return"select"===t.element.get(0).tagName.toLowerCase()?t.initSelection=function(e,t){var i=[];e.find("option").filter(function(){return this.selected&&!this.disabled}).each2(function(e,t){i.push(n.optionToData(t))}),t(i)}:"data"in t&&(t.initSelection=t.initSelection||function(n,i){var r=s(n.val(),t.separator),o=[];t.query({matcher:function(n,i,s){var l=e.grep(r,function(e){return a(e,t.id(s))}).length;return l&&o.push(s),l},callback:e.isFunction(i)?function(){for(var e=[],n=0;n<r.length;n++)for(var s=r[n],l=0;l<o.length;l++){var c=o[l];if(a(s,t.id(c))){e.push(c),o.splice(l,1);break}}i(e)}:e.noop})}),t},selectChoice:function(e){var t=this.container.find(".select2-search-choice-focus");t.length&&e&&e[0]==t[0]||(t.length&&this.opts.element.trigger("choice-deselected",t),t.removeClass("select2-search-choice-focus"),e&&e.length&&(this.close(),e.addClass("select2-search-choice-focus"),this.opts.element.trigger("choice-selected",e)))},destroy:function(){e("label[for='"+this.search.attr("id")+"']").attr("for",this.opts.element.attr("id")),this.parent.destroy.apply(this,arguments),D.call(this,"searchContainer","selection")},initContainer:function(){var t,n=".select2-choices";this.searchContainer=this.container.find(".select2-search-field"),this.selection=t=this.container.find(n);var i=this;this.selection.on("click",".select2-search-choice:not(.select2-locked)",function(t){i.search[0].focus(),i.selectChoice(e(this))}),this.search.attr("id","s2id_autogen"+N()),this.search.prev().text(e("label[for='"+this.opts.element.attr("id")+"']").text()).attr("for",this.search.attr("id")),this.search.on("input paste",this.bind(function(){this.search.attr("placeholder")&&0==this.search.val().length||this.isInterfaceEnabled()&&(this.opened()||this.open())})),this.search.attr("tabindex",this.elementTabIndex),this.keydowns=0,this.search.on("keydown",this.bind(function(e){if(this.isInterfaceEnabled()){++this.keydowns;var n=t.find(".select2-search-choice-focus"),i=n.prev(".select2-search-choice:not(.select2-locked)"),r=n.next(".select2-search-choice:not(.select2-locked)"),o=h(this.search);if(n.length&&(e.which==M.LEFT||e.which==M.RIGHT||e.which==M.BACKSPACE||e.which==M.DELETE||e.which==M.ENTER)){var a=n;return e.which==M.LEFT&&i.length?a=i:e.which==M.RIGHT?a=r.length?r:null:e.which===M.BACKSPACE?this.unselect(n.first())&&(this.search.width(10),a=i.length?i:r):e.which==M.DELETE?this.unselect(n.first())&&(this.search.width(10),a=r.length?r:null):e.which==M.ENTER&&(a=null),this.selectChoice(a),g(e),void(a&&a.length||this.open())}if((e.which===M.BACKSPACE&&1==this.keydowns||e.which==M.LEFT)&&0==o.offset&&!o.length)return this.selectChoice(t.find(".select2-search-choice:not(.select2-locked)").last()),void g(e);if(this.selectChoice(null),this.opened())switch(e.which){case M.UP:case M.DOWN:return this.moveHighlight(e.which===M.UP?-1:1),void g(e);case M.ENTER:return this.selectHighlighted(),void g(e);case M.TAB:return this.selectHighlighted({noFocus:!0}),void this.close();case M.ESC:return this.cancel(e),void g(e)}if(e.which!==M.TAB&&!M.isControl(e)&&!M.isFunctionKey(e)&&e.which!==M.BACKSPACE&&e.which!==M.ESC){if(e.which===M.ENTER){if(!1===this.opts.openOnEnter)return;if(e.altKey||e.ctrlKey||e.shiftKey||e.metaKey)return}this.open(),e.which!==M.PAGE_UP&&e.which!==M.PAGE_DOWN||g(e),e.which===M.ENTER&&g(e)}}})),this.search.on("keyup",this.bind(function(e){this.keydowns=0,this.resizeSearch()})),this.search.on("blur",this.bind(function(t){this.container.removeClass("select2-container-active"),this.search.removeClass("select2-focused"),this.selectChoice(null),this.opened()||this.clearSearch(),t.stopImmediatePropagation(),this.opts.element.trigger(e.Event("select2-blur"))})),this.container.on("click",n,this.bind(function(t){this.isInterfaceEnabled()&&(e(t.target).closest(".select2-search-choice").length>0||(this.selectChoice(null),this.clearPlaceholder(),this.container.hasClass("select2-container-active")||this.opts.element.trigger(e.Event("select2-focus")),this.open(),this.focusSearch(),t.preventDefault()))})),this.container.on("focus",n,this.bind(function(){
+this.isInterfaceEnabled()&&(this.container.hasClass("select2-container-active")||this.opts.element.trigger(e.Event("select2-focus")),this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"),this.clearPlaceholder())})),this.initContainerWidth(),this.opts.element.addClass("select2-offscreen"),this.clearSearch()},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.search.prop("disabled",!this.isInterfaceEnabled())},initSelection:function(){if(""===this.opts.element.val()&&""===this.opts.element.text()&&(this.updateSelection([]),this.close(),this.clearSearch()),this.select||""!==this.opts.element.val()){var e=this;this.opts.initSelection.call(null,this.opts.element,function(n){n!==t&&null!==n&&(e.updateSelection(n),e.close(),e.clearSearch())})}},clearSearch:function(){var e=this.getPlaceholder(),n=this.getMaxSearchWidth();e!==t&&0===this.getVal().length&&!1===this.search.hasClass("select2-focused")?(this.search.val(e).addClass("select2-default"),this.search.width(n>0?n:this.container.css("width"))):this.search.val("").width(10)},clearPlaceholder:function(){this.search.hasClass("select2-default")&&this.search.val("").removeClass("select2-default")},opening:function(){this.clearPlaceholder(),this.resizeSearch(),this.parent.opening.apply(this,arguments),this.focusSearch(),""===this.search.val()&&this.nextSearchTerm!=t&&(this.search.val(this.nextSearchTerm),this.search.select()),this.updateResults(!0),this.opts.shouldFocusInput(this)&&this.search.focus(),this.opts.element.trigger(e.Event("select2-open"))},close:function(){this.opened()&&this.parent.close.apply(this,arguments)},focus:function(){this.close(),this.search.focus()},isFocused:function(){return this.search.hasClass("select2-focused")},updateSelection:function(t){var n=[],i=[],o=this;e(t).each(function(){r(o.id(this),n)<0&&(n.push(o.id(this)),i.push(this))}),t=i,this.selection.find(".select2-search-choice").remove(),e(t).each(function(){o.addSelectedChoice(this)}),o.postprocessResults()},tokenize:function(){var e=this.search.val();null!=(e=this.opts.tokenizer.call(this,e,this.data(),this.bind(this.onSelect),this.opts))&&e!=t&&(this.search.val(e),e.length>0&&this.open())},onSelect:function(e,n){this.triggerSelect(e)&&""!==e.text&&(this.addSelectedChoice(e),this.opts.element.trigger({type:"selected",val:this.id(e),choice:e}),this.nextSearchTerm=this.opts.nextSearchTerm(e,this.search.val()),this.clearSearch(),this.updateResults(),!this.select&&this.opts.closeOnSelect||this.postprocessResults(e,!1,!0===this.opts.closeOnSelect),this.opts.closeOnSelect?(this.close(),this.search.width(10)):this.countSelectableResults()>0?(this.search.width(10),this.resizeSearch(),this.getMaximumSelectionSize()>0&&this.val().length>=this.getMaximumSelectionSize()?this.updateResults(!0):this.nextSearchTerm!=t&&(this.search.val(this.nextSearchTerm),this.updateResults(),this.search.select()),this.positionDropdown()):(this.close(),this.search.width(10)),this.triggerChange({added:e}),n&&n.noFocus||this.focusSearch())},cancel:function(){this.close(),this.focusSearch()},addSelectedChoice:function(n){var i,r,o=!n.locked,a=e("<li class='select2-search-choice'> <div></div> <a href='#' class='select2-search-choice-close' tabindex='-1'></a></li>"),s=e("<li class='select2-search-choice select2-locked'><div></div></li>"),l=o?a:s,c=this.id(n),u=this.getVal();i=this.opts.formatSelection(n,l.find("div"),this.opts.escapeMarkup),i!=t&&l.find("div").replaceWith("<div>"+i+"</div>"),r=this.opts.formatSelectionCssClass(n,l.find("div")),r!=t&&l.addClass(r),o&&l.find(".select2-search-choice-close").on("mousedown",g).on("click dblclick",this.bind(function(t){this.isInterfaceEnabled()&&(this.unselect(e(t.target)),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"),g(t),this.close(),this.focusSearch())})).on("focus",this.bind(function(){this.isInterfaceEnabled()&&(this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"))})),l.data("select2-data",n),l.insertBefore(this.searchContainer),u.push(c),this.setVal(u)},unselect:function(t){var n,i,o=this.getVal();if(t=t.closest(".select2-search-choice"),0===t.length)throw"Invalid argument: "+t+". Must be .select2-search-choice";if(n=t.data("select2-data")){var a=e.Event("select2-removing");if(a.val=this.id(n),a.choice=n,this.opts.element.trigger(a),a.isDefaultPrevented())return!1;for(;(i=r(this.id(n),o))>=0;)o.splice(i,1),this.setVal(o),this.select&&this.postprocessResults();return t.remove(),this.opts.element.trigger({type:"select2-removed",val:this.id(n),choice:n}),this.triggerChange({removed:n}),!0}},postprocessResults:function(e,t,n){var i=this.getVal(),o=this.results.find(".select2-result"),a=this.results.find(".select2-result-with-children"),s=this;o.each2(function(e,t){r(s.id(t.data("select2-data")),i)>=0&&(t.addClass("select2-selected"),t.find(".select2-result-selectable").addClass("select2-selected"))}),a.each2(function(e,t){t.is(".select2-result-selectable")||0!==t.find(".select2-result-selectable:not(.select2-selected)").length||t.addClass("select2-selected")}),-1==this.highlight()&&!1!==n&&s.highlight(0),!this.opts.createSearchChoice&&!o.filter(".select2-result:not(.select2-selected)").length>0&&(!e||e&&!e.more&&0===this.results.find(".select2-no-results").length)&&k(s.opts.formatNoMatches,"formatNoMatches")&&this.results.append("<li class='select2-no-results'>"+S(s.opts.formatNoMatches,s.opts.element,s.search.val())+"</li>")},getMaxSearchWidth:function(){return this.selection.width()-l(this.search)},resizeSearch:function(){var e,t,n,i,r,o=l(this.search);e=v(this.search)+10,t=this.search.offset().left,n=this.selection.width(),i=this.selection.offset().left,r=n-(t-i)-o,r<e&&(r=n-o),r<40&&(r=n-o),r<=0&&(r=e),this.search.width(Math.floor(r))},getVal:function(){var e;return this.select?(e=this.select.val(),null===e?[]:e):(e=this.opts.element.val(),s(e,this.opts.separator))},setVal:function(t){var n;this.select?this.select.val(t):(n=[],e(t).each(function(){r(this,n)<0&&n.push(this)}),this.opts.element.val(0===n.length?"":n.join(this.opts.separator)))},buildChangeDetails:function(e,t){for(var t=t.slice(0),e=e.slice(0),n=0;n<t.length;n++)for(var i=0;i<e.length;i++)a(this.opts.id(t[n]),this.opts.id(e[i]))&&(t.splice(n,1),n>0&&n--,e.splice(i,1),i--);return{added:t,removed:e}},val:function(n,i){var r,o=this;if(0===arguments.length)return this.getVal();if(r=this.data(),r.length||(r=[]),!n&&0!==n)return this.opts.element.val(""),this.updateSelection([]),this.clearSearch(),void(i&&this.triggerChange({added:this.data(),removed:r}));if(this.setVal(n),this.select)this.opts.initSelection(this.select,this.bind(this.updateSelection)),i&&this.triggerChange(this.buildChangeDetails(r,this.data()));else{if(this.opts.initSelection===t)throw new Error("val() cannot be called if initSelection() is not defined");this.opts.initSelection(this.opts.element,function(t){var n=e.map(t,o.id);o.setVal(n),o.updateSelection(t),o.clearSearch(),i&&o.triggerChange(o.buildChangeDetails(r,o.data()))})}this.clearSearch()},onSortStart:function(){if(this.select)throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead.");this.search.width(0),this.searchContainer.hide()},onSortEnd:function(){var t=[],n=this;this.searchContainer.show(),this.searchContainer.appendTo(this.searchContainer.parent()),this.resizeSearch(),this.selection.find(".select2-search-choice").each(function(){t.push(n.opts.id(e(this).data("select2-data")))}),this.setVal(t),this.triggerChange()},data:function(t,n){var i,r,o=this;if(0===arguments.length)return this.selection.children(".select2-search-choice").map(function(){return e(this).data("select2-data")}).get();r=this.data(),t||(t=[]),i=e.map(t,function(e){return o.opts.id(e)}),this.setVal(i),this.updateSelection(t),this.clearSearch(),n&&this.triggerChange(this.buildChangeDetails(r,this.data()))}}),e.fn.select2=function(){var n,i,o,a,s,l=Array.prototype.slice.call(arguments,0),c=["val","destroy","opened","open","close","focus","isFocused","container","dropdown","onSortStart","onSortEnd","enable","disable","readonly","positionDropdown","data","search"],u=["opened","isFocused","container","dropdown"],d=["val","data"],f={search:"externalSearch"};return this.each(function(){if(0===l.length||"object"==typeof l[0])n=0===l.length?{}:e.extend({},l[0]),n.element=e(this),"select"===n.element.get(0).tagName.toLowerCase()?s=n.element.prop("multiple"):(s=n.multiple||!1,"tags"in n&&(n.multiple=s=!0)),i=s?new window.Select2.class.multi:new window.Select2.class.single,i.init(n);else{if("string"!=typeof l[0])throw"Invalid arguments to select2 plugin: "+l;if(r(l[0],c)<0)throw"Unknown method: "+l[0];if(a=t,(i=e(this).data("select2"))===t)return;if(o=l[0],"container"===o?a=i.container:"dropdown"===o?a=i.dropdown:(f[o]&&(o=f[o]),a=i[o].apply(i,l.slice(1))),r(l[0],u)>=0||r(l[0],d)>=0&&1==l.length)return!1}}),a===t?this:a},e.fn.select2.defaults={width:"copy",loadMorePadding:0,closeOnSelect:!0,openOnEnter:!0,containerCss:{},dropdownCss:{},containerCssClass:"",dropdownCssClass:"",formatResult:function(e,t,n,i){var r=[];return y(e.text,n.term,r,i),r.join("")},formatSelection:function(e,n,i){return e?i(e.text):t},sortResults:function(e,t,n){return e},formatResultCssClass:function(e){return e.css},formatSelectionCssClass:function(e,n){return t},minimumResultsForSearch:0,minimumInputLength:0,maximumInputLength:null,maximumSelectionSize:0,id:function(e){return e==t?null:e.id},matcher:function(e,t){return i(""+t).toUpperCase().indexOf(i(""+e).toUpperCase())>=0},separator:",",tokenSeparators:[],tokenizer:T,escapeMarkup:b,blurOnChange:!1,selectOnBlur:!1,adaptContainerCssClass:function(e){return e},adaptDropdownCssClass:function(e){return null},nextSearchTerm:function(e,n){return t},searchInputPlaceholder:"",createSearchChoicePosition:"top",shouldFocusInput:function(e){return!(("ontouchstart"in window||navigator.msMaxTouchPoints>0)&&e.opts.minimumResultsForSearch<0)}},e.fn.select2.locales=[],e.fn.select2.locales.en={formatMatches:function(e){return 1===e?"One result is available, press enter to select it.":e+" results are available, use up and down arrow keys to navigate."},formatNoMatches:function(){return"No matches found"},formatAjaxError:function(e,t,n){return"Loading failed"},formatInputTooShort:function(e,t){var n=t-e.length;return"Please enter "+n+" or more character"+(1==n?"":"s")},formatInputTooLong:function(e,t){var n=e.length-t;return"Please delete "+n+" character"+(1==n?"":"s")},formatSelectionTooBig:function(e){return"You can only select "+e+" item"+(1==e?"":"s")},formatLoadMore:function(e){return"Loading more results…"},formatSearching:function(){return"Searching…"}},e.extend(e.fn.select2.defaults,e.fn.select2.locales.en),e.fn.select2.ajaxDefaults={transport:e.ajax,params:{type:"GET",cache:!1,dataType:"json"}},window.Select2={query:{ajax:w,local:x,tags:C},util:{debounce:d,markMatch:y,escapeMarkup:b,stripDiacritics:i},class:{abstract:O,single:I,multi:P}}}}(jQuery),function(){"use strict";var e={TAB:9,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,SHIFT:16,CTRL:17,ALT:18,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,BACKSPACE:8,DELETE:46,COMMAND:91,MAP:{91:"COMMAND",8:"BACKSPACE",9:"TAB",13:"ENTER",16:"SHIFT",17:"CTRL",18:"ALT",19:"PAUSEBREAK",20:"CAPSLOCK",27:"ESC",32:"SPACE",33:"PAGE_UP",34:"PAGE_DOWN",35:"END",36:"HOME",37:"LEFT",38:"UP",39:"RIGHT",40:"DOWN",43:"+",44:"PRINTSCREEN",45:"INSERT",46:"DELETE",48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",59:";",61:"=",65:"A",66:"B",67:"C",68:"D",69:"E",70:"F",71:"G",72:"H",73:"I",74:"J",75:"K",76:"L",77:"M",78:"N",79:"O",80:"P",81:"Q",82:"R",83:"S",84:"T",85:"U",86:"V",87:"W",88:"X",89:"Y",90:"Z",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9",106:"*",107:"+",109:"-",110:".",111:"/",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NUMLOCK",145:"SCROLLLOCK",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},isControl:function(t){switch(t.which){case e.COMMAND:case e.SHIFT:case e.CTRL:case e.ALT:return!0}return!!t.metaKey},isFunctionKey:function(e){return(e=e.which?e.which:e)>=112&&e<=123},isVerticalMovement:function(t){return~[e.UP,e.DOWN].indexOf(t)},isHorizontalMovement:function(t){return~[e.LEFT,e.RIGHT,e.BACKSPACE,e.DELETE].indexOf(t)}};void 0===angular.element.prototype.querySelectorAll&&(angular.element.prototype.querySelectorAll=function(e){return angular.element(this[0].querySelectorAll(e))}),void 0===angular.element.prototype.closest&&(angular.element.prototype.closest=function(e){for(var t=this[0],n=t.matches||t.webkitMatchesSelector||t.mozMatchesSelector||t.msMatchesSelector;t;){if(n.bind(t)(e))return t;t=t.parentElement}return!1});var t=0,n=angular.module("ui.select",[]).constant("uiSelectConfig",{theme:"bootstrap",searchEnabled:!0,sortable:!1,placeholder:"",refreshDelay:1e3,closeOnSelect:!0,generateId:function(){return t++},appendToBody:!1}).service("uiSelectMinErr",function(){var e=angular.$$minErr("ui.select");return function(){var t=e.apply(this,arguments),n=t.message.replace(new RegExp("\nhttp://errors.angularjs.org/.*"),"");return new Error(n)}}).directive("uisTranscludeAppend",function(){return{link:function(e,t,n,i,r){r(e,function(e){t.append(e)})}}}).filter("highlight",function(){function e(e){return e.replace(/([.?*+^$[\]\\(){}|-])/g,"\\$1")}return function(t,n){return n&&t?t.replace(new RegExp(e(n),"gi"),'<span class="ui-select-highlight">$&</span>'):t}}).factory("uisOffset",["$document","$window",function(e,t){return function(n){var i=n[0].getBoundingClientRect();return{width:i.width||n.prop("offsetWidth"),height:i.height||n.prop("offsetHeight"),top:i.top+(t.pageYOffset||e[0].documentElement.scrollTop),left:i.left+(t.pageXOffset||e[0].documentElement.scrollLeft)}}}]);n.directive("uiSelectChoices",["uiSelectConfig","uisRepeatParser","uiSelectMinErr","$compile",function(e,t,n,i){return{restrict:"EA",require:"^uiSelect",replace:!0,transclude:!0,templateUrl:function(t){return(t.parent().attr("theme")||e.theme)+"/choices.tpl.html"},compile:function(r,o){if(!o.repeat)throw n("repeat","Expected 'repeat' expression.");return function(r,o,a,s,l){var c=a.groupBy,u=a.groupFilter;if(s.parseRepeatAttr(a.repeat,c,u),s.disableChoiceExpression=a.uiDisableChoice,s.onHighlightCallback=a.onHighlight,c){var d=o.querySelectorAll(".ui-select-choices-group");if(1!==d.length)throw n("rows","Expected 1 .ui-select-choices-group but got '{0}'.",d.length);d.attr("ng-repeat",t.getGroupNgRepeatExpression())}var f=o.querySelectorAll(".ui-select-choices-row");if(1!==f.length)throw n("rows","Expected 1 .ui-select-choices-row but got '{0}'.",f.length);f.attr("ng-repeat",t.getNgRepeatExpression(s.parserResult.itemName,"$select.items",s.parserResult.trackByExp,c)).attr("ng-if","$select.open").attr("ng-mouseenter","$select.setActiveItem("+s.parserResult.itemName+")").attr("ng-click","$select.select("+s.parserResult.itemName+",false,$event)");var p=o.querySelectorAll(".ui-select-choices-row-inner");if(1!==p.length)throw n("rows","Expected 1 .ui-select-choices-row-inner but got '{0}'.",p.length);p.attr("uis-transclude-append",""),i(o,l)(r),r.$watch("$select.search",function(e){e&&!s.open&&s.multiple&&s.activate(!1,!0),s.activeIndex=s.tagging.isActivated?-1:0,s.refresh(a.refresh)}),a.$observe("refreshDelay",function(){var t=r.$eval(a.refreshDelay);s.refreshDelay=void 0!==t?t:e.refreshDelay})}}}}]),n.controller("uiSelectCtrl",["$scope","$element","$timeout","$filter","uisRepeatParser","uiSelectMinErr","uiSelectConfig",function(t,n,i,r,o,a,s){function l(){(f.resetSearchInput||void 0===f.resetSearchInput&&s.resetSearchInput)&&(f.search=p,f.selected&&f.items.length&&!f.multiple&&(f.activeIndex=f.items.indexOf(f.selected)))}function c(e,t){var n,i,r=[];for(n=0;n<t.length;n++)for(i=0;i<e.length;i++)e[i].name==[t[n]]&&r.push(e[i]);return r}function u(t){var n=!0;switch(t){case e.DOWN:!f.open&&f.multiple?f.activate(!1,!0):f.activeIndex<f.items.length-1&&f.activeIndex++;break;case e.UP:!f.open&&f.multiple?f.activate(!1,!0):(f.activeIndex>0||0===f.search.length&&f.tagging.isActivated&&f.activeIndex>-1)&&f.activeIndex--;break;case e.TAB:f.multiple&&!f.open||f.select(f.items[f.activeIndex],!0);break;case e.ENTER:f.open&&(f.tagging.isActivated||f.activeIndex>=0)?f.select(f.items[f.activeIndex]):f.activate(!1,!0);break;case e.ESC:f.close();break;default:n=!1}return n}function d(){var e=n.querySelectorAll(".ui-select-choices-content"),t=e.querySelectorAll(".ui-select-choices-row");if(t.length<1)throw a("choices","Expected multiple .ui-select-choices-row but got '{0}'.",t.length);if(!(f.activeIndex<0)){var i=t[f.activeIndex],r=i.offsetTop+i.clientHeight-e[0].scrollTop,o=e[0].offsetHeight;r>o?e[0].scrollTop+=r-o:r<i.clientHeight&&(f.isGrouped&&0===f.activeIndex?e[0].scrollTop=0:e[0].scrollTop-=i.clientHeight-r)}}var f=this,p="";if(f.placeholder=s.placeholder,f.searchEnabled=s.searchEnabled,f.sortable=s.sortable,f.refreshDelay=s.refreshDelay,f.removeSelected=!1,f.closeOnSelect=!0,f.search=p,f.activeIndex=0,f.items=[],f.open=!1,f.focus=!1,f.disabled=!1,f.selected=void 0,f.focusser=void 0,f.resetSearchInput=!0,f.multiple=void 0,f.disableChoiceExpression=void 0,f.tagging={isActivated:!1,fct:void 0},f.taggingTokens={isActivated:!1,tokens:void 0},f.lockChoiceExpression=void 0,f.clickTriggeredSelect=!1,f.$filter=r,f.searchInput=n.querySelectorAll("input.ui-select-search"),1!==f.searchInput.length)throw a("searchInput","Expected 1 input.ui-select-search but got '{0}'.",f.searchInput.length);f.isEmpty=function(){return angular.isUndefined(f.selected)||null===f.selected||""===f.selected},f.activate=function(e,n){f.disabled||f.open||(n||l(),t.$broadcast("uis:activate"),f.open=!0,f.activeIndex=f.activeIndex>=f.items.length?0:f.activeIndex,-1===f.activeIndex&&!1!==f.taggingLabel&&(f.activeIndex=0),i(function(){f.search=e||f.search,f.searchInput[0].focus()}))},f.findGroupByName=function(e){return f.groups&&f.groups.filter(function(t){return t.name===e})[0]},f.parseRepeatAttr=function(e,n,i){function r(e){var r=t.$eval(n);if(f.groups=[],angular.forEach(e,function(e){var t=angular.isFunction(r)?r(e):e[r],n=f.findGroupByName(t);n?n.items.push(e):f.groups.push({name:t,items:[e]})}),i){var o=t.$eval(i);angular.isFunction(o)?f.groups=o(f.groups):angular.isArray(o)&&(f.groups=c(f.groups,o))}f.items=[],f.groups.forEach(function(e){f.items=f.items.concat(e.items)})}function s(e){f.items=e}f.setItemsFn=n?r:s,f.parserResult=o.parse(e),f.isGrouped=!!n,f.itemProperty=f.parserResult.itemName,f.refreshItems=function(e){e=e||f.parserResult.source(t);var n=f.selected;if(angular.isArray(n)&&!n.length||!f.removeSelected)f.setItemsFn(e);else if(void 0!==e){var i=e.filter(function(e){return n.indexOf(e)<0});f.setItemsFn(i)}},t.$watchCollection(f.parserResult.source,function(e){if(void 0===e||null===e)f.items=[];else{if(!angular.isArray(e))throw a("items","Expected an array but got '{0}'.",e);f.refreshItems(e),f.ngModel.$modelValue=null}})};var h;f.refresh=function(e){void 0!==e&&(h&&i.cancel(h),h=i(function(){t.$eval(e)},f.refreshDelay))},f.setActiveItem=function(e){f.activeIndex=f.items.indexOf(e)},f.isActive=function(e){if(!f.open)return!1;var t=f.items.indexOf(e[f.itemProperty]),n=t===f.activeIndex;return!(!n||t<0&&!1!==f.taggingLabel||t<0&&!1===f.taggingLabel)&&(n&&!angular.isUndefined(f.onHighlightCallback)&&e.$eval(f.onHighlightCallback),n)},f.isDisabled=function(e){if(f.open){var t,n=f.items.indexOf(e[f.itemProperty]),i=!1;return n>=0&&!angular.isUndefined(f.disableChoiceExpression)&&(t=f.items[n],i=!!e.$eval(f.disableChoiceExpression),t._uiSelectChoiceDisabled=i),i}},f.select=function(e,n,r){if(void 0===e||!e._uiSelectChoiceDisabled){if(!f.items&&!f.search)return;if(!e||!e._uiSelectChoiceDisabled){if(f.tagging.isActivated){if(!1===f.taggingLabel)if(f.activeIndex<0){if(!(e=void 0!==f.tagging.fct?f.tagging.fct(f.search):f.search)||angular.equals(f.items[0],e))return}else e=f.items[f.activeIndex];else if(0===f.activeIndex){if(void 0===e)return;if(void 0!==f.tagging.fct&&"string"==typeof e){if(!(e=f.tagging.fct(f.search)))return}else"string"==typeof e&&(e=e.replace(f.taggingLabel,"").trim())}if(f.selected&&angular.isArray(f.selected)&&f.selected.filter(function(t){return angular.equals(t,e)}).length>0)return void f.close(n)}t.$broadcast("uis:select",e);var o={};o[f.parserResult.itemName]=e,i(function(){f.onSelectCallback(t,{$item:e,$model:f.parserResult.modelMapper(t,o)})}),f.closeOnSelect&&f.close(n),r&&"click"===r.type&&(f.clickTriggeredSelect=!0)}}},f.close=function(e){f.open&&(f.ngModel&&f.ngModel.$setTouched&&f.ngModel.$setTouched(),l(),f.open=!1,t.$broadcast("uis:close",e))},f.setFocus=function(){f.focus||f.focusInput[0].focus()},f.clear=function(e){f.select(void 0),e.stopPropagation(),i(function(){f.focusser[0].focus()},0,!1)},f.toggle=function(e){f.open?(f.close(),e.preventDefault(),e.stopPropagation()):f.activate()},f.isLocked=function(e,t){var n,i=f.selected[t];return i&&!angular.isUndefined(f.lockChoiceExpression)&&(n=!!e.$eval(f.lockChoiceExpression),i._uiSelectChoiceLocked=n),n};var g=null;f.sizeSearchInput=function(){var e=f.searchInput[0],n=f.searchInput.parent().parent()[0],r=function(){return n.clientWidth*!!e.offsetParent},o=function(t){if(0===t)return!1;var n=t-e.offsetLeft-10;return n<50&&(n=t),f.searchInput.css("width",n+"px"),!0};f.searchInput.css("width","10px"),i(function(){null!==g||o(r())||(g=t.$watch(r,function(e){o(e)&&(g(),g=null)}))})},f.searchInput.on("keydown",function(n){var r=n.which;t.$apply(function(){var t=!1;if((f.items.length>0||f.tagging.isActivated)&&(u(r),f.taggingTokens.isActivated)){for(var o=0;o<f.taggingTokens.tokens.length;o++)f.taggingTokens.tokens[o]===e.MAP[n.keyCode]&&f.search.length>0&&(t=!0);t&&i(function(){f.searchInput.triggerHandler("tagged");var t=f.search.replace(e.MAP[n.keyCode],"").trim();f.tagging.fct&&(t=f.tagging.fct(t)),t&&f.select(t,!0)})}}),e.isVerticalMovement(r)&&f.items.length>0&&d(),r!==e.ENTER&&r!==e.ESC||(n.preventDefault(),n.stopPropagation())}),f.searchInput.on("paste",function(e){var t=e.originalEvent.clipboardData.getData("text/plain");if(t&&t.length>0&&f.taggingTokens.isActivated&&f.tagging.fct){var n=t.split(f.taggingTokens.tokens[0]);n&&n.length>0&&(angular.forEach(n,function(e){var t=f.tagging.fct(e);t&&f.select(t,!0)}),e.preventDefault(),e.stopPropagation())}}),f.searchInput.on("tagged",function(){i(function(){l()})}),t.$on("$destroy",function(){f.searchInput.off("keyup keydown tagged blur paste")})}]),n.directive("uiSelect",["$document","uiSelectConfig","uiSelectMinErr","uisOffset","$compile","$parse","$timeout",function(e,t,n,i,r,o,a){return{restrict:"EA",templateUrl:function(e,n){return(n.theme||t.theme)+(angular.isDefined(n.multiple)?"/select-multiple.tpl.html":"/select.tpl.html")},replace:!0,transclude:!0,require:["uiSelect","^ngModel"],scope:!0,controller:"uiSelectCtrl",controllerAs:"$select",compile:function(r,s){return angular.isDefined(s.multiple)?r.append("<ui-select-multiple/>").removeAttr("multiple"):r.append("<ui-select-single/>"),function(r,s,l,c,u){function d(e){if(h.open){if(!(window.jQuery?window.jQuery.contains(s[0],e.target):s[0].contains(e.target))&&!h.clickTriggeredSelect){var t=["input","button","textarea"],n=angular.element(e.target).scope(),i=n&&n.$select&&n.$select!==h;i||(i=~t.indexOf(e.target.tagName.toLowerCase())),h.close(i),r.$digest()}h.clickTriggeredSelect=!1}}function f(){var t=i(s);v=angular.element('<div class="ui-select-placeholder"></div>'),v[0].style.width=t.width+"px",v[0].style.height=t.height+"px",s.after(v),$=s[0].style.width,e.find("body").append(s),s[0].style.position="absolute",s[0].style.left=t.left+"px",s[0].style.top=t.top+"px",s[0].style.width=t.width+"px"}function p(){null!==v&&(v.replaceWith(s),v=null,s[0].style.position="",s[0].style.left="",s[0].style.top="",s[0].style.width=$)}var h=c[0],g=c[1];h.generatedId=t.generateId(),h.baseTitle=l.title||"Select box",h.focusserTitle=h.baseTitle+" focus",h.focusserId="focusser-"+h.generatedId,h.closeOnSelect=function(){return angular.isDefined(l.closeOnSelect)?o(l.closeOnSelect)():t.closeOnSelect}(),h.onSelectCallback=o(l.onSelect),h.onRemoveCallback=o(l.onRemove),h.ngModel=g,h.choiceGrouped=function(e){return h.isGrouped&&e&&e.name},l.tabindex&&l.$observe("tabindex",function(e){h.focusInput.attr("tabindex",e),s.removeAttr("tabindex")}),r.$watch("searchEnabled",function(){var e=r.$eval(l.searchEnabled);h.searchEnabled=void 0!==e?e:t.searchEnabled}),r.$watch("sortable",function(){var e=r.$eval(l.sortable);h.sortable=void 0!==e?e:t.sortable}),l.$observe("disabled",function(){h.disabled=void 0!==l.disabled&&l.disabled}),l.$observe("resetSearchInput",function(){var e=r.$eval(l.resetSearchInput);h.resetSearchInput=void 0===e||e}),l.$observe("tagging",function(){if(void 0!==l.tagging){var e=r.$eval(l.tagging);h.tagging={isActivated:!0,fct:!0!==e?e:void 0}}else h.tagging={isActivated:!1,fct:void 0}}),l.$observe("taggingLabel",function(){void 0!==l.tagging&&("false"===l.taggingLabel?h.taggingLabel=!1:h.taggingLabel=void 0!==l.taggingLabel?l.taggingLabel:"(new)")}),l.$observe("taggingTokens",function(){if(void 0!==l.tagging){var e=void 0!==l.taggingTokens?l.taggingTokens.split("|"):[",","ENTER"];h.taggingTokens={isActivated:!0,tokens:e}}}),angular.isDefined(l.autofocus)&&a(function(){h.setFocus()}),angular.isDefined(l.focusOn)&&r.$on(l.focusOn,function(){a(function(){h.setFocus()})}),e.on("click",d),r.$on("$destroy",function(){e.off("click",d)}),u(r,function(e){var t=angular.element("<div>").append(e),i=t.querySelectorAll(".ui-select-match");if(i.removeAttr("ui-select-match"),i.removeAttr("data-ui-select-match"),1!==i.length)throw n("transcluded","Expected 1 .ui-select-match but got '{0}'.",i.length);s.querySelectorAll(".ui-select-match").replaceWith(i);var r=t.querySelectorAll(".ui-select-choices");if(r.removeAttr("ui-select-choices"),r.removeAttr("data-ui-select-choices"),1!==r.length)throw n("transcluded","Expected 1 .ui-select-choices but got '{0}'.",r.length);s.querySelectorAll(".ui-select-choices").replaceWith(r)});var m=r.$eval(l.appendToBody);(void 0!==m?m:t.appendToBody)&&(r.$watch("$select.open",function(e){e?f():p()}),r.$on("$destroy",function(){p()}));var v=null,$="",y=null;r.$watch("$select.open",function(t){if(t){if(null===(y=angular.element(s).querySelectorAll(".ui-select-dropdown")))return;y[0].style.opacity=0,a(function(){var t=i(s),n=i(y);t.top+t.height+n.height>e[0].documentElement.scrollTop+e[0].documentElement.clientHeight&&(y[0].style.position="absolute",y[0].style.top=-1*n.height+"px",s.addClass("direction-up")),y[0].style.opacity=1})}else{if(null===y)return;y[0].style.position="",y[0].style.top="",s.removeClass("direction-up")}})}}}}]),n.directive("uiSelectMatch",["uiSelectConfig",function(e){return{restrict:"EA",require:"^uiSelect",replace:!0,transclude:!0,templateUrl:function(t){return(t.parent().attr("theme")||e.theme)+(t.parent().attr("multiple")?"/match-multiple.tpl.html":"/match.tpl.html")},link:function(t,n,i,r){function o(e){r.allowClear=!!angular.isDefined(e)&&(""===e||"true"===e.toLowerCase())}r.lockChoiceExpression=i.uiLockChoice,i.$observe("placeholder",function(t){r.placeholder=void 0!==t?t:e.placeholder}),i.$observe("allowClear",o),o(i.allowClear),r.multiple&&r.sizeSearchInput()}}}]),n.directive("uiSelectMultiple",["uiSelectMinErr","$timeout",function(t,n){return{restrict:"EA",require:["^uiSelect","^ngModel"],controller:["$scope","$timeout",function(e,t){var n,i=this,r=e.$select;e.$evalAsync(function(){n=e.ngModel}),i.activeMatchIndex=-1,i.updateModel=function(){n.$setViewValue(Date.now()),i.refreshComponent()},i.refreshComponent=function(){r.refreshItems(),r.sizeSearchInput()},i.removeChoice=function(n){var o=r.selected[n];if(!o._uiSelectChoiceLocked){var a={};a[r.parserResult.itemName]=o,r.selected.splice(n,1),i.activeMatchIndex=-1,r.sizeSearchInput(),t(function(){r.onRemoveCallback(e,{$item:o,$model:r.parserResult.modelMapper(e,a)})}),i.updateModel()}},i.getPlaceholder=function(){if(!r.selected.length)return r.placeholder}}],controllerAs:"$selectMultiple",link:function(i,r,o,a){function s(e){return angular.isNumber(e.selectionStart)?e.selectionStart:e.value.length}function l(t){var n=s(d.searchInput[0]),i=d.selected.length,r=i-1,o=p.activeMatchIndex,a=p.activeMatchIndex+1,l=p.activeMatchIndex-1,c=o;return!(n>0||d.search.length&&t==e.RIGHT)&&(d.close(),c=function(){switch(t){case e.LEFT:return~p.activeMatchIndex?l:r;case e.RIGHT:return~p.activeMatchIndex&&o!==r?a:(d.activate(),!1);case e.BACKSPACE:return~p.activeMatchIndex?(p.removeChoice(o),l):r;case e.DELETE:return!!~p.activeMatchIndex&&(p.removeChoice(p.activeMatchIndex),o)}}(),d.selected.length&&!1!==c?p.activeMatchIndex=Math.min(r,Math.max(0,c)):p.activeMatchIndex=-1,!0)}function c(e){return void 0!==e&&void 0!==d.search&&e.filter(function(e){return void 0!==d.search.toUpperCase()&&void 0!==e&&e.toUpperCase()===d.search.toUpperCase()}).length>0}function u(e,t){var n=-1;if(angular.isArray(e))for(var i=angular.copy(e),r=0;r<i.length;r++)if(void 0===d.tagging.fct)i[r]+" "+d.taggingLabel===t&&(n=r);else{var o=i[r];o.isTag=!0,angular.equals(o,t)&&(n=r)}return n}var d=a[0],f=i.ngModel=a[1],p=i.$selectMultiple;d.multiple=!0,d.removeSelected=!0,d.focusInput=d.searchInput,f.$parsers.unshift(function(){for(var e,t={},n=[],r=d.selected.length-1;r>=0;r--)t={},t[d.parserResult.itemName]=d.selected[r],e=d.parserResult.modelMapper(i,t),n.unshift(e);return n}),f.$formatters.unshift(function(e){var t,n=d.parserResult.source(i,{$select:{search:""}}),r={};if(!n)return e;var o=[],a=function(e,n){if(e&&e.length){for(var a=e.length-1;a>=0;a--){if(r[d.parserResult.itemName]=e[a],t=d.parserResult.modelMapper(i,r),d.parserResult.trackByExp){var s=/\.(.+)/.exec(d.parserResult.trackByExp);if(s.length>0&&t[s[1]]==n[s[1]])return o.unshift(e[a]),!0}if(angular.equals(t,n))return o.unshift(e[a]),!0}return!1}};if(!e)return o;for(var s=e.length-1;s>=0;s--)a(d.selected,e[s])||a(n,e[s])||o.unshift(e[s]);return o}),i.$watchCollection(function(){return f.$modelValue},function(e,t){t!=e&&(f.$modelValue=null,p.refreshComponent())}),f.$render=function(){if(!angular.isArray(f.$viewValue)){if(!angular.isUndefined(f.$viewValue)&&null!==f.$viewValue)throw t("multiarr","Expected model value to be array but got '{0}'",f.$viewValue);d.selected=[]}d.selected=f.$viewValue,i.$evalAsync()},i.$on("uis:select",function(e,t){d.selected.push(t),p.updateModel()}),i.$on("uis:activate",function(){p.activeMatchIndex=-1}),i.$watch("$select.disabled",function(e,t){t&&!e&&d.sizeSearchInput()}),d.searchInput.on("keydown",function(t){var n=t.which;i.$apply(function(){var i=!1;e.isHorizontalMovement(n)&&(i=l(n)),i&&n!=e.TAB&&(t.preventDefault(),t.stopPropagation())})}),d.searchInput.on("keyup",function(t){if(e.isVerticalMovement(t.which)||i.$evalAsync(function(){d.activeIndex=!1===d.taggingLabel?-1:0}),d.tagging.isActivated&&d.search.length>0){if(t.which===e.TAB||e.isControl(t)||e.isFunctionKey(t)||t.which===e.ESC||e.isVerticalMovement(t.which))return;if(d.activeIndex=!1===d.taggingLabel?-1:0,!1===d.taggingLabel)return;var n,r,o,a,s=angular.copy(d.items),l=angular.copy(d.items),f=!1,p=-1;if(void 0!==d.tagging.fct){if(o=d.$filter("filter")(s,{isTag:!0}),o.length>0&&(a=o[0]),s.length>0&&a&&(f=!0,s=s.slice(1,s.length),l=l.slice(1,l.length)),n=d.tagging.fct(d.search),n.isTag=!0,l.filter(function(e){return angular.equals(e,d.tagging.fct(d.search))}).length>0)return;n.isTag=!0}else{if(o=d.$filter("filter")(s,function(e){return e.match(d.taggingLabel)}),o.length>0&&(a=o[0]),r=s[0],void 0!==r&&s.length>0&&a&&(f=!0,s=s.slice(1,s.length),l=l.slice(1,l.length)),n=d.search+" "+d.taggingLabel,u(d.selected,d.search)>-1)return;if(c(l.concat(d.selected)))return void(f&&(s=l,i.$evalAsync(function(){d.activeIndex=0,d.items=s})))
+;if(c(l))return void(f&&(d.items=l.slice(1,l.length)))}f&&(p=u(d.selected,n)),p>-1?s=s.slice(p+1,s.length-1):(s=[],s.push(n),s=s.concat(l)),i.$evalAsync(function(){d.activeIndex=0,d.items=s})}}),d.searchInput.on("blur",function(){n(function(){p.activeMatchIndex=-1})})}}}]),n.directive("uiSelectSingle",["$timeout","$compile",function(t,n){return{restrict:"EA",require:["^uiSelect","^ngModel"],link:function(i,r,o,a){var s=a[0],l=a[1];l.$parsers.unshift(function(e){var t={};return t[s.parserResult.itemName]=e,s.parserResult.modelMapper(i,t)}),l.$formatters.unshift(function(e){var t,n=s.parserResult.source(i,{$select:{search:""}}),r={};if(n){var o=function(n){return r[s.parserResult.itemName]=n,(t=s.parserResult.modelMapper(i,r))==e};if(s.selected&&o(s.selected))return s.selected;for(var a=n.length-1;a>=0;a--)if(o(n[a]))return n[a]}return e}),i.$watch("$select.selected",function(e){l.$viewValue!==e&&l.$setViewValue(e)}),l.$render=function(){s.selected=l.$viewValue},i.$on("uis:select",function(e,t){s.selected=t}),i.$on("uis:close",function(e,n){t(function(){s.focusser.prop("disabled",!1),n||s.focusser[0].focus()},0,!1)}),i.$on("uis:activate",function(){c.prop("disabled",!0)});var c=angular.element("<input ng-disabled='$select.disabled' class='ui-select-focusser ui-select-offscreen' type='text' id='{{ $select.focusserId }}' aria-label='{{ $select.focusserTitle }}' aria-haspopup='true' role='button' />");n(c)(i),s.focusser=c,s.focusInput=c,r.parent().append(c),c.bind("focus",function(){i.$evalAsync(function(){s.focus=!0})}),c.bind("blur",function(){i.$evalAsync(function(){s.focus=!1})}),c.bind("keydown",function(t){if(t.which===e.BACKSPACE)return t.preventDefault(),t.stopPropagation(),s.select(void 0),void i.$apply();t.which===e.TAB||e.isControl(t)||e.isFunctionKey(t)||t.which===e.ESC||(t.which!=e.DOWN&&t.which!=e.UP&&t.which!=e.ENTER&&t.which!=e.SPACE||(t.preventDefault(),t.stopPropagation(),s.activate()),i.$digest())}),c.bind("keyup input",function(t){t.which===e.TAB||e.isControl(t)||e.isFunctionKey(t)||t.which===e.ESC||t.which==e.ENTER||t.which===e.BACKSPACE||(s.activate(c.val()),c.val(""),i.$digest())})}}}]),n.directive("uiSelectSort",["$timeout","uiSelectConfig","uiSelectMinErr",function(e,t,n){return{require:"^uiSelect",link:function(t,i,r,o){if(null===t[r.uiSelectSort])throw n("sort","Expected a list to sort");var a=angular.extend({axis:"horizontal"},t.$eval(r.uiSelectSortOptions)),s=a.axis;t.$watch(function(){return o.sortable},function(e){e?i.attr("draggable",!0):i.removeAttr("draggable")}),i.on("dragstart",function(e){i.addClass("dragging"),(e.dataTransfer||e.originalEvent.dataTransfer).setData("text/plain",t.$index)}),i.on("dragend",function(){i.removeClass("dragging")});var l,c=function(e,t){this.splice(t,0,this.splice(e,1)[0])},u=function(e){e.preventDefault(),("vertical"===s?e.offsetY||e.layerY||(e.originalEvent?e.originalEvent.offsetY:0):e.offsetX||e.layerX||(e.originalEvent?e.originalEvent.offsetX:0))<this["vertical"===s?"offsetHeight":"offsetWidth"]/2?(i.removeClass("dropping-after"),i.addClass("dropping-before")):(i.removeClass("dropping-before"),i.addClass("dropping-after"))},d=function(t){t.preventDefault();var n=parseInt((t.dataTransfer||t.originalEvent.dataTransfer).getData("text/plain"),10);e.cancel(l),l=e(function(){f(n)},20)},f=function(e){var n=t.$eval(r.uiSelectSort),o=n[e],a=null;a=i.hasClass("dropping-before")?e<t.$index?t.$index-1:t.$index:e<t.$index?t.$index:t.$index+1,c.apply(n,[e,a]),t.$apply(function(){t.$emit("uiSelectSort:change",{array:n,item:o,from:e,to:a})}),i.removeClass("dropping"),i.removeClass("dropping-before"),i.removeClass("dropping-after"),i.off("drop",d)};i.on("dragenter",function(){i.hasClass("dragging")||(i.addClass("dropping"),i.on("dragover",u),i.on("drop",d))}),i.on("dragleave",function(e){e.target==i&&(i.removeClass("dropping"),i.removeClass("dropping-before"),i.removeClass("dropping-after"),i.off("dragover",u),i.off("drop",d))})}}}]),n.service("uisRepeatParser",["uiSelectMinErr","$parse",function(e,t){var n=this;n.parse=function(n){var i=n.match(/^\s*(?:([\s\S]+?)\s+as\s+)?([\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);if(!i)throw e("iexp","Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",n);return{itemName:i[2],source:t(i[3]),trackByExp:i[4],modelMapper:t(i[1]||i[2])}},n.getGroupNgRepeatExpression=function(){return"$group in $select.groups"},n.getNgRepeatExpression=function(e,t,n,i){var r=e+" in "+(i?"$group.items":t);return n&&(r+=" track by "+n),r}}])}(),angular.module("ui.select").run(["$templateCache",function(e){e.put("bootstrap/choices.tpl.html",'<ul class="ui-select-choices ui-select-choices-content ui-select-dropdown dropdown-menu" role="listbox" ng-show="$select.items.length > 0"><li class="ui-select-choices-group" id="ui-select-choices-{{ $select.generatedId }}"><div class="divider" ng-show="$select.isGrouped && $index > 0"></div><div ng-show="$select.isGrouped" class="ui-select-choices-group-label dropdown-header" ng-bind="$group.name"></div><div id="ui-select-choices-row-{{ $select.generatedId }}-{{$index}}" class="ui-select-choices-row" ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" role="option"><a href="javascript:void(0)" class="ui-select-choices-row-inner"></a></div></li></ul>'),e.put("bootstrap/match-multiple.tpl.html",'<span class="ui-select-match"><span ng-repeat="$item in $select.selected"><span class="ui-select-match-item btn btn-default btn-xs" tabindex="-1" type="button" ng-disabled="$select.disabled" ng-click="$selectMultiple.activeMatchIndex = $index;" ng-class="{\'btn-primary\':$selectMultiple.activeMatchIndex === $index, \'select-locked\':$select.isLocked(this, $index)}" ui-select-sort="$select.selected"><span class="close ui-select-match-close" ng-hide="$select.disabled" ng-click="$selectMultiple.removeChoice($index)">&nbsp;&times;</span> <span uis-transclude-append=""></span></span></span></span>'),e.put("bootstrap/match.tpl.html",'<div class="ui-select-match" ng-hide="$select.open" ng-disabled="$select.disabled" ng-class="{\'btn-default-focus\':$select.focus}"><span tabindex="-1" class="btn btn-default form-control ui-select-toggle" aria-label="{{ $select.baseTitle }} activate" ng-disabled="$select.disabled" ng-click="$select.activate()" style="outline: 0;"><span ng-show="$select.isEmpty()" class="ui-select-placeholder text-muted">{{$select.placeholder}}</span> <span ng-hide="$select.isEmpty()" class="ui-select-match-text pull-left" ng-class="{\'ui-select-allow-clear\': $select.allowClear && !$select.isEmpty()}" ng-transclude=""></span> <i class="caret pull-right" ng-click="$select.toggle($event)"></i> <a ng-show="$select.allowClear && !$select.isEmpty()" aria-label="{{ $select.baseTitle }} clear" style="margin-right: 10px" ng-click="$select.clear($event)" class="btn btn-xs btn-link pull-right"><i class="glyphicon glyphicon-remove" aria-hidden="true"></i></a></span></div>'),e.put("bootstrap/select-multiple.tpl.html",'<div class="ui-select-container ui-select-multiple ui-select-bootstrap dropdown form-control" ng-class="{open: $select.open}"><div><div class="ui-select-match"></div><input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="ui-select-search input-xs" placeholder="{{$selectMultiple.getPlaceholder()}}" ng-disabled="$select.disabled" ng-hide="$select.disabled" ng-click="$select.activate()" ng-model="$select.search" role="combobox" aria-label="{{ $select.baseTitle }}" ondrop="return false;"></div><div class="ui-select-choices"></div></div>'),e.put("bootstrap/select.tpl.html",'<div class="ui-select-container ui-select-bootstrap dropdown" ng-class="{open: $select.open}"><div class="ui-select-match"></div><input type="text" autocomplete="off" tabindex="-1" aria-expanded="true" aria-label="{{ $select.baseTitle }}" aria-owns="ui-select-choices-{{ $select.generatedId }}" aria-activedescendant="ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}" class="form-control ui-select-search" placeholder="{{$select.placeholder}}" ng-model="$select.search" ng-show="$select.searchEnabled && $select.open"><div class="ui-select-choices"></div></div>'),e.put("select2/choices.tpl.html",'<ul class="ui-select-choices ui-select-choices-content select2-results"><li class="ui-select-choices-group" ng-class="{\'select2-result-with-children\': $select.choiceGrouped($group) }"><div ng-show="$select.choiceGrouped($group)" class="ui-select-choices-group-label select2-result-label" ng-bind="$group.name"></div><ul role="listbox" id="ui-select-choices-{{ $select.generatedId }}" ng-class="{\'select2-result-sub\': $select.choiceGrouped($group), \'select2-result-single\': !$select.choiceGrouped($group) }"><li role="option" id="ui-select-choices-row-{{ $select.generatedId }}-{{$index}}" class="ui-select-choices-row" ng-class="{\'select2-highlighted\': $select.isActive(this), \'select2-disabled\': $select.isDisabled(this)}"><div class="select2-result-label ui-select-choices-row-inner"></div></li></ul></li></ul>'),e.put("select2/match-multiple.tpl.html",'<span class="ui-select-match"><li class="ui-select-match-item select2-search-choice" ng-repeat="$item in $select.selected" ng-class="{\'select2-search-choice-focus\':$selectMultiple.activeMatchIndex === $index, \'select2-locked\':$select.isLocked(this, $index)}" ui-select-sort="$select.selected"><span uis-transclude-append=""></span> <a href="javascript:;" class="ui-select-match-close select2-search-choice-close" ng-click="$selectMultiple.removeChoice($index)" tabindex="-1"></a></li></span>'),e.put("select2/match.tpl.html",'<a class="select2-choice ui-select-match" ng-class="{\'select2-default\': $select.isEmpty()}" ng-click="$select.toggle($event)" aria-label="{{ $select.baseTitle }} select"><span ng-show="$select.isEmpty()" class="select2-chosen">{{$select.placeholder}}</span> <span ng-hide="$select.isEmpty()" class="select2-chosen" ng-transclude=""></span> <abbr ng-if="$select.allowClear && !$select.isEmpty()" class="select2-search-choice-close" ng-click="$select.clear($event)"></abbr> <span class="select2-arrow ui-select-toggle"><b></b></span></a>'),e.put("select2/select-multiple.tpl.html",'<div class="ui-select-container ui-select-multiple select2 select2-container select2-container-multi" ng-class="{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled}"><ul class="select2-choices"><span class="ui-select-match"></span><li class="select2-search-field"><input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" role="combobox" aria-expanded="true" aria-owns="ui-select-choices-{{ $select.generatedId }}" aria-label="{{ $select.baseTitle }}" aria-activedescendant="ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}" class="select2-input ui-select-search" placeholder="{{$selectMultiple.getPlaceholder()}}" ng-disabled="$select.disabled" ng-hide="$select.disabled" ng-model="$select.search" ng-click="$select.activate()" style="width: 34px;" ondrop="return false;"></li></ul><div class="ui-select-dropdown select2-drop select2-with-searchbox select2-drop-active" ng-class="{\'select2-display-none\': !$select.open}"><div class="ui-select-choices"></div></div></div>'),e.put("select2/select.tpl.html",'<div class="ui-select-container select2 select2-container" ng-class="{\'select2-container-active select2-dropdown-open open\': $select.open, \'select2-container-disabled\': $select.disabled, \'select2-container-active\': $select.focus, \'select2-allowclear\': $select.allowClear && !$select.isEmpty()}"><div class="ui-select-match"></div><div class="ui-select-dropdown select2-drop select2-with-searchbox select2-drop-active" ng-class="{\'select2-display-none\': !$select.open}"><div class="select2-search" ng-show="$select.searchEnabled"><input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" role="combobox" aria-expanded="true" aria-owns="ui-select-choices-{{ $select.generatedId }}" aria-label="{{ $select.baseTitle }}" aria-activedescendant="ui-select-choices-row-{{ $select.generatedId }}-{{ $select.activeIndex }}" class="ui-select-search select2-input" ng-model="$select.search"></div><div class="ui-select-choices"></div></div></div>'),e.put("selectize/choices.tpl.html",'<div ng-show="$select.open" class="ui-select-choices ui-select-dropdown selectize-dropdown single"><div class="ui-select-choices-content selectize-dropdown-content"><div class="ui-select-choices-group optgroup" role="listbox"><div ng-show="$select.isGrouped" class="ui-select-choices-group-label optgroup-header" ng-bind="$group.name"></div><div role="option" class="ui-select-choices-row" ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}"><div class="option ui-select-choices-row-inner" data-selectable=""></div></div></div></div></div>'),e.put("selectize/match.tpl.html",'<div ng-hide="($select.open || $select.isEmpty())" class="ui-select-match" ng-transclude=""></div>'),e.put("selectize/select.tpl.html",'<div class="ui-select-container selectize-control single" ng-class="{\'open\': $select.open}"><div class="selectize-input" ng-class="{\'focus\': $select.open, \'disabled\': $select.disabled, \'selectize-focus\' : $select.focus}" ng-click="$select.activate()"><div class="ui-select-match"></div><input type="text" autocomplete="off" tabindex="-1" class="ui-select-search ui-select-toggle" ng-click="$select.toggle($event)" placeholder="{{$select.placeholder}}" ng-model="$select.search" ng-hide="!$select.searchEnabled || ($select.selected && !$select.open)" ng-disabled="$select.disabled" aria-label="{{ $select.baseTitle }}"></div><div class="ui-select-choices"></div></div>')}]),require.modules={},require.aliases={},require.resolve=function(e){"/"===e.charAt(0)&&(e=e.slice(1));for(var t=[e,e+".js",e+".json",e+"/index.js",e+"/index.json"],n=0;n<t.length;n++){var e=t[n];if(require.modules.hasOwnProperty(e))return e;if(require.aliases.hasOwnProperty(e))return require.aliases[e]}},require.normalize=function(e,t){var n=[];if("."!=t.charAt(0))return t;e=e.split("/"),t=t.split("/");for(var i=0;i<t.length;++i)".."==t[i]?e.pop():"."!=t[i]&&""!=t[i]&&n.push(t[i]);return e.concat(n).join("/")},require.register=function(e,t){require.modules[e]=t},require.alias=function(e,t){if(!require.modules.hasOwnProperty(e))throw new Error('Failed to alias "'+e+'", it does not exist');require.aliases[t]=e},require.relative=function(e){function t(e,t){for(var n=e.length;n--;)if(e[n]===t)return n;return-1}function n(t){return require(n.resolve(t),e,t)}var i=require.normalize(e,"..");return n.resolve=function(n){var r=n.charAt(0);if("/"==r)return n.slice(1);if("."==r)return require.normalize(i,n);var o=e.split("/"),a=t(o,"deps")+1;return a||(a=0),n=o.slice(0,a+1).join("/")+"/deps/"+n},n.exists=function(e){return require.modules.hasOwnProperty(n.resolve(e))},n},require.register("switchery/switchery.js",function(e,t,n){function i(e,t){if(!(this instanceof i))return new i(t);this.element=e,this.options=t||{};for(var n in r)n in this.options||(this.options[n]=r[n]);"checkbox"==this.element.type&&this.init()}n.exports=i;var r={color:"#64bd63",className:"switchery",disabled:!1,speed:"0.1s"};i.prototype.hide=function(){this.element.style.display="none"},i.prototype.show=function(){var e=this.create();this.element.parentNode.appendChild(e)},i.prototype.create=function(){return this.switcher=document.createElement("span"),this.jack=document.createElement("small"),this.switcher.appendChild(this.jack),this.switcher.className=this.options.className,this.switcher},i.prototype.isChecked=function(){return this.element.checked},i.prototype.isDisabled=function(){return this.options.disabled||this.element.disabled},i.prototype.setPosition=function(e){var t=this.isChecked(),n=this.switcher,i=this.jack;e&&t?t=!1:e&&!t&&(t=!0),!0===t?(this.element.checked=!0,window.getComputedStyle?i.style.left=parseInt(window.getComputedStyle(n).width)-i.offsetWidth+"px":i.style.left=parseInt(n.currentStyle.width)-i.offsetWidth+"px",this.options.color&&this.colorize()):(i.style.left="0",this.element.checked=!1,this.switcher.style.backgroundColor="",this.switcher.style.borderColor="")},i.prototype.setSpeed=function(){this.switcher.style.transitionDuration=this.options.speed,this.jack.style.transitionDuration=this.options.speed},i.prototype.setAttributes=function(){var e=this.element.getAttribute("id"),t=this.element.getAttribute("name");e&&this.switcher.setAttribute("id",e),t&&this.switcher.setAttribute("name",t)},i.prototype.colorize=function(){this.switcher.style.backgroundColor=this.options.color,this.switcher.style.borderColor=this.options.color},i.prototype.handleClick=function(){var e=this,t=this.switcher;!1===this.isDisabled()?t.addEventListener?t.addEventListener("click",function(){e.setPosition(!0)}):t.attachEvent("onclick",function(){e.setPosition(!0)}):this.element.disabled=!0},i.prototype.init=function(){this.hide(),this.show(),this.setSpeed(),this.setPosition(),this.setAttributes(),this.handleClick()}}),require.alias("switchery/switchery.js","switchery/index.js"),!function(){function e(t){var n=e.modules[t];if(!n)throw new Error('failed to require "'+t+'"');return"exports"in n||"function"!=typeof n.definition||(n.client=n.component=!0,n.definition.call(this,n.exports={},n),delete n.definition),n.exports}e.loader="component",e.helper={},e.helper.semVerSort=function(e,t){for(var n=e.version.split("."),i=t.version.split("."),r=0;r<n.length;++r){var o=parseInt(n[r],10),a=parseInt(i[r],10);if(o!==a)return o>a?1:-1;var s=n[r].substr((""+o).length),l=i[r].substr((""+a).length);if(""===s&&""!==l)return 1;if(""!==s&&""===l)return-1;if(""!==s&&""!==l)return s>l?1:-1}return 0},e.latest=function(t,n){function i(e){throw new Error('failed to find latest module of "'+e+'"')}var r=/(.*)~(.*)@v?(\d+\.\d+\.\d+[^\/]*)$/;/(.*)~(.*)/.test(t)||i(t);for(var o=Object.keys(e.modules),a=[],s=[],l=0;l<o.length;l++){var c=o[l];if(new RegExp(t+"@").test(c)){var u=c.substr(t.length+1);null!=r.exec(c)?a.push({version:u,name:c}):s.push({version:u,name:c})}}if(0===a.concat(s).length&&i(t),a.length>0){var d=a.sort(e.helper.semVerSort).pop().name;return!0===n?d:e(d)}var d=s.sort(function(e,t){return e.name>t.name})[0].name;return!0===n?d:e(d)},e.modules={},e.register=function(t,n){e.modules[t]={definition:n}},e.define=function(t,n){e.modules[t]={exports:n}},e.register("abpetkov~transitionize@0.0.3",function(e,t){function n(e,t){return this instanceof n?(this.element=e,this.props=t||{},void this.init()):new n(e,t)}t.exports=n,n.prototype.isSafari=function(){return/Safari/.test(navigator.userAgent)&&/Apple Computer/.test(navigator.vendor)},n.prototype.init=function(){var e=[];for(var t in this.props)e.push(t+" "+this.props[t]);this.element.style.transition=e.join(", "),this.isSafari()&&(this.element.style.webkitTransition=e.join(", "))}}),e.register("ftlabs~fastclick@v0.6.11",function(e,t){function n(e){"use strict";var t,i=this;if(this.trackingClick=!1,this.trackingClickStart=0,this.targetElement=null,this.touchStartX=0,this.touchStartY=0,this.lastTouchIdentifier=0,this.touchBoundary=10,this.layer=e,!e||!e.nodeType)throw new TypeError("Layer must be a document node");this.onClick=function(){return n.prototype.onClick.apply(i,arguments)},this.onMouse=function(){return n.prototype.onMouse.apply(i,arguments)},this.onTouchStart=function(){return n.prototype.onTouchStart.apply(i,arguments)},this.onTouchMove=function(){return n.prototype.onTouchMove.apply(i,arguments)},this.onTouchEnd=function(){return n.prototype.onTouchEnd.apply(i,arguments)},this.onTouchCancel=function(){return n.prototype.onTouchCancel.apply(i,arguments)},n.notNeeded(e)||(this.deviceIsAndroid&&(e.addEventListener("mouseover",this.onMouse,!0),e.addEventListener("mousedown",this.onMouse,!0),e.addEventListener("mouseup",this.onMouse,!0)),e.addEventListener("click",this.onClick,!0),e.addEventListener("touchstart",this.onTouchStart,!1),e.addEventListener("touchmove",this.onTouchMove,!1),e.addEventListener("touchend",this.onTouchEnd,!1),e.addEventListener("touchcancel",this.onTouchCancel,!1),Event.prototype.stopImmediatePropagation||(e.removeEventListener=function(t,n,i){var r=Node.prototype.removeEventListener;"click"===t?r.call(e,t,n.hijacked||n,i):r.call(e,t,n,i)},e.addEventListener=function(t,n,i){var r=Node.prototype.addEventListener;"click"===t?r.call(e,t,n.hijacked||(n.hijacked=function(e){e.propagationStopped||n(e)}),i):r.call(e,t,n,i)}),"function"==typeof e.onclick&&(t=e.onclick,e.addEventListener("click",function(e){t(e)},!1),e.onclick=null))}n.prototype.deviceIsAndroid=navigator.userAgent.indexOf("Android")>0,n.prototype.deviceIsIOS=/iP(ad|hone|od)/.test(navigator.userAgent),n.prototype.deviceIsIOS4=n.prototype.deviceIsIOS&&/OS 4_\d(_\d)?/.test(navigator.userAgent),n.prototype.deviceIsIOSWithBadTarget=n.prototype.deviceIsIOS&&/OS ([6-9]|\d{2})_\d/.test(navigator.userAgent),n.prototype.needsClick=function(e){"use strict";switch(e.nodeName.toLowerCase()){case"button":case"select":case"textarea":if(e.disabled)return!0;break;case"input":if(this.deviceIsIOS&&"file"===e.type||e.disabled)return!0;break;case"label":case"video":return!0}return/\bneedsclick\b/.test(e.className)},n.prototype.needsFocus=function(e){"use strict";switch(e.nodeName.toLowerCase()){case"textarea":return!0;case"select":return!this.deviceIsAndroid;case"input":switch(e.type){case"button":case"checkbox":case"file":case"image":case"radio":case"submit":return!1}return!e.disabled&&!e.readOnly;default:return/\bneedsfocus\b/.test(e.className)}},n.prototype.sendClick=function(e,t){"use strict";var n,i;document.activeElement&&document.activeElement!==e&&document.activeElement.blur(),i=t.changedTouches[0],n=document.createEvent("MouseEvents"),n.initMouseEvent(this.determineEventType(e),!0,!0,window,1,i.screenX,i.screenY,i.clientX,i.clientY,!1,!1,!1,!1,0,null),n.forwardedTouchEvent=!0,e.dispatchEvent(n)},n.prototype.determineEventType=function(e){"use strict";return this.deviceIsAndroid&&"select"===e.tagName.toLowerCase()?"mousedown":"click"},n.prototype.focus=function(e){"use strict";var t;this.deviceIsIOS&&e.setSelectionRange&&0!==e.type.indexOf("date")&&"time"!==e.type?(t=e.value.length,e.setSelectionRange(t,t)):e.focus()},n.prototype.updateScrollParent=function(e){"use strict";var t,n;if(!(t=e.fastClickScrollParent)||!t.contains(e)){n=e;do{if(n.scrollHeight>n.offsetHeight){t=n,e.fastClickScrollParent=n;break}n=n.parentElement}while(n)}t&&(t.fastClickLastScrollTop=t.scrollTop)},n.prototype.getTargetElementFromEventTarget=function(e){"use strict";return e.nodeType===Node.TEXT_NODE?e.parentNode:e},n.prototype.onTouchStart=function(e){"use strict";var t,n,i;if(e.targetTouches.length>1)return!0;if(t=this.getTargetElementFromEventTarget(e.target),n=e.targetTouches[0],this.deviceIsIOS){if(i=window.getSelection(),i.rangeCount&&!i.isCollapsed)return!0;if(!this.deviceIsIOS4){if(n.identifier===this.lastTouchIdentifier)return e.preventDefault(),!1;this.lastTouchIdentifier=n.identifier,this.updateScrollParent(t)}}return this.trackingClick=!0,this.trackingClickStart=e.timeStamp,this.targetElement=t,this.touchStartX=n.pageX,this.touchStartY=n.pageY,e.timeStamp-this.lastClickTime<200&&e.preventDefault(),!0},n.prototype.touchHasMoved=function(e){"use strict";var t=e.changedTouches[0],n=this.touchBoundary;return Math.abs(t.pageX-this.touchStartX)>n||Math.abs(t.pageY-this.touchStartY)>n},n.prototype.onTouchMove=function(e){"use strict";return!this.trackingClick||((this.targetElement!==this.getTargetElementFromEventTarget(e.target)||this.touchHasMoved(e))&&(this.trackingClick=!1,this.targetElement=null),!0)},n.prototype.findControl=function(e){"use strict";return void 0!==e.control?e.control:e.htmlFor?document.getElementById(e.htmlFor):e.querySelector("button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea")},n.prototype.onTouchEnd=function(e){"use strict";var t,n,i,r,o,a=this.targetElement;if(!this.trackingClick)return!0;if(e.timeStamp-this.lastClickTime<200)return this.cancelNextClick=!0,!0;if(this.cancelNextClick=!1,this.lastClickTime=e.timeStamp,n=this.trackingClickStart,this.trackingClick=!1,this.trackingClickStart=0,this.deviceIsIOSWithBadTarget&&(o=e.changedTouches[0],a=document.elementFromPoint(o.pageX-window.pageXOffset,o.pageY-window.pageYOffset)||a,a.fastClickScrollParent=this.targetElement.fastClickScrollParent),"label"===(i=a.tagName.toLowerCase())){if(t=this.findControl(a)){if(this.focus(a),this.deviceIsAndroid)return!1;a=t}}else if(this.needsFocus(a))return e.timeStamp-n>100||this.deviceIsIOS&&window.top!==window&&"input"===i?(this.targetElement=null,!1):(this.focus(a),this.deviceIsIOS4&&"select"===i||(this.targetElement=null,e.preventDefault()),!1);return!(!this.deviceIsIOS||this.deviceIsIOS4||!(r=a.fastClickScrollParent)||r.fastClickLastScrollTop===r.scrollTop)||(this.needsClick(a)||(e.preventDefault(),this.sendClick(a,e)),!1)},n.prototype.onTouchCancel=function(){"use strict";this.trackingClick=!1,this.targetElement=null},n.prototype.onMouse=function(e){"use strict";return!this.targetElement||(!!e.forwardedTouchEvent||(!(e.cancelable&&(!this.needsClick(this.targetElement)||this.cancelNextClick))||(e.stopImmediatePropagation?e.stopImmediatePropagation():e.propagationStopped=!0,e.stopPropagation(),e.preventDefault(),!1)))},n.prototype.onClick=function(e){"use strict";var t;return this.trackingClick?(this.targetElement=null,this.trackingClick=!1,!0):"submit"===e.target.type&&0===e.detail||(t=this.onMouse(e),t||(this.targetElement=null),t)},n.prototype.destroy=function(){"use strict";var e=this.layer;this.deviceIsAndroid&&(e.removeEventListener("mouseover",this.onMouse,!0),e.removeEventListener("mousedown",this.onMouse,!0),e.removeEventListener("mouseup",this.onMouse,!0)),e.removeEventListener("click",this.onClick,!0),e.removeEventListener("touchstart",this.onTouchStart,!1),e.removeEventListener("touchmove",this.onTouchMove,!1),e.removeEventListener("touchend",this.onTouchEnd,!1),e.removeEventListener("touchcancel",this.onTouchCancel,!1)},n.notNeeded=function(e){"use strict";var t,i;if(void 0===window.ontouchstart)return!0;if(i=+(/Chrome\/([0-9]+)/.exec(navigator.userAgent)||[,0])[1]){if(!n.prototype.deviceIsAndroid)return!0;if(t=document.querySelector("meta[name=viewport]")){if(-1!==t.content.indexOf("user-scalable=no"))return!0;if(i>31&&window.innerWidth<=window.screen.width)return!0}}return"none"===e.style.msTouchAction},n.attach=function(e){"use strict";return new n(e)},"undefined"!=typeof define&&define.amd?define(function(){"use strict";return n}):void 0!==t&&t.exports?(t.exports=n.attach,t.exports.FastClick=n):window.FastClick=n}),e.register("component~indexof@0.0.3",function(e,t){t.exports=function(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0;n<e.length;++n)if(e[n]===t)return n;return-1}}),e.register("component~classes@1.2.1",function(t,n){function i(e){if(!e)throw new Error("A DOM element reference is required");this.el=e,this.list=e.classList}var r=e("component~indexof@0.0.3"),o=/\s+/,a=Object.prototype.toString;n.exports=function(e){return new i(e)},i.prototype.add=function(e){if(this.list)return this.list.add(e),this;var t=this.array();return~r(t,e)||t.push(e),this.el.className=t.join(" "),this},i.prototype.remove=function(e){if("[object RegExp]"==a.call(e))return this.removeMatching(e);if(this.list)return this.list.remove(e),this;var t=this.array(),n=r(t,e);return~n&&t.splice(n,1),this.el.className=t.join(" "),this},i.prototype.removeMatching=function(e){for(var t=this.array(),n=0;n<t.length;n++)e.test(t[n])&&this.remove(t[n]);return this},i.prototype.toggle=function(e,t){return this.list?(void 0!==t?t!==this.list.toggle(e,t)&&this.list.toggle(e):this.list.toggle(e),this):(void 0!==t?t?this.add(e):this.remove(e):this.has(e)?this.remove(e):this.add(e),this)},i.prototype.array=function(){var e=this.el.className.replace(/^\s+|\s+$/g,""),t=e.split(o);return""===t[0]&&t.shift(),t},i.prototype.has=i.prototype.contains=function(e){return this.list?this.list.contains(e):!!~r(this.array(),e)}}),e.register("component~event@0.1.4",function(e,t){var n=window.addEventListener?"addEventListener":"attachEvent",i=window.removeEventListener?"removeEventListener":"detachEvent",r="addEventListener"!==n?"on":"";e.bind=function(e,t,i,o){return e[n](r+t,i,o||!1),i},e.unbind=function(e,t,n,o){return e[i](r+t,n,o||!1),n}}),e.register("component~query@0.0.3",function(e,t){function n(e,t){return t.querySelector(e)}e=t.exports=function(e,t){return t=t||document,n(e,t)},e.all=function(e,t){return t=t||document,t.querySelectorAll(e)},e.engine=function(t){if(!t.one)throw new Error(".one callback required");if(!t.all)throw new Error(".all callback required");return n=t.one,e.all=t.all,e}}),e.register("component~matches-selector@0.1.5",function(t,n){function i(e,t){if(!e||1!==e.nodeType)return!1;if(a)return a.call(e,t);for(var n=r.all(t,e.parentNode),i=0;i<n.length;++i)if(n[i]==e)return!0;return!1}var r=e("component~query@0.0.3"),o=Element.prototype,a=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.msMatchesSelector||o.oMatchesSelector;n.exports=i}),e.register("component~closest@0.1.4",function(t,n){var i=e("component~matches-selector@0.1.5");n.exports=function(e,t,n,r){for(e=n?{parentNode:e}:e,r=r||document;(e=e.parentNode)&&e!==document;){if(i(e,t))return e;if(e===r)return}}}),e.register("component~delegate@0.2.3",function(t,n){var i=e("component~closest@0.1.4"),r=e("component~event@0.1.4");t.bind=function(e,t,n,o,a){return r.bind(e,n,function(n){var r=n.target||n.srcElement;n.delegateTarget=i(r,t,!0,e),n.delegateTarget&&o.call(e,n)},a)},t.unbind=function(e,t,n,i){r.unbind(e,t,n,i)}}),e.register("component~events@1.0.9",function(t,n){function i(e,t){if(!(this instanceof i))return new i(e,t);if(!e)throw new Error("element required");if(!t)throw new Error("object required");this.el=e,this.obj=t,this._events={}}function r(e){var t=e.split(/ +/);return{name:t.shift(),selector:t.join(" ")}}var o=e("component~event@0.1.4"),a=e("component~delegate@0.2.3");n.exports=i,i.prototype.sub=function(e,t,n){this._events[e]=this._events[e]||{},this._events[e][t]=n},i.prototype.bind=function(e,t){function n(){var e=[].slice.call(arguments).concat(u);l[t].apply(l,e)}var i=r(e),s=this.el,l=this.obj,c=i.name,t=t||"on"+c,u=[].slice.call(arguments,2);return i.selector?n=a.bind(s,i.selector,c,n):o.bind(s,c,n),this.sub(c,t,n),n},i.prototype.unbind=function(e,t){if(0==arguments.length)return this.unbindAll();if(1==arguments.length)return this.unbindAllOf(e);var n=this._events[e];if(n){var i=n[t];i&&o.unbind(this.el,e,i)}},i.prototype.unbindAll=function(){for(var e in this._events)this.unbindAllOf(e)},i.prototype.unbindAllOf=function(e){var t=this._events[e];if(t)for(var n in t)this.unbind(e,n)}}),e.register("switchery",function(t,n){function i(e,t){if(!(this instanceof i))return new i(e,t);this.element=e,this.options=t||{};for(var n in l)null==this.options[n]&&(this.options[n]=l[n]);null!=this.element&&"checkbox"==this.element.type&&this.init(),!0===this.isDisabled()&&this.disable()}var r=e("abpetkov~transitionize@0.0.3"),o=e("ftlabs~fastclick@v0.6.11"),a=e("component~classes@1.2.1"),s=e("component~events@1.0.9");n.exports=i;var l={color:"#64bd63",secondaryColor:"#dfdfdf",jackColor:"#fff",jackSecondaryColor:null,className:"switchery",disabled:!1,disabledOpacity:.5,speed:"0.4s",size:"default"};i.prototype.hide=function(){this.element.style.display="none"},i.prototype.show=function(){var e=this.create();this.insertAfter(this.element,e)},i.prototype.create=function(){return this.switcher=document.createElement("span"),this.jack=document.createElement("small"),this.switcher.appendChild(this.jack),this.switcher.className=this.options.className,this.events=s(this.switcher,this),this.switcher},i.prototype.insertAfter=function(e,t){
+e.parentNode.insertBefore(t,e.nextSibling)},i.prototype.setPosition=function(e){var t=this.isChecked(),n=this.switcher,i=this.jack;e&&t?t=!1:e&&!t&&(t=!0),!0===t?(this.element.checked=!0,i.style.left=window.getComputedStyle?parseInt(window.getComputedStyle(n).width)-parseInt(window.getComputedStyle(i).width)+"px":parseInt(n.currentStyle.width)-parseInt(i.currentStyle.width)+"px",this.options.color&&this.colorize(),this.setSpeed()):(i.style.left=0,this.element.checked=!1,this.switcher.style.boxShadow="inset 0 0 0 0 "+this.options.secondaryColor,this.switcher.style.borderColor=this.options.secondaryColor,this.switcher.style.backgroundColor=this.options.secondaryColor!==l.secondaryColor?this.options.secondaryColor:"#fff",this.jack.style.backgroundColor=this.options.jackSecondaryColor!==this.options.jackColor?this.options.jackSecondaryColor:this.options.jackColor,this.setSpeed())},i.prototype.setSpeed=function(){var e={},t={"background-color":this.options.speed,left:this.options.speed.replace(/[a-z]/,"")/2+"s"};e=this.isChecked()?{border:this.options.speed,"box-shadow":this.options.speed,"background-color":3*this.options.speed.replace(/[a-z]/,"")+"s"}:{border:this.options.speed,"box-shadow":this.options.speed},r(this.switcher,e),r(this.jack,t)},i.prototype.setSize=function(){switch(this.options.size){case"small":a(this.switcher).add("switchery-small");break;case"large":a(this.switcher).add("switchery-large");break;default:a(this.switcher).add("switchery-default")}},i.prototype.colorize=function(){var e=this.switcher.offsetHeight/2;this.switcher.style.backgroundColor=this.options.color,this.switcher.style.borderColor=this.options.color,this.switcher.style.boxShadow="inset 0 0 0 "+e+"px "+this.options.color,this.jack.style.backgroundColor=this.options.jackColor},i.prototype.handleOnchange=function(e){if(document.dispatchEvent){var t=document.createEvent("HTMLEvents");t.initEvent("change",!0,!0),this.element.dispatchEvent(t)}else this.element.fireEvent("onchange")},i.prototype.handleChange=function(){var e=this,t=this.element;t.addEventListener?t.addEventListener("change",function(){e.setPosition()}):t.attachEvent("onchange",function(){e.setPosition()})},i.prototype.handleClick=function(){var e=this.switcher;o(e),this.events.bind("click","bindClick")},i.prototype.bindClick=function(){var e=this.element.parentNode.tagName.toLowerCase(),t="label"!==e;this.setPosition(t),this.handleOnchange(this.element.checked)},i.prototype.markAsSwitched=function(){this.element.setAttribute("data-switchery",!0)},i.prototype.markedAsSwitched=function(){return this.element.getAttribute("data-switchery")},i.prototype.init=function(){this.hide(),this.show(),this.setSize(),this.setPosition(),this.markAsSwitched(),this.handleChange(),this.handleClick()},i.prototype.isChecked=function(){return this.element.checked},i.prototype.isDisabled=function(){return this.options.disabled||this.element.disabled||this.element.readOnly},i.prototype.destroy=function(){this.events.unbind()},i.prototype.enable=function(){this.options.disabled&&(this.options.disabled=!1),this.element.disabled&&(this.element.disabled=!1),this.element.readOnly&&(this.element.readOnly=!1),this.switcher.style.opacity=1,this.events.bind("click","bindClick")},i.prototype.disable=function(){this.options.disabled||(this.options.disabled=!0),this.element.disabled||(this.element.disabled=!0),this.element.readOnly||(this.element.readOnly=!0),this.switcher.style.opacity=this.options.disabledOpacity,this.destroy()}}),"object"==typeof exports?module.exports=e("switchery"):"function"==typeof define&&define.amd?define("Switchery",[],function(){return e("switchery")}):(this||window).Switchery=e("switchery")}(),angular.module("NgSwitchery",[]).directive("uiSwitch",["$window","$timeout","$log","$parse",function(e,t,n,i){function r(n,r,o,a){function s(){t(function(){c&&angular.element(c.switcher).remove(),c=new e.Switchery(r[0],l);var t=c.element;t.checked=n.initValue,c.setPosition(!1),t.addEventListener("change",function(e){n.$apply(function(){a.$setViewValue(t.checked)})})},0)}if(!a)return!1;var l={};try{l=i(o.uiSwitch)(n)}catch(e){}var c,u;o.$observe("disabled",function(e){void 0!=e&&e!=u&&(u=e,s())}),s()}return{require:"ngModel",restrict:"AE",scope:{initValue:"=ngModel"},link:r}}]),function(){function e(e){return["$rootScope","$window",function(t,n){for(var i,r,o,a=n[e]||(console.warn("This browser does not support Web Storage!"),{}),s={$default:function(e){for(var t in e)angular.isDefined(s[t])||(s[t]=e[t]);return s},$reset:function(e){for(var t in s)"$"===t[0]||delete s[t];return s.$default(e)}},l=0;l<a.length;l++)(o=a.key(l))&&"ngStorage-"===o.slice(0,10)&&(s[o.slice(10)]=angular.fromJson(a.getItem(o)));return i=angular.copy(s),t.$watch(function(){r||(r=setTimeout(function(){if(r=null,!angular.equals(s,i)){angular.forEach(s,function(e,t){angular.isDefined(e)&&"$"!==t[0]&&a.setItem("ngStorage-"+t,angular.toJson(e)),delete i[t]});for(var e in i)a.removeItem("ngStorage-"+e);i=angular.copy(s)}},100))}),"localStorage"===e&&n.addEventListener&&n.addEventListener("storage",function(e){"ngStorage-"===e.key.slice(0,10)&&(e.newValue?s[e.key.slice(10)]=angular.fromJson(e.newValue):delete s[e.key.slice(10)],i=angular.copy(s),t.$apply())}),s}]}angular.module("ngStorage",[]).factory("$localStorage",e("localStorage")).factory("$sessionStorage",e("sessionStorage"))}(); \ No newline at end of file
diff --git a/old/moon_gui/delivery/version.json b/old/moon_gui/delivery/version.json
new file mode 100755
index 00000000..0e224bd8
--- /dev/null
+++ b/old/moon_gui/delivery/version.json
@@ -0,0 +1 @@
+{ "version": "1.0.0" } \ No newline at end of file
diff --git a/old/moon_gui/gulpfile.js b/old/moon_gui/gulpfile.js
new file mode 100644
index 00000000..5929da4b
--- /dev/null
+++ b/old/moon_gui/gulpfile.js
@@ -0,0 +1,213 @@
+'use strict';
+
+var gulp = require('gulp');
+
+var plugins = require('gulp-load-plugins')({
+ pattern: ['gulp-*','vinyl-paths', 'del', 'browser-sync', 'stream-series'],
+ replaceString: /\bgulp[\-.]/
+});
+
+const paths = {
+ app:'static/',
+ templates : 'templates/',
+ build : 'dist/',
+ delivery: 'delivery/',
+ modules:[
+ 'jquery/dist/jquery.js',
+ 'underscore/underscore.js',
+ 'bootstrap/dist/js/bootstrap.js',
+ 'angular/angular.js',
+ 'angular-route/angular-route.js',
+ 'angular-resource/angular-resource.js',
+ 'angular-cookies/angular-cookies.js',
+ 'angular-animate/angular-animate.js',
+ 'angular-messages/angular-messages.min.js',
+ 'angular-bootstrap/ui-bootstrap-tpls.js',
+ 'angular-ui-router/release/angular-ui-router.js',
+ 'angular-translate/dist/angular-translate.js',
+ 'angular-translate-loader-static-files/angular-translate-loader-static-files.js',
+ 'angular-translate-storage-cookie/angular-translate-storage-cookie.js',
+ 'angular-strap/dist/angular-strap.js',
+ 'angular-strap/dist/angular-strap.tpl.js',
+ 'angularjs-toaster/toaster.js',
+ 'ng-table/dist/ng-table.js',
+ 'select2/select2.js',
+ 'angular-ui-select/select.js',
+ 'switchery/standalone/switchery.js',
+ 'ng-switchery/dist/ng-switchery.js',
+ 'ng-storage/ngStorage.min.js'
+ ],
+ cssModules:[
+ 'bootstrap/dist/css/bootstrap.css',
+ 'ng-table/dist/ng-table.css',
+ 'select2/select2.css',
+ 'angular-ui-select/select.css',
+ 'selectize/dist/css/selectize.default.css',
+ 'angular-motion/dist/angular-motion.css',
+ 'switchery/standalone/switchery.css',
+ 'angularjs-toaster/toaster.css'
+ ]
+
+};
+
+gulp.task('webServer', function() {
+
+ plugins.browserSync({
+ notify: false,
+ server: {
+ baseDir: paths.build,
+ middleware: function (req, res, next) {
+ res.setHeader('Access-Control-Allow-Origin', '*');
+ res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT');
+ next();
+ }}
+ });
+ gulp.watch(['templates/*', 'static/**/*'], ['inject', plugins.browserSync.reload]);
+});
+
+gulp.task('inject', function () {
+ // Js
+ var appStream = gulp.src([paths.app + 'app/moon.module.js', paths.app + 'app/moon.constants.js', paths.app + 'app/**/*.js*'])
+ .pipe(plugins.concat('app.js'))
+ .pipe(plugins.uglify())
+ .pipe(gulp.dest(paths.build + 'js/'));
+
+ // Modules js
+ var moduleJsStream = gulp.src(paths.modules.map( function(item){return 'node_modules/' + item;}))
+ .pipe(plugins.concat('modules.js'))
+ .pipe(plugins.uglify())
+ .pipe(gulp.dest(paths.build + 'js/'));
+
+ //Version
+ gulp.src([paths.app + '/version.json'])
+ .pipe(plugins.htmlmin({collapseWhitespace: true}))
+ .pipe(gulp.dest(paths.build));
+
+
+ // Html
+ gulp.src([paths.app + 'app/**/*.html'])
+ .pipe(plugins.htmlmin({collapseWhitespace: true}))
+ .pipe(gulp.dest(paths.build + 'html'));
+
+ // Styles
+ var cssStream = gulp.src(paths.cssModules.map( function(item){return 'node_modules/' + item;}).concat([paths.app + 'styles/main.css']))
+ .pipe(plugins.concat('main.css'))
+ .pipe(plugins.cleanCss())
+ .pipe(gulp.dest(paths.build + 'assets/css'));
+
+ // fonts
+ gulp.src(['node_modules/bootstrap/dist/fonts/gly*'])
+ .pipe(gulp.dest(paths.build + 'assets/fonts'));
+
+ // i18n
+ gulp.src([paths.app + 'i18n/*.json'])
+ .pipe(gulp.dest(paths.build + 'assets/i18n'));
+
+ // Images
+ gulp.src([paths.app + 'img/*.gif', paths.app + 'img/*.png', paths.app + 'img/*.jpg'])
+ .pipe(gulp.dest(paths.build + 'assets/img'));
+
+ // Favicon
+ gulp.src([paths.app + '*.ico'])
+ .pipe(gulp.dest(paths.build + 'assets/img'));
+
+ gulp.src(paths.templates + 'index.html')
+ .pipe(plugins.inject(plugins.streamSeries(moduleJsStream, appStream), { ignorePath: paths.build, addRootSlash: false }))
+ .pipe(plugins.inject(cssStream , { ignorePath: paths.build, addRootSlash: false }))
+ .pipe(gulp.dest(paths.build));
+});
+
+gulp.task('copyMinifyHtml',function(){
+ // app
+ gulp.src([paths.app + 'app/**/*.html'])
+ .pipe(plugins.htmlmin({collapseWhitespace: true}))
+ .pipe(gulp.dest(paths.build + 'html'));
+});
+
+
+
+gulp.task('webServerDelivery', function() {
+
+ plugins.browserSync({
+ notify: false,
+ server: {
+ baseDir: paths.delivery,
+ middleware: function (req, res, next) {
+ res.setHeader('Access-Control-Allow-Origin', '*');
+ res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT');
+ next();
+ }}
+ });
+
+});
+
+gulp.task('injectDelivery', function () {
+ // Js
+ var appStream = gulp.src([paths.app + 'app/moon.module.js', paths.app + 'app/moon.constants.js', paths.app + 'app/**/*.js*'])
+ .pipe(plugins.concat('app.js'))
+ .pipe(plugins.uglify())
+ .pipe(gulp.dest(paths.delivery + 'js/'));
+
+ // Modules js
+ var moduleJsStream = gulp.src(paths.modules.map( function(item){return 'node_modules/' + item;}))
+ .pipe(plugins.concat('modules.js'))
+ .pipe(plugins.uglify())
+ .pipe(gulp.dest(paths.delivery + 'js/'));
+
+ //Version
+ gulp.src([paths.app + '/version.json'])
+ .pipe(plugins.htmlmin({collapseWhitespace: true}))
+ .pipe(gulp.dest(paths.delivery));
+
+
+ // Html
+ gulp.src([paths.app + 'app/**/*.html'])
+ .pipe(plugins.htmlmin({collapseWhitespace: true}))
+ .pipe(gulp.dest(paths.delivery + 'html'));
+
+
+ // Styles
+ var cssStream = gulp.src(paths.cssModules.map( function(item){return 'node_modules/' + item;}).concat([paths.app + 'styles/main.css']))
+ .pipe(plugins.concat('main.css'))
+ .pipe(plugins.cleanCss())
+ .pipe(gulp.dest(paths.delivery + 'assets/css'));
+
+ // fonts
+ gulp.src(['node_modules/bootstrap/dist/fonts/gly*'])
+ .pipe(gulp.dest(paths.delivery + 'assets/fonts'));
+
+
+ // i18n
+ gulp.src([paths.app + 'i18n/*.json'])
+ .pipe(gulp.dest(paths.delivery + 'assets/i18n'));
+
+ // Images
+ gulp.src([paths.app + 'img/*.gif', paths.app + 'img/*.png', paths.app + 'img/*.jpg'])
+ .pipe(gulp.dest(paths.delivery + 'assets/img'));
+
+ // Favicon
+ gulp.src([paths.app + '*.ico'])
+ .pipe(gulp.dest(paths.delivery + 'assets/img'));
+
+ gulp.src(paths.templates + 'index.html')
+ .pipe(plugins.inject(plugins.streamSeries(moduleJsStream, appStream), { ignorePath: paths.delivery, addRootSlash: false }))
+ .pipe(plugins.inject(cssStream , { ignorePath: paths.delivery, addRootSlash: false }))
+ .pipe(gulp.dest(paths.delivery));
+});
+
+gulp.task('copyMinifyHtmlDelivery',function(){
+ // app
+ gulp.src([paths.app + 'app/**/*.html'])
+ .pipe(plugins.htmlmin({collapseWhitespace: true}))
+ .pipe(gulp.dest(paths.delivery + 'html'));
+});
+
+
+
+
+gulp.task('build', [ 'inject', 'copyMinifyHtml']);
+gulp.task('delivery', [ 'injectDelivery', 'copyMinifyHtmlDelivery']);
+gulp.task('html', ['copyAndMinifyHtml']);
+gulp.task('default', ['build', 'webServer' ]); \ No newline at end of file
diff --git a/old/moon_gui/package.json b/old/moon_gui/package.json
new file mode 100644
index 00000000..45157e5e
--- /dev/null
+++ b/old/moon_gui/package.json
@@ -0,0 +1,54 @@
+{
+ "name": "moonwebview",
+ "version": "1.0.0",
+ "homepage": "https://github.com/rebirthmonkey/moon",
+ "authors": [
+ "arnaud.marhin <arnaud.marhin@orange.com>",
+ "samy Abdallah <samy.abdallah@orange.com>, @samyabh"
+ ],
+ "description": "Authorization module for OpenStack",
+ "main": "index.js",
+ "dependencies": {},
+ "devDependencies": {
+ "angular": "1.3.0",
+ "angular-animate": "1.3.0",
+ "angular-bootstrap": "0.12.2",
+ "angular-cookies": "1.3.0",
+ "angular-messages": "1.5.0",
+ "angular-motion": "0.3.4",
+ "angular-resource": "1.3.0",
+ "angular-route": "1.3.0",
+ "angular-strap": "2.3.8",
+ "angular-translate": "2.4.1",
+ "angular-translate-loader-static-files": "2.7.0",
+ "angular-translate-storage-cookie": "2.7.0",
+ "angular-ui-router": "0.2.11",
+ "angular-ui-select": "0.12.10",
+ "angularjs-toaster": "0.4.12",
+ "bootstrap": "3.2.0",
+ "browser-sync": "^2.18.8",
+ "del": "^2.2.2",
+ "gulp": "^3.9.1",
+ "gulp-clean-css": "^3.0.3",
+ "gulp-concat": "^2.6.1",
+ "gulp-htmlmin": "^3.0.0",
+ "gulp-inject": "^4.2.0",
+ "gulp-load-plugins": "^1.5.0",
+ "gulp-uglify": "^2.0.1",
+ "gulp-webserver": "^0.9.1",
+ "jquery": "2.1.1",
+ "ng-storage": "^0.3.2",
+ "ng-switchery": "1.0.0",
+ "ng-table": "0.5.4",
+ "select2": "3.5.1",
+ "selectize": "0.12.0",
+ "stream-series": "^0.1.1",
+ "switchery": "0.0.2",
+ "underscore": "1.8.3",
+ "vinyl-paths": "^2.1.0"
+ },
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "license": "Apache-2.0"
+}
diff --git a/old/moon_gui/run.sh b/old/moon_gui/run.sh
new file mode 100644
index 00000000..94bc8360
--- /dev/null
+++ b/old/moon_gui/run.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+service apache2 start
+
+sed "s/{{MANAGER_HOST}}/$MANAGER_HOST/g" -i /root/static/app/moon.constants.js
+sed "s/{{MANAGER_PORT}}/$MANAGER_PORT/g" -i /root/static/app/moon.constants.js
+sed "s/{{KEYSTONE_HOST}}/$KEYSTONE_HOST/g" -i /root/static/app/moon.constants.js
+sed "s/{{KEYSTONE_PORT}}/$KEYSTONE_PORT/g" -i /root/static/app/moon.constants.js
+
+echo "--------------------------"
+cat /root/static/app/moon.constants.js
+echo "--------------------------"
+
+gulp delivery
+cp -rv /root/delivery/* /var/www/html
+
+tail -f /var/log/apache2/error.log
diff --git a/old/moon_gui/static/app/authentication/authentication.controller.js b/old/moon_gui/static/app/authentication/authentication.controller.js
new file mode 100755
index 00000000..ce38bc5f
--- /dev/null
+++ b/old/moon_gui/static/app/authentication/authentication.controller.js
@@ -0,0 +1,58 @@
+/**
+ * @author Samy Abdallah
+ */
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('AuthenticationController', AuthenticationController);
+
+ AuthenticationController.$inject = ['authenticationService', '$translate', 'alertService', '$state', '$rootScope'];
+
+ function AuthenticationController(authenticationService, $translate, alertService, $state, $rootScope) {
+
+ var vm = this;
+
+ vm.login = login;
+ vm.loading = false;
+
+ vm.credentials = {
+ username : '',
+ password : ''
+ };
+
+ activate();
+
+ function activate(){
+ if($rootScope.connected){
+ $state.go('moon.dashboard');
+ }
+ }
+
+ function login(){
+ vm.loading = true;
+ authenticationService.Login(vm.credentials, loginSuccess, loginError);
+ }
+
+ function loginSuccess() {
+
+ $translate('moon.login.success').then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ $state.go('moon.dashboard');
+ vm.loading = false;
+ });
+
+ }
+
+ function loginError(reason) {
+
+ $translate('moon.login.error', { errorCode: reason.status }).then( function(translatedValue) {
+ alertService.alertError(translatedValue);
+ vm.loading = false;
+ });
+
+ }
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/authentication/authentication.tpl.html b/old/moon_gui/static/app/authentication/authentication.tpl.html
new file mode 100755
index 00000000..77d1646b
--- /dev/null
+++ b/old/moon_gui/static/app/authentication/authentication.tpl.html
@@ -0,0 +1,28 @@
+<div class="col-md-6 col-md-offset-3">
+
+ <h2 data-translate="moon.login.titlePage">Login</h2>
+
+ <form name="form" ng-submit="form.$valid && auth.login()" novalidate>
+
+ <div class="form-group" ng-class="{ 'has-error': form.$submitted && form.username.$invalid }">
+ <label for="username" data-translate="moon.login.username" >Username</label>
+ <input type="text" id="username" name="username" class="form-control" ng-model="auth.credentials.username" required />
+ <div ng-messages="form.$submitted && form.username.$error" class="help-block">
+ <div ng-message="required" data-translate="moon.login.check.username.required" >Username is required</div>
+ </div>
+ </div>
+
+ <div class="form-group" ng-class="{ 'has-error': form.$submitted && form.password.$invalid }">
+ <label for="password" data-translate="moon.login.password" >Password</label>
+ <input type="password" id="password" name="password" class="form-control" ng-model="auth.credentials.password" required />
+ <div ng-messages="form.$submitted && form.password.$error" class="help-block">
+ <div ng-message="required" data-translate="moon.login.check.password.required">Password is required</div>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <button ng-disabled="auth.loading" class="btn btn-primary" data-translate="moon.login.login" >Login</button>
+ <img ng-if="auth.loading" src="assets/img/ajax-loader.gif" />
+ </div>
+ </form>
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/common/404/404.tpl.html b/old/moon_gui/static/app/common/404/404.tpl.html
new file mode 100755
index 00000000..61e0420c
--- /dev/null
+++ b/old/moon_gui/static/app/common/404/404.tpl.html
@@ -0,0 +1,3 @@
+<div data-translate="moon.global.404">Not found!</div>
+
+<div> Go <a href="" ui-sref="moon.project.list">Projects ?</a></div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/common/compatibility/compatibility.tpl.html b/old/moon_gui/static/app/common/compatibility/compatibility.tpl.html
new file mode 100755
index 00000000..0e32dc4f
--- /dev/null
+++ b/old/moon_gui/static/app/common/compatibility/compatibility.tpl.html
@@ -0,0 +1,26 @@
+<div class="modal" tabindex="-1" data-role="modalCompatibility">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.compatibility.title"></h4>
+ </div>
+
+ <div class="modal-body">
+ <span data-translate="moon.compatibility.content"></span>
+ </div>
+
+ <div class="modal-footer">
+ <div class="btn-toolbar" style="float: right;">
+ <button ng-click="$hide()" class="btn btn-default" data-translate="moon.compatibility.close">Close</button>
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/common/footer/footer.controller.js b/old/moon_gui/static/app/common/footer/footer.controller.js
new file mode 100755
index 00000000..d7506840
--- /dev/null
+++ b/old/moon_gui/static/app/common/footer/footer.controller.js
@@ -0,0 +1,54 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('FooterController', FooterController);
+
+ FooterController.$inject = ['$modal', 'versionService'];
+
+ function FooterController($modal, versionService) {
+
+ var footer = this;
+
+ footer.version = null;
+ footer.browsersModal = null;
+ footer.showBrowsersCompliance = showBrowsersCompliance;
+
+ newBrowsersModal();
+ currentVersion();
+
+ function newBrowsersModal() {
+
+ footer.browsersModal = $modal({ template: 'html/common/compatibility/compatibility.tpl.html', show: false });
+
+ return footer.browsersModal;
+
+ }
+
+ function showBrowsersCompliance() {
+ footer.browsersModal.$promise.then(footer.browsersModal.show);
+ }
+
+ function currentVersion() {
+
+ var _self = footer;
+
+ versionService.version.get().$promise.then(function(data) {
+
+ _self.version = (data.version) ? data.version : 'SNAPSHOT';
+
+ return _self.version;
+
+ });
+
+ }
+
+ }
+
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/common/footer/footer.tpl.html b/old/moon_gui/static/app/common/footer/footer.tpl.html
new file mode 100755
index 00000000..aacb392d
--- /dev/null
+++ b/old/moon_gui/static/app/common/footer/footer.tpl.html
@@ -0,0 +1,7 @@
+<div class="container footer" ng-controller="FooterController as footer">
+ <div class="row">
+ <div class="pull-right">
+ <span>v<span ng-bind="footer.version"></span></span> - <a href="" ng-click="footer.showBrowsersCompliance()" data-translate="moon.compatibility.label">browser compatibility</a>
+ </div>
+ </div>
+</div>
diff --git a/old/moon_gui/static/app/common/header/header.controller.js b/old/moon_gui/static/app/common/header/header.controller.js
new file mode 100755
index 00000000..13ef4d6f
--- /dev/null
+++ b/old/moon_gui/static/app/common/header/header.controller.js
@@ -0,0 +1,56 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('HeaderController', HeaderController);
+
+ HeaderController.$inject = ['$translate', 'menuService', 'authenticationService', 'alertService'];
+
+ function HeaderController($translate, menuService, authenticationService, alertService) {
+
+ var header = this;
+
+ /*
+ *
+ */
+
+ header.isProjectTabActive = menuService.isProjectTabActive;
+ header.isPDPTabActive = menuService.isPDPTabActive;
+ header.isLogsTabActive = menuService.isLogsTabActive;
+ header.isPolicyTabActive = menuService.isPolicyTabActive;
+ header.isModelTabActive = menuService.isModelTabActive;
+ header.changeLocale = changeLocale;
+ header.logout = logout;
+ header.currentLanguage = $translate.use();
+
+ header.getUser = authenticationService.GetUser;
+
+ /*
+ *
+ */
+
+ function changeLocale(localeKey, event) {
+
+ event.preventDefault();
+ $translate.use(localeKey);
+ $translate.preferredLanguage(localeKey);
+ header.currentLanguage = localeKey;
+
+ }
+
+ function logout(){
+
+ authenticationService.Logout();
+ $translate('moon.logout.success').then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ }
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/common/header/header.tpl.html b/old/moon_gui/static/app/common/header/header.tpl.html
new file mode 100755
index 00000000..7c7633d1
--- /dev/null
+++ b/old/moon_gui/static/app/common/header/header.tpl.html
@@ -0,0 +1,52 @@
+<div class="container banner" ng-controller="HeaderController as header">
+
+ <div class="row">
+
+ <div class="col-md-3 sub-banner">
+ <a ui-sref="moon.dashboard"><img src="assets/img/logo-orange.gif" alt="Orange" /> </a>
+ <img src="assets/img/logo-openstack.png" alt="OpenStack" />
+ </div>
+
+ <div class="col-md-6 center-block">
+ <h1 data-translate="moon.global.applicationName">Moon UI</h1>
+ </div>
+
+ <div class="col-md-3">
+
+ <span class="pull-right">
+
+ <a href="" ng-click="header.changeLocale('fr', $event)" ng-class="{'strong' : header.currentLanguage === 'fr'}"><img src="assets/img/arrow-link.gif" alt="fr_" />fr</a>
+ <a href="" ng-click="header.changeLocale('en', $event)" ng-class="{'strong' : header.currentLanguage === 'en'}"><img src="assets/img/arrow-link.gif" alt="en_" />en</a>
+
+ <a href="" ng-if="connected" ng-click="header.logout()" class="left30">
+ <span class="glyphicon glyphicon-log-out"></span>
+ <span data-translate="moon.logout.title">Logout</span>(<span ng-bind="header.getUser().token.user.name"></span>)
+ </a>
+
+ <a href="" ng-if="!connected" class="left30">
+ <span class="glyphicon glyphicon-log-in"></span>
+ <span data-translate="moon.login.title">Login</span>
+ </a>
+ </span>
+
+ </div>
+
+ </div>
+
+ <div class="row">
+ <toaster-container toaster-options="{'position-class': 'toast-top-right', 'close-button': true}"></toaster-container>
+ </div>
+
+ <div class="row" ng-if="connected">
+
+ <ul class="nav nav-tabs">
+ <li ng-class="{active: header.isModelTabActive()}"><a ui-sref="moon.model.list" data-translate="moon.menu.model">Models</a></li>
+ <li ng-class="{active: header.isPolicyTabActive()}"><a ui-sref="moon.policy.list" data-translate="moon.menu.policy">Policy</a></li>
+ <li ng-class="{active: header.isPDPTabActive()}"><a ui-sref="moon.pdp.list" data-translate="moon.menu.pdp">PDP</a></li>
+ <li ng-class="{active: header.isProjectTabActive()}"><a ui-sref="moon.project.list" data-translate="moon.menu.project">Projects</a></li>
+ <!--<li ng-class="{active: header.isLogsTabActive()}"><a ui-sref="moon.logs" data-translate="moon.menu.logs">Logs</a></li>-->
+ </ul>
+
+ </div>
+
+</div>
diff --git a/old/moon_gui/static/app/common/loader/loader.dir.js b/old/moon_gui/static/app/common/loader/loader.dir.js
new file mode 100755
index 00000000..ba40c121
--- /dev/null
+++ b/old/moon_gui/static/app/common/loader/loader.dir.js
@@ -0,0 +1,19 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonLoader', moonLoader);
+
+ moonLoader.$inject = [];
+
+ function moonLoader() {
+
+ return {
+ templateUrl : 'html/common/loader/loader.tpl.html',
+ restrict : 'E'
+ };
+ }
+
+})();
diff --git a/old/moon_gui/static/app/common/loader/loader.tpl.html b/old/moon_gui/static/app/common/loader/loader.tpl.html
new file mode 100755
index 00000000..51da439f
--- /dev/null
+++ b/old/moon_gui/static/app/common/loader/loader.tpl.html
@@ -0,0 +1 @@
+<img src="assets/img/ajax-loader.gif" /> \ No newline at end of file
diff --git a/old/moon_gui/static/app/common/waiting/waiting.tpl.html b/old/moon_gui/static/app/common/waiting/waiting.tpl.html
new file mode 100755
index 00000000..6c042635
--- /dev/null
+++ b/old/moon_gui/static/app/common/waiting/waiting.tpl.html
@@ -0,0 +1,15 @@
+<div class="modal" tabindex="-1" data-role="modalWaiting">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-body centered">
+ <img src="assets/img/ajax-waiting.gif" />
+ </div>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/dashboard/dashboard.tpl.html b/old/moon_gui/static/app/dashboard/dashboard.tpl.html
new file mode 100755
index 00000000..67184bcc
--- /dev/null
+++ b/old/moon_gui/static/app/dashboard/dashboard.tpl.html
@@ -0,0 +1,14 @@
+<div class="container">
+
+ <div class="row">
+
+ <h1 data-translate="moon.dashboard.content">Moon:Software-Defined Security Framework</h1>
+ </div>
+
+ <div class="row">
+
+ <img src="assets/img/et.jpg" alt="ET" class="img-responsive img-dashboard"/>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/logs/logs.controller.js b/old/moon_gui/static/app/logs/logs.controller.js
new file mode 100755
index 00000000..e48e2b8b
--- /dev/null
+++ b/old/moon_gui/static/app/logs/logs.controller.js
@@ -0,0 +1,16 @@
+/**
+ * @author Samy Abdallah
+ */
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('LogsController', LogsController);
+
+ function LogsController() {
+
+ }
+
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/logs/logs.tpl.html b/old/moon_gui/static/app/logs/logs.tpl.html
new file mode 100755
index 00000000..fecc0289
--- /dev/null
+++ b/old/moon_gui/static/app/logs/logs.tpl.html
@@ -0,0 +1,3 @@
+<div class="container">
+ Logs
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/model/action/model-add.tpl.html b/old/moon_gui/static/app/model/action/model-add.tpl.html
new file mode 100755
index 00000000..dee53a97
--- /dev/null
+++ b/old/moon_gui/static/app/model/action/model-add.tpl.html
@@ -0,0 +1,66 @@
+<div ng-controller="ModelAddController as add" class="modal" tabindex="-1" data-role="modalAddModel">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.model.add.title"></h4>
+ </div>
+
+ <div class="modal-body">
+
+ <form class="form-horizontal" role="form" name="add.form">
+
+ <div class="form-group" ng-class="{'has-error': add.form.name.$invalid && add.form.name.$dirty}">
+
+ <label for="name" class="col-sm-3 control-label" data-translate="moon.model.add.form.name">Name</label>
+
+ <div class="col-sm-6">
+
+ <input name="name" id="name" class="form-control" type="text" data-ng-model="add.model.name" required />
+
+ <div class="help-block" ng-show="add.form.name.$dirty && add.form.name.$invalid">
+ <small class="error" ng-show="add.form.name.$error.required" data-translate="moon.model.add.check.name.required">Name is required</small>
+ </div>
+
+ </div>
+ </div>
+
+ <div class="form-group">
+
+ <label for="description" class="col-sm-3 control-label" data-translate="moon.model.add.form.description">Description</label>
+ <div class="col-sm-6">
+ <textarea id="description" name="description" class="form-control" data-ng-model="add.model.description"></textarea>
+ </div>
+
+ </div>
+
+ </form>
+
+ </div>
+
+ <div class="modal-footer">
+
+ <div class="btn-toolbar" style="float: right;">
+
+ <a href="" ng-click="$hide()" class="btn btn-default">
+ <span data-translate="moon.model.add.action.cancel">Cancel</span>
+ </a>
+
+ <a href="" ng-disabled="add.loading" ng-click="add.create()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-save"></span>
+ <span data-translate="moon.model.add.action.create">Create Model</span>
+ </a>
+ <moon-loader ng-if="add.loading"></moon-loader>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ </div>
+
+</div>
diff --git a/old/moon_gui/static/app/model/action/model-delete.tpl.html b/old/moon_gui/static/app/model/action/model-delete.tpl.html
new file mode 100755
index 00000000..cde16d0e
--- /dev/null
+++ b/old/moon_gui/static/app/model/action/model-delete.tpl.html
@@ -0,0 +1,39 @@
+<div ng-controller="ModelDeleteController as del" class="modal" tabindex="-1" data-role="modalDeleteModel">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.model.remove.title"></h4>
+ </div>
+
+ <div class="modal-body">
+
+ <p><span data-translate="moon.model.remove.content.query" data-translate-values="{ modelName: del.model.name }"></span></p>
+
+ </div>
+
+ <div class="modal-footer">
+ <div class="btn-toolbar" style="float: right;">
+
+ <a href="" ng-click="$hide()" class="btn btn-default">
+ <span data-translate="moon.model.remove.action.cancel">Cancel</span>
+ </a>
+
+ <a href="" ng-disabled="del.loading" ng-click="del.remove()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span data-translate="moon.model.remove.action.delete">Delete</span>
+ </a>
+
+ <moon-loader ng-if="del.loading" ></moon-loader>
+
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/model/action/model-view.tpl.html b/old/moon_gui/static/app/model/action/model-view.tpl.html
new file mode 100755
index 00000000..46c295c7
--- /dev/null
+++ b/old/moon_gui/static/app/model/action/model-view.tpl.html
@@ -0,0 +1,41 @@
+<div ng-controller="ModelViewController as view" class="modal" tabindex="-1" data-role="modalViewProject">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.model.view.title" data-translate-values="{modelName: view.model.name}"></h4>
+ </div>
+ <div class="modal-body">
+ <dl class="dl-horizontal">
+ <dt data-translate="moon.model.view.id">Id</dt>
+ <dd ng-bind="view.model.id"></dd>
+ <dt data-translate="moon.model.view.name">Name</dt>
+ <dd ng-bind="view.model.name"></dd>
+ <dt data-translate="moon.model.view.description">Description</dt>
+ <dd ng-bind="view.model.description"></dd>
+ </dl>
+
+ <div ng-if="view.meta_rules_values">
+ <moon-meta-rules-list mapped-model="view.model" edit-mode="false"></moon-meta-rules-list>
+ </div>
+
+ <div ng-if="!view.meta_rules_values">
+ <moon-loader></moon-loader>
+ </div>
+
+ </div>
+
+ <div class="modal-footer top10">
+ <div class="btn-toolbar" style="float: right;">
+ <button ng-click="$hide()" class="btn btn-default" data-translate="moon.model.view.action.close">Close</button>
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+
+</div>
diff --git a/old/moon_gui/static/app/model/action/model.controller.add.js b/old/moon_gui/static/app/model/action/model.controller.add.js
new file mode 100755
index 00000000..11d3abf4
--- /dev/null
+++ b/old/moon_gui/static/app/model/action/model.controller.add.js
@@ -0,0 +1,71 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('ModelAddController', ModelAddController);
+
+ ModelAddController.$inject = ['$scope', 'modelService', 'alertService', '$translate', 'formService', 'utilService'];
+
+ function ModelAddController($scope, modelService, alertService, $translate, formService, utilService) {
+
+ var add = this;
+
+ /*
+ *
+ */
+
+ add.form = {};
+
+ add.loading = false;
+
+ add.model = { name: null, description: null, meta_rules : [] };
+
+ add.create = createModel;
+
+ function createModel() {
+
+ if(formService.isInvalid(add.form)) {
+
+ formService.checkFieldsValidity(add.form);
+
+ } else {
+
+ add.loading = true;
+
+ modelService.data.create({}, add.model, createSuccess, createError);
+
+ }
+
+ function createSuccess(data) {
+
+ var createdModel = utilService.transformOne(data, 'models');
+
+ $translate('moon.model.add.success', { modelName: createdModel.name }).then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ add.loading = false;
+
+ $scope.$emit('event:modelCreatedSuccess', createdModel);
+
+ }
+
+ function createError(reason) {
+
+ $translate('moon.model.add.error', { modelName: add.model.name }).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ add.loading = false;
+
+ $scope.$emit('event:modelCreatedError', add.project);
+
+ }
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/model/action/model.controller.delete.js b/old/moon_gui/static/app/model/action/model.controller.delete.js
new file mode 100755
index 00000000..5d9dae1a
--- /dev/null
+++ b/old/moon_gui/static/app/model/action/model.controller.delete.js
@@ -0,0 +1,72 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('ModelDeleteController', ModelDeleteController);
+
+ ModelDeleteController.$inject = ['$scope', '$translate', 'alertService', 'modelService'];
+
+ function ModelDeleteController($scope, $translate, alertService, modelService) {
+
+ var del = this;
+
+ /*
+ *
+ */
+
+ del.model = $scope.model;
+ del.loading = false;
+
+ del.remove = deleteModel;
+
+ activate();
+
+ /**
+ *
+ */
+
+ function activate(){
+
+ }
+
+
+ function deleteModel(){
+
+ del.loading = true;
+
+ modelService.delete(del.model, deleteSuccess, deleteError);
+
+ function deleteSuccess(data) {
+
+ $translate('moon.model.remove.success', { modelName: del.model.name }).then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ del.loading = false;
+
+ $scope.$emit('event:modelDeletedSuccess', del.model);
+
+ }
+
+ function deleteError(reason) {
+
+ $translate('moon.model.remove.error', { modelName: del.model.name, errorCode: reason.data.error.code, message : reason.data.error.message } ).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ del.loading = false;
+
+ $scope.$emit('event:modelDeletedError', del.model);
+
+ }
+
+ }
+ }
+
+})();
diff --git a/old/moon_gui/static/app/model/action/model.controller.view.js b/old/moon_gui/static/app/model/action/model.controller.view.js
new file mode 100755
index 00000000..7605eecf
--- /dev/null
+++ b/old/moon_gui/static/app/model/action/model.controller.view.js
@@ -0,0 +1,53 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('ModelViewController', ModelViewController);
+
+ ModelViewController.$inject = ['$scope', 'metaRuleService'];
+
+ function ModelViewController($scope, metaRuleService) {
+
+ var view = this;
+
+ /*
+ *
+ */
+
+ view.model = $scope.model;
+
+ view.meta_rules_values = false;
+
+ activate();
+
+ function activate(){
+
+ if(view.model.meta_rules.length > 0 ){
+
+ findMetaRules();
+
+ }else{
+
+ view.meta_rules_values = [];
+
+ }
+
+ }
+
+ function findMetaRules(){
+
+ metaRuleService.findSomeWithMetaData(view.model.meta_rules).then(function(metaRules){
+
+ view.meta_rules_values = metaRules;
+
+ view.model.meta_rules_values = metaRules;
+
+ });
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/model/edit/metadata/metadata-edit.tpl.html b/old/moon_gui/static/app/model/edit/metadata/metadata-edit.tpl.html
new file mode 100755
index 00000000..2616be1c
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metadata/metadata-edit.tpl.html
@@ -0,0 +1,99 @@
+<div>
+
+ <div class="col-md-4 col-sm-4 col-xs-4">
+ <a class="btn btn-primary" type="button" style="white-space: normal;" ng-click="edit.fromList = !edit.fromList">
+ <span ng-if="!edit.fromList" data-translate="moon.model.metadata.edit.action.list">Add from the list</span>
+ <span ng-if="edit.fromList" data-translate="moon.model.metadata.edit.action.new">Add a new Category</span>
+ </a>
+ </div>
+
+ <div class="col-md-8 col-sm-8 col-xs-8">
+
+ <form name="selectMetaData" ng-if="edit.fromList" class="form-horizontal" role="form" >
+
+ <div class="form-group" >
+
+ <ui-select ng-model="edit.selectedMetaData" name="object">
+
+ <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match>
+ <ui-select-choices repeat="ametaData in edit.list">
+ <div ng-value="ametaData" ng-bind="ametaData.name"></div>
+ </ui-select-choices>
+
+ </ui-select>
+
+ </div>
+
+ <div class="form-group">
+
+ <div class="pull-left col-md-4 col-sm-4 col-xs-4">
+
+ <a href="" ng-disabled="edit.loading || !edit.selectedMetaData" ng-click="edit.deleteMetaData()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span data-translate="moon.model.metadata.edit.action.delete">Delete</span>
+ </a>
+
+ </div>
+
+ <div class="pull-right col-md-7 col-md-offset-1 col-sm-7 col-sm-offset-1 col-xs-7 col-xs-offset-1 ">
+
+ <a href="" ng-disabled="edit.loading || !edit.selectedMetaData" ng-click="edit.addToMetaRule()" class="btn btn-warning" style="white-space: normal;">
+ <span class="glyphicon glyphicon-link"></span>
+ <span data-translate="moon.model.metadata.edit.action.add">Add the selected Category</span>
+ </a>
+
+ </div>
+
+ </div>
+
+ <moon-loader ng-if="edit.loading"></moon-loader>
+
+ </form>
+
+ <form ng-if="!edit.fromList" class="form-horizontal" role="form" name="edit.form">
+
+ <div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}">
+
+ <label for="name" class="col-sm-3 control-label" data-translate="moon.model.metadata.edit.name">Name</label>
+
+ <div class="col-sm-6">
+
+ <input name="name" id="name" class="form-control" type="text" data-ng-model="edit.metaData.name" required />
+
+ <div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid">
+ <small class="error" ng-show="edit.form.name.$error.required" data-translate="moon.model.metadata.edit.check.name.required">Name is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <label for="description" class="col-sm-3 control-label" data-translate="moon.model.metadata.edit.description">Description</label>
+ <div class="col-sm-6">
+ <textarea id="description" name="description" class="form-control" data-ng-model="edit.metaData.description"></textarea>
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <div class="pull-right">
+
+ <a href="" ng-disabled="edit.loading" ng-click="edit.create()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-save"></span>
+ <span data-translate="moon.model.metadata.edit.action.create">Create</span>
+ </a>
+
+ <moon-loader ng-if="edit.loading"></moon-loader>
+
+ </div>
+
+ </div>
+
+ </form>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/model/edit/metadata/metadata-list.tpl.html b/old/moon_gui/static/app/model/edit/metadata/metadata-list.tpl.html
new file mode 100755
index 00000000..30a42dbc
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metadata/metadata-list.tpl.html
@@ -0,0 +1,491 @@
+<div>
+ <!--
+ !shortDisplay allow to display more details than shortDisplay.
+ It will display panels row by row and each panels list have a table with more columns
+ -->
+ <div ng-if="!list.shortDisplay">
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.model.metadata.subject.title">List of associated Subject Categories</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive">
+
+ <table class="table table-striped">
+
+ <thead>
+ <tr>
+ <th data-translate="moon.model.metadata.table.id">Id</th>
+ <th data-translate="moon.model.metadata.table.name">Name</th>
+ <th data-translate="moon.model.metadata.table.description">Description</th>
+ <th ng-if="list.editMode" data-translate="moon.model.metadata.table.action.title"></th>
+ </tr>
+ </thead>
+
+ <moon-loader ng-if="list.loadingCatSub"></moon-loader>
+
+ <tbody ng-if="!list.loadingCatSub && list.getSubjectCategories().length > 0">
+ <tr ng-repeat="(key, value) in list.catSub">
+ <td ng-bind="value.id"></td>
+ <td ng-bind="value.name"></td>
+ <td ng-bind="value.description"></td>
+ <td ng-if="list.editMode">
+
+ <a href="" ng-if="!value.loader" ng-click="list.unMapSub(value)">
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metadata.action.remove">Remove</span>
+ </a>
+
+ <!--<div ng-if="!value.loader" class="dropdown">
+
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.model.metadata.table.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+
+ <ul class="dropdown-menu">
+
+ <li>
+ <a href="" ng-click="list.unMapSub(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metadata.action.remove">Remove</span>
+ </a>
+ </li>
+
+ <li class="divider"></li>
+
+ <li>
+ <a href="" ng-click="list.deleteSub(value)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.model.metadata.table.action.delete">Delete</span>
+ </a>
+ </li>
+
+ </ul>
+
+ </div>-->
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>
+
+ </tr>
+ </tbody>
+
+
+ <tbody ng-if="!list.loadingCatSub && list.catSub.length === 0">
+ <tr>
+ <td data-translate="moon.model.metadata.subject.notFound">There is no Subjects</td>
+ <td></td>
+ <td></td>
+ <td ng-if="list.editMode"></td>
+ </tr>
+ </tbody>
+
+ </table>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div ng-if="list.editMode" class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.model.metadata.subject.add.title">Add a Subject Category</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <moon-meta-data-edit meta-rule="list.metaRule"
+ meta-data-type="list.typeOfSubject"></moon-meta-data-edit>
+
+ </div>
+
+ </div>
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.model.metadata.object.title">List associated of Object Categories</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive">
+
+ <table class="table table-striped">
+
+ <thead>
+ <tr>
+ <th data-translate="moon.model.metadata.table.id">Id</th>
+ <th data-translate="moon.model.metadata.table.name">Name</th>
+ <th data-translate="moon.model.metadata.table.description">Description</th>
+ <th ng-if="list.editMode" data-translate="moon.model.metadata.table.action.title"></th>
+
+ </tr>
+ </thead>
+
+ <moon-loader ng-if="list.loadingCatObj"></moon-loader>
+
+ <tbody ng-if="!list.loadingCatObj && list.catObj.length > 0">
+ <tr ng-repeat="(key, value) in list.catObj">
+ <td ng-bind="value.id"></td>
+ <td ng-bind="value.name"></td>
+ <td ng-bind="value.description"></td>
+ <td ng-if="list.editMode">
+
+ <a href="" ng-if="!value.loader" ng-click="list.unMapObj(value)">
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metadata.action.remove">Remove</span>
+ </a>
+
+
+ <!--<div ng-if="!value.loader" class="dropdown">
+
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.model.metadata.table.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+
+ <ul class="dropdown-menu">
+
+ <li>
+ <a href="" ng-click="list.unMapObj(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metadata.action.remove">Remove</span>
+ </a>
+ </li>
+
+ <li class="divider"></li>
+
+ <li>
+ <a href="" ng-click="list.deleteObj(value)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.model.metadata.table.action.delete">Delete</span>
+ </a>
+ </li>
+
+ </ul>
+
+ </div>-->
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>
+ </tr>
+ </tbody>
+
+ <tbody ng-if="!list.loadingCatObj && list.catObj.length === 0">
+ <tr>
+ <td data-translate="moon.model.metadata.object.notFound">There is no Objects</td>
+ <td></td>
+ <td></td>
+ <td ng-if="list.editMode"></td>
+ </tr>
+ </tbody>
+
+ </table>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div ng-if="list.editMode" class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.model.metadata.object.add.title">Add an Object Category</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <moon-meta-data-edit meta-rule="list.metaRule" meta-data-type="list.typeOfObject"></moon-meta-data-edit>
+
+ </div>
+
+ </div>
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.model.metadata.action.title">List associated of Action Categories</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive">
+
+ <table class="table table-striped">
+
+ <thead>
+ <tr>
+ <th data-translate="moon.model.metadata.table.id">Id</th>
+ <th data-translate="moon.model.metadata.table.name">Name</th>
+ <th data-translate="moon.model.metadata.table.description">Description</th>
+ <th ng-if="list.editMode" data-translate="moon.model.metadata.table.action.title"></th>
+ </tr>
+ </thead>
+
+ <moon-loader ng-if="list.loadingCatAct"></moon-loader>
+
+ <tbody ng-if="!list.loadingCatAct && list.catAct.length > 0">
+ <tr ng-repeat="(key, value) in list.catAct">
+ <td ng-bind="value.id"></td>
+ <td ng-bind="value.name"></td>
+ <td ng-bind="value.description"></td>
+ <td ng-if="list.editMode">
+
+ <a href="" ng-if="!value.loader" ng-click="list.unMapAct(value)">
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metadata.action.remove">Remove</span>
+ </a>
+
+ <!--<div ng-if="!value.loader" class="dropdown">
+
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.model.metadata.table.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+
+ <ul class="dropdown-menu">
+
+ <li>
+ <a href="" ng-click="list.unMapAct(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metadata.action.remove">Remove</span>
+ </a>
+ </li>
+
+ <li class="divider"></li>
+
+ <li>
+ <a href="" ng-click="list.deleteAct(value)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.model.metadata.table.action.delete">Delete</span>
+ </a>
+ </li>
+
+ </ul>
+
+ </div>-->
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>
+ </tr>
+ </tbody>
+
+ <tbody ng-if="!list.loadingCatAct && list.catAct.length === 0">
+ <tr>
+ <td data-translate="moon.model.metadata.action.notFound">There is no Actions</td>
+ <td></td>
+ <td></td>
+ <td ng-if="list.editMode"></td>
+ </tr>
+ </tbody>
+
+ </table>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div ng-if="list.editMode" class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.model.metadata.action.add.title">Add an Action Category</h4>
+
+ </div>
+
+ <div class="panel-body">.
+
+ <moon-meta-data-edit meta-rule="list.metaRule" meta-data-type="list.typeOfAction"></moon-meta-data-edit>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <!--
+ !shortDisplay allow to display less details than shortDisplay.
+ It will display 3 panels on the same row, each panels have a table with on columns (name)
+ -->
+ <div ng-if="list.shortDisplay">
+
+ <div class="row">
+
+ <div class="col-md-4">
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.model.metadata.subject.title">List of associated Subject Categories</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive">
+
+ <table class="table table-striped">
+
+ <thead>
+ <tr>
+ <th data-translate="moon.model.metadata.table.name">Name</th>
+ </tr>
+ </thead>
+
+ <moon-loader ng-if="list.loadingCatSub"></moon-loader>
+
+ <tbody ng-if="!list.loadingCatSub && list.getSubjectCategories().length > 0">
+ <tr ng-repeat="(key, value) in list.catSub">
+ <td ng-bind="value.name"></td>
+ </tr>
+ </tbody>
+
+
+ <tbody ng-if="!list.loadingCatSub && list.catSub.length === 0">
+ <tr>
+ <td data-translate="moon.model.metadata.subject.notFound">There is no Subjects</td>
+ </tr>
+ </tbody>
+
+ </table>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div class="col-md-4">
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.model.metadata.object.title">List associated of Object Categories</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive">
+
+ <table class="table table-striped">
+
+ <thead>
+ <tr>
+ <th data-translate="moon.model.metadata.table.name">Name</th>
+ </tr>
+ </thead>
+
+ <moon-loader ng-if="list.loadingCatObj"></moon-loader>
+
+ <tbody ng-if="!list.loadingCatObj && list.catObj.length > 0">
+ <tr ng-repeat="(key, value) in list.catObj">
+ <td ng-bind="value.name"></td>
+ </tr>
+ </tbody>
+
+ <tbody ng-if="!list.loadingCatObj && list.catObj.length === 0">
+ <tr>
+ <td data-translate="moon.model.metadata.object.notFound">There is no Objects</td>
+ </tr>
+ </tbody>
+
+ </table>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div class="col-md-4">
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.model.metadata.action.title">List associated of Action Categories</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive">
+
+ <table class="table table-striped">
+
+ <thead>
+ <tr>
+ <th data-translate="moon.model.metadata.table.name">Name</th>
+ </tr>
+ </thead>
+
+ <moon-loader ng-if="list.loadingCatAct"></moon-loader>
+
+ <tbody ng-if="!list.loadingCatAct && list.catAct.length > 0">
+ <tr ng-repeat="(key, value) in list.catAct">
+ <td ng-bind="value.name"></td>
+ </tr>
+ </tbody>
+
+ <tbody ng-if="!list.loadingCatAct && list.catAct.length === 0">
+ <tr>
+ <td data-translate="moon.model.metadata.action.notFound">There is no Actions</td>
+ </tr>
+ </tbody>
+
+ </table>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/model/edit/metadata/metadata.edit.dir.js b/old/moon_gui/static/app/model/edit/metadata/metadata.edit.dir.js
new file mode 100755
index 00000000..ab79b5db
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metadata/metadata.edit.dir.js
@@ -0,0 +1,332 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonMetaDataEdit', moonMetaDataEdit);
+
+ moonMetaDataEdit.$inject = [];
+
+ function moonMetaDataEdit() {
+
+ return {
+ templateUrl : 'html/model/edit/metadata/metadata-edit.tpl.html',
+ bindToController : true,
+ controller : moonMetaDataEditController,
+ controllerAs : 'edit',
+ scope : {
+ //Type can be 'ACTION', 'OBJECT', 'SUBJECT'
+ metaDataType: '=',
+ metaRule : '='
+ },
+ restrict : 'E',
+ replace : true
+ };
+ }
+
+ angular
+ .module('moon')
+ .controller('moonMetaDataEditController', moonMetaDataEditController);
+
+ moonMetaDataEditController.$inject = ['$scope', 'metaDataService', 'META_DATA_CST', 'alertService',
+ '$translate', 'formService', 'metaRuleService', 'utilService'];
+
+ function moonMetaDataEditController($scope, metaDataService, META_DATA_CST, alertService,
+ $translate, formService, metaRuleService, utilService) {
+
+ var edit = this;
+
+ edit.metaDataType = $scope.edit.metaDataType;
+ edit.metaRule = $scope.edit.metaRule;
+
+ edit.fromList = true;
+
+ edit.form = {};
+
+ edit.metaData = { name: null, description: null};
+
+ edit.list = [];
+
+ edit.create = createMetaData;
+ edit.addToMetaRule = addToMetaRule;
+ edit.deleteMetaData = deleteMetaData;
+
+ activate();
+
+ /*
+ *
+ */
+
+ function activate(){
+
+ switch(edit.metaDataType){
+
+ case META_DATA_CST.TYPE.SUBJECT:
+
+ metaDataService.subject.findAllWithCallback(callBackList);
+ break;
+
+ case META_DATA_CST.TYPE.OBJECT:
+
+ metaDataService.object.findAllWithCallback(callBackList);
+ break;
+
+ case META_DATA_CST.TYPE.ACTION:
+
+ metaDataService.action.findAllWithCallback(callBackList);
+ break;
+
+ default :
+
+ edit.list = [];
+ break;
+
+ }
+
+ function callBackList(list){
+
+ edit.list = list;
+
+ }
+
+ }
+
+ /**
+ * Add
+ */
+
+ function addToMetaRule(){
+
+ if(!edit.selectedMetaData){
+
+ return;
+
+ }
+
+ var metaRuleToSend = angular.copy(edit.metaRule);
+
+ switch(edit.metaDataType){
+
+ case META_DATA_CST.TYPE.SUBJECT:
+
+ metaRuleToSend.subject_categories.push(edit.selectedMetaData.id);
+ break;
+
+ case META_DATA_CST.TYPE.OBJECT:
+
+ metaRuleToSend.object_categories.push(edit.selectedMetaData.id);
+ break;
+
+ case META_DATA_CST.TYPE.ACTION:
+
+ metaRuleToSend.action_categories.push(edit.selectedMetaData.id);
+ break;
+ }
+
+ metaRuleService.update(metaRuleToSend, updateMetaRuleSuccess, updateMetaRuleError);
+
+ function updateMetaRuleSuccess(data){
+
+ $translate('moon.model.metarules.update.success', { metaRuleName: metaRuleToSend.name }).then( function(translatedValue) {
+
+ alertService.alertSuccess(translatedValue);
+
+ });
+
+ metaRuleToSend = utilService.transformOne(data, 'meta_rules');
+
+ angular.copy(metaRuleToSend, edit.metaRule)
+
+ $scope.$emit('event:updateMetaRuleFromMetaDataAddSuccess', edit.metaRule);
+
+ stopLoading();
+
+ }
+
+ function updateMetaRuleError(reason){
+
+ $translate('moon.model.metarules.update.error', { metaRuleName: metaRuleToSend.name, reason: reason.message}).then( function(translatedValue) {
+
+ alertService.alertError(translatedValue);
+
+ });
+
+ stopLoading();
+
+ }
+
+ }
+
+ /**
+ * Create
+ */
+
+ function createMetaData() {
+
+ if(formService.isInvalid(edit.form)) {
+
+ formService.checkFieldsValidity(edit.form);
+
+ } else {
+
+ startLoading();
+
+ var metaDataToSend = angular.copy(edit.metaData);
+
+ switch(edit.metaDataType){
+
+ case META_DATA_CST.TYPE.SUBJECT:
+
+ metaDataService.subject.add(metaDataToSend, createSuccess, createError);
+ break;
+
+ case META_DATA_CST.TYPE.OBJECT:
+
+ metaDataService.object.add(metaDataToSend, createSuccess, createError);
+ break;
+
+ case META_DATA_CST.TYPE.ACTION:
+
+ metaDataService.action.add(metaDataToSend, createSuccess, createError);
+ break;
+ }
+
+ }
+
+ function createSuccess(data) {
+
+ var created = {};
+
+ switch(edit.metaDataType){
+
+ case META_DATA_CST.TYPE.SUBJECT:
+
+ created = utilService.transformOne(data, 'subject_categories');
+ break;
+
+ case META_DATA_CST.TYPE.OBJECT:
+
+ created = utilService.transformOne(data, 'object_categories');
+ break;
+
+ case META_DATA_CST.TYPE.ACTION:
+
+ created = utilService.transformOne(data, 'action_categories');
+ break;
+ }
+
+ $translate('moon.model.metadata.edit.create.success', { name: created.name }).then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ stopLoading();
+
+ edit.list.push(created);
+
+ displayList();
+
+ }
+
+ function createError(reason) {
+
+ $translate('moon.model.metadata.edit.create.error', { name: metaDataToSend.name }).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ stopLoading();
+
+ }
+
+ }
+
+ function deleteMetaData(){
+
+ if(!edit.selectedMetaData){
+
+ return;
+
+ }
+
+ startLoading();
+
+ var metaDataToDelete = angular.copy(edit.selectedMetaData);
+
+ switch(edit.metaDataType){
+ case META_DATA_CST.TYPE.SUBJECT:
+
+ metaDataService.subject.delete(metaDataToDelete, deleteSuccess, deleteError);
+ break;
+
+ case META_DATA_CST.TYPE.OBJECT:
+
+ metaDataService.object.delete(metaDataToDelete, deleteSuccess, deleteError);
+ break;
+
+ case META_DATA_CST.TYPE.ACTION:
+
+ metaDataService.action.delete(metaDataToDelete, deleteSuccess, deleteError);
+ break;
+ }
+
+
+ function deleteSuccess(data) {
+
+ $translate('moon.model.metadata.edit.delete.success', { name: metaDataToDelete.name }).then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ metaRuleService.findOneWithMetaData(edit.metaRule.id).then( function(metaRule){
+
+ angular.copy(metaRule, edit.metaRule)
+
+ cleanSelectedValue();
+
+ activate();
+
+ stopLoading();
+
+ $scope.$emit('event:deleteMetaDataFromMetaDataAddSuccess', edit.metaRule);
+
+ });
+
+ }
+
+ function deleteError(reason) {
+
+ $translate('moon.model.metadata.edit.delete.error', { name: metaDataToDelete.name }).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ stopLoading();
+
+ }
+ }
+
+ function cleanSelectedValue(){
+
+ delete edit.selectedMetaData;
+
+ }
+
+ function startLoading(){
+
+ edit.loading = true;
+
+ }
+
+ function stopLoading(){
+
+ edit.loading = false;
+
+ }
+
+ function displayList(){
+
+ edit.fromList = true;
+
+ }
+
+ }
+
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/model/edit/metadata/metadata.list.dir.js b/old/moon_gui/static/app/model/edit/metadata/metadata.list.dir.js
new file mode 100755
index 00000000..305192b6
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metadata/metadata.list.dir.js
@@ -0,0 +1,374 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonMetaDataList', moonMetaDataList);
+
+ moonMetaDataList.$inject = [];
+
+ function moonMetaDataList() {
+
+ return {
+ templateUrl : 'html/model/edit/metadata/metadata-list.tpl.html',
+ bindToController : true,
+ controller : moonMetaDataListController,
+ controllerAs : 'list',
+ scope : {
+ metaRule: '=',
+ editMode: '=',
+ // shortDisplay : boolean value
+ //shortDisplay: '='
+ },
+ restrict : 'E',
+ replace : true
+ };
+ }
+
+ angular
+ .module('moon')
+ .controller('moonMetaDataListController', moonMetaDataListController);
+
+ moonMetaDataListController.$inject = ['$scope', '$rootScope', 'metaDataService', '$translate', 'alertService', 'metaRuleService', 'META_DATA_CST', 'utilService'];
+
+ function moonMetaDataListController($scope, $rootScope, metaDataService, $translate, alertService, metaRuleService, META_DATA_CST, utilService){
+
+ var list = this;
+
+ list.metaRule = $scope.list.metaRule;
+ list.editMode = $scope.list.editMode;
+ list.shortDisplay = $scope.list.shortDisplay;
+
+ list.typeOfSubject = META_DATA_CST.TYPE.SUBJECT;
+ list.typeOfObject = META_DATA_CST.TYPE.OBJECT;
+ list.typeOfAction = META_DATA_CST.TYPE.ACTION;
+
+ list.unMapSub = unMapSub;
+ list.unMapObj = unMapObj;
+ list.unMapAct = unMapAct;
+
+ // list.deleteSub = deleteSub;
+ // list.deleteObj = deleteObj;
+ // list.deleteAct = deleteAct;
+
+ list.getSubjectCategories = getSubjectCategories;
+ list.getObjectCategories = getObjectCategories;
+ list.getActionCategories = getActionCategories;
+
+ activate();
+
+ function activate(){
+
+ manageSubjectCategories();
+
+ manageObjectCategories();
+
+ manageActionCategories();
+
+ }
+
+ var rootListeners = {
+
+ 'event:updateMetaRuleFromMetaDataAddSuccess': $rootScope.$on('event:updateMetaRuleFromMetaDataAddSuccess', updateMetaRuleCategories),
+
+ 'event:deleteMetaDataFromMetaDataAddSuccess': $rootScope.$on('event:deleteMetaDataFromMetaDataAddSuccess', deleteMetaRuleCategories)
+
+ };
+
+ for (var unbind in rootListeners) {
+ $scope.$on('$destroy', rootListeners[unbind]);
+ }
+
+ function manageSubjectCategories(){
+
+ list.loadingCatSub = true;
+
+ metaDataService.subject.findSomeWithCallback(list.metaRule.subject_categories, function(categories){
+
+ list.catSub = categories;
+ list.loadingCatSub = false;
+
+ });
+ }
+
+ function manageObjectCategories(){
+
+ list.loadingCatObj = true;
+
+ metaDataService.object.findSomeWithCallback(list.metaRule.object_categories, function(categories){
+
+ list.catObj = categories;
+ list.loadingCatObj = false;
+
+ });
+
+ }
+
+ function manageActionCategories(){
+
+ list.loadingCatAct = true;
+
+ metaDataService.action.findSomeWithCallback(list.metaRule.action_categories, function(categories){
+
+ list.catAct = categories;
+ list.loadingCatAct = false;
+
+ });
+
+ }
+
+
+ /**
+ * UnMap
+ */
+
+ function unMapSub(subject){
+
+ subject.loader = true;
+
+ var metaRuleToSend = angular.copy(list.metaRule);
+
+ metaRuleToSend.subject_categories = _.without(metaRuleToSend.subject_categories, subject.id);
+
+ metaRuleService.update(metaRuleToSend, updateMetaRuleSuccess, updateMetaRuleError);
+
+ function updateMetaRuleSuccess(data){
+
+ $translate('moon.model.metarules.update.success', { metaRuleName: list.metaRule.name }).then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ metaRuleToSend = metaRuleService.findMetaDataFromMetaRule(utilService.transformOne(data, 'meta_rules'));
+ angular.copy(metaRuleToSend, list.metaRule);
+
+ activate();
+
+ subject.loader = false;
+
+ }
+
+ function updateMetaRuleError(reason){
+
+ $translate('moon.model.metarules.update.error', { metaRuleName: list.metaRule.name, reason: reason.message}).then( function(translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ subject.loader = false;
+
+ }
+
+ }
+
+ function unMapObj(object){
+
+ object.loader = true;
+
+ var metaRuleToSend = angular.copy(list.metaRule);
+
+ metaRuleToSend.object_categories = _.without(metaRuleToSend.object_categories, object.id);
+
+ metaRuleService.update(metaRuleToSend, updateMetaRuleSuccess, updateMetaRuleError);
+
+ function updateMetaRuleSuccess(data){
+
+ $translate('moon.model.metarules.update.success', { metaRuleName: list.metaRule.name }).then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ metaRuleToSend = metaRuleService.findMetaDataFromMetaRule(utilService.transformOne(data, 'meta_rules'));
+ angular.copy(metaRuleToSend, list.metaRule);
+
+ activate();
+
+ object.loader = false;
+
+ }
+
+ function updateMetaRuleError(reason){
+
+ $translate('moon.model.metarules.update.error', { metaRuleName: list.metaRule.name, reason: reason.message}).then( function(translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ object.loader = false;
+
+ }
+
+ }
+
+ function unMapAct(action){
+
+ action.loader = true;
+
+ var metaRuleToSend = angular.copy(list.metaRule);
+
+ metaRuleToSend.action_categories = _.without(metaRuleToSend.action_categories, action.id);
+
+ metaRuleService.update(metaRuleToSend, updateMetaRuleSuccess, updateMetaRuleError);
+
+ function updateMetaRuleSuccess(data){
+
+ $translate('moon.model.metarules.update.success', { metaRuleName: list.metaRule.name }).then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ metaRuleToSend = metaRuleService.findMetaDataFromMetaRule(utilService.transformOne(data, 'meta_rules'));
+ angular.copy(metaRuleToSend, list.metaRule);
+
+ activate();
+
+ action.loader = false;
+
+ }
+
+ function updateMetaRuleError(reason){
+
+ $translate('moon.model.metarules.update.error', { metaRuleName: list.metaRule.name, reason: reason.message}).then( function(translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ action.loader = false;
+
+ }
+
+ }
+
+ // /**
+ // * Delete
+ // */
+ //
+ // function deleteSub(subject){
+ //
+ // subject.loader = true;
+ //
+ // metaDataService.subject.delete(subject, deleteSubSuccess, deleteSubError);
+ //
+ // function deleteSubSuccess(data){
+ //
+ // $translate('moon.model.metadata.subject.delete.success', { subjectName: subject.name }).then( function(translatedValue) {
+ // alertService.alertSuccess(translatedValue);
+ // });
+ //
+ // removeSubFromSubList(subject);
+ //
+ // subject.loader = false;
+ //
+ // }
+ //
+ // function deleteSubError(reason){
+ //
+ // $translate('moon.model.metadata.subject.delete.error',
+ // { subjectName: subject.name, reason: reason.message}).then( function(translatedValue) {
+ // alertService.alertError(translatedValue);
+ // });
+ //
+ // subject.loader = false;
+ //
+ // }
+ // }
+ //
+ // function deleteObj(object){
+ //
+ // object.loader = true;
+ //
+ // metaDataService.object.delete(object, deleteObjSuccess, deleteObjError);
+ //
+ // function deleteObjSuccess(data){
+ //
+ // $translate('moon.model.metadata.object.delete.success', { objectName: object.name }).then( function(translatedValue) {
+ // alertService.alertSuccess(translatedValue);
+ // });
+ //
+ // removeObjFromObjList(object);
+ // /*list.catSub = metaDataService.subject.findSome(list.metaRule.subject_categories);
+ // list.catObj = metaDataService.object.findSome(list.metaRule.object_categories);
+ // list.catAct = metaDataService.action.findSome(list.metaRule.action_categories);*/
+ //
+ // object.loader = false;
+ //
+ // }
+ //
+ // function deleteObjError(reason){
+ //
+ // $translate('moon.model.metadata.object.delete.error', { objectName: object.name, reason: reason.message}).then( function(translatedValue) {
+ // alertService.alertError(translatedValue);
+ // });
+ //
+ // object.loader = false;
+ // }
+ // }
+ //
+ // function deleteAct(action){
+ //
+ // action.loader = true;
+ //
+ // metaDataService.action.delete(action, deleteActSuccess, deleteActError);
+ //
+ // function deleteActSuccess(data){
+ //
+ // $translate('moon.model.metadata.action.delete.success', { actionName: action.name }).then( function(translatedValue) {
+ // alertService.alertSuccess(translatedValue);
+ // });
+ //
+ // removeActFromActList(action);
+ //
+ // action.loader = false;
+ //
+ // }
+ //
+ // function deleteActError(reason){
+ //
+ // $translate('moon.model.metadata.action.delete.error', { actionName: action.name, reason: reason.message}).then( function(translatedValue) {
+ // alertService.alertError(translatedValue);
+ // });
+ //
+ // action.loader = false;
+ //
+ // }
+ // }
+
+ function getSubjectCategories(){
+ return list.catSub ? list.catSub : [];
+ }
+
+ function getObjectCategories(){
+ return list.catObj ? list.catObj : [];
+ }
+
+ function getActionCategories(){
+ return list.catAct ? list.catAct : [];
+ }
+
+ // function removeSubFromSubList(subject){
+ // list.catSub = _.without(list.catSub, subject);
+ // }
+ //
+ // function removeObjFromObjList(object){
+ // list.catObj = _.without(list.catObj, object);
+ // }
+ //
+ // function removeActFromActList(action){
+ // list.catAct = _.without(list.catAct, action);
+ // }
+
+ function updateMetaRuleCategories( event, metaRule){
+
+ list.metaRule = metaRule;
+
+ activate();
+
+ }
+
+
+ function deleteMetaRuleCategories( event, metaRule){
+
+ list.metaRule = metaRule;
+
+ activate();
+
+ }
+
+ }
+
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-add.tpl.html b/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-add.tpl.html
new file mode 100755
index 00000000..a721e6d0
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-add.tpl.html
@@ -0,0 +1,50 @@
+<div class="row">
+
+ <form class="form-horizontal" role="form" name="add.form">
+
+ <div class="form-group" ng-class="{'has-error': add.form.name.$invalid && add.form.name.$dirty}">
+
+ <label for="name" class="col-sm-3 control-label" data-translate="moon.model.metarules.add.form.name">Name</label>
+
+ <div class="col-sm-6">
+
+ <input name="name" id="name" class="form-control" type="text" data-ng-model="add.metaRule.name" required />
+
+ <div class="help-block" ng-show="add.form.name.$dirty && add.form.name.$invalid">
+ <small class="error" ng-show="add.form.name.$error.required" data-translate="moon.model.metarules.add.check.name.required">Name is required</small>
+ </div>
+
+ </div>
+ </div>
+
+ <div class="form-group">
+
+ <label for="description" class="col-sm-3 control-label" data-translate="moon.model.metarules.add.form.description">Description</label>
+ <div class="col-sm-6">
+ <textarea id="description" name="description" class="form-control" data-ng-model="add.metaRule.description"></textarea>
+ </div>
+
+ </div>
+
+
+ <div class="form-group">
+
+ <div class="col-sm-8">
+
+ <div class="pull-right">
+
+ <a href="" ng-disabled="add.loading" ng-click="add.create()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-save"></span>
+ <span data-translate="moon.model.metarules.add.action.create">Create</span>
+ </a>
+
+ <moon-loader ng-if="add.loading"></moon-loader>
+
+ </div>
+
+ </div>
+
+ </div>
+ </form>
+
+</div>
diff --git a/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-map.tpl.html b/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-map.tpl.html
new file mode 100755
index 00000000..1830204b
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-map.tpl.html
@@ -0,0 +1,102 @@
+<div ng-controller="moonMetaRulesMapController as map" class="modal" tabindex="-1" data-role="MapMetaRules">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.model.metarules.map.title"></h4>
+
+ </div>
+
+ <div class="modal-body">
+
+ <div class="row">
+
+ <div class="col-sm-3">
+
+ <button class="btn btn-primary" style="white-space: normal;" ng-click="map.addMetaRuleToList = !map.addMetaRuleToList">
+
+ <span ng-if="!map.addMetaRuleToList" data-translate="moon.model.metarules.map.action.new">Add a new Meta Rule</span>
+ <span ng-if="map.addMetaRuleToList" data-translate="moon.model.metarules.map.action.list">List of Meta Rules</span>
+
+ </button>
+
+ </div>
+
+ <div class="col-sm-9">
+
+ <form class="form-horizontal" role="form" name="map.form">
+
+ <div class="form-group" ng-if="!map.addMetaRuleToList">
+
+ <label class="col-sm-3 control-label" data-translate="moon.model.metarules.map.form.list">List of Meta Rule</label>
+
+ <div class="col-sm-9">
+
+ <ui-select ng-model="map.selectedMetaRule" name="object">
+
+ <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match>
+ <ui-select-choices repeat="ametaRule in map.metaRules">
+ <div ng-value="ametaRule" ng-bind="ametaRule.name"></div>
+ </ui-select-choices>
+
+ </ui-select>
+
+ </div>
+
+ </div>
+
+ <div class="form-group" ng-if="!map.addMetaRuleToList">
+
+ <moon-loader ng-if="map.metaRulesLoading || map.mappingLoading" ></moon-loader>
+
+ <div class="col-sm-5">
+ <a href="" ng-disabled="map.metaRulesLoading || map.mappingLoading || !map.selectedMetaRule" ng-click="map.deleteMetaRule()" class="btn btn-warning" style="white-space: normal;">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span data-translate="moon.model.metarules.map.action.delete">Delete the selected Meta Rule</span>
+ </a>
+ </div>
+
+ <div class="col-sm-5 col-sm-offset-2">
+ <a href="" ng-disabled="map.metaRulesLoading || map.mappingLoading || !map.selectedMetaRule" ng-click="map.mapToModel()" class="btn btn-warning" style="white-space: normal;">
+ <span class="glyphicon glyphicon-link"></span>
+ <span data-translate="moon.model.metarules.map.action.add">Add the selected Meta Rule</span>
+ </a>
+ </div>
+
+ </div>
+
+ <div class="form-group" ng-if="map.addMetaRuleToList">
+
+ <moon-meta-rules-add></moon-meta-rules-add>
+
+ </div>
+
+ </form>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div class="modal-footer">
+
+ <div class="btn-toolbar" style="float: right;">
+
+ <a href="" ng-click="$hide()" class="btn btn-default">
+ <span data-translate="moon.model.metarules.add.action.cancel">Cancel</span>
+ </a>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ </div>
+
+</div>
diff --git a/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-unmap.tpl.html b/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-unmap.tpl.html
new file mode 100755
index 00000000..bb02aba2
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules-unmap.tpl.html
@@ -0,0 +1,35 @@
+<div ng-controller="MetaRulesUnMapController as unmap" class="modal" tabindex="-1" data-role="modalUnMapMetaRule">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.model.metarules.unmap.title"></h4>
+ </div>
+
+ <div class="modal-body">
+ <span data-translate="moon.model.metarules.unmap.content" data-translate-values="{ modelName: unmap.model.name, metaRuleName: unmap.metaRule.name }"></span>
+ </div>
+
+ <div class="modal-footer">
+
+ <div class="btn-toolbar" style="float: right;">
+ <a href="" ng-click="$hide()" class="btn btn-default">
+ <span data-translate="moon.model.metarules.unmap.action.cancel">Cancel</span>
+ </a>
+ <a href="" ng-disabled="unmap.unMappingLoading" ng-click="unmap.unmap()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span data-translate="moon.model.metarules.unmap.action.unmap">Unmap</span>
+ </a>
+ <moon-loader ng-if="unmap.unMappingLoading" ></moon-loader>
+ </div>
+
+ </div>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.controller.add.js b/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.controller.add.js
new file mode 100755
index 00000000..a95951fa
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.controller.add.js
@@ -0,0 +1,99 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonMetaRulesAdd', moonMetaRulesAdd);
+
+ moonMetaRulesAdd.$inject = [];
+
+ function moonMetaRulesAdd() {
+
+ return {
+ templateUrl : 'html/model/edit/metarules/action/mapping/metarules-add.tpl.html',
+ bindToController : true,
+ controller : moonMetaRulesAddController,
+ controllerAs : 'add',
+ scope : {
+ metaRules : '='
+ },
+ restrict : 'E',
+ replace : true
+ };
+ }
+
+
+ angular
+ .module('moon')
+ .controller('moonMetaRulesAddController', moonMetaRulesAddController);
+
+ moonMetaRulesAddController.$inject = ['$scope', 'metaRuleService', 'alertService', '$translate', 'formService', 'utilService'];
+
+ function moonMetaRulesAddController($scope, metaRuleService, alertService, $translate, formService, utilService) {
+
+ var add = this;
+
+ /*
+ *
+ */
+
+ add.laoading = false;
+
+ add.form = {};
+
+ add.metaRule = { name: null, description: null, subject_categories : [], object_categories : [], action_categories : [] };
+
+ add.create = createMetaRule;
+
+ activate();
+
+ function activate(){
+
+ }
+
+ function createMetaRule() {
+
+ if(formService.isInvalid(add.form)) {
+
+ formService.checkFieldsValidity(add.form);
+
+ } else {
+
+ add.loading = true;
+
+ metaRuleService.data.create({}, add.metaRule, createSuccess, createError);
+
+ }
+
+ function createSuccess(data) {
+
+ var createdMetaRule = utilService.transformOne(data, 'meta_rules');
+
+ $translate('moon.model.metarules.add.success', { metaRuleName: createdMetaRule.name }).then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ add.loading = false;
+
+ $scope.$emit('event:metaRuleCreatedSuccess', createdMetaRule);
+
+ }
+
+ function createError(reason) {
+
+ $translate('moon.model.metarules.add.error', { metaRuleName: add.metaRule.name }).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ add.loading = false;
+
+ $scope.$emit('event:metaRuleCreatedError', add.project);
+
+ }
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.map.controller.js b/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.map.controller.js
new file mode 100755
index 00000000..cf9ba06c
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.map.controller.js
@@ -0,0 +1,213 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('moonMetaRulesMapController', moonMetaRulesMapController);
+
+ moonMetaRulesMapController.$inject = ['$scope', '$rootScope', 'alertService', '$translate', 'formService', 'metaRuleService', 'modelService', 'utilService'];
+
+ function moonMetaRulesMapController($scope, $rootScope, alertService, $translate, formService, metaRuleService, modelService, utilService ) {
+
+ var map = this;
+
+ /*
+ *
+ */
+
+ map.metaRules = [];
+
+ map.model = $scope.model;
+
+ map.addMetaRuleToList = false;
+
+ map.mapToModel = mapToModel;
+
+ map.deleteMetaRule = deleteMetaRule;
+
+ activate();
+
+ function activate() {
+
+ resolveMetaRules();
+
+ }
+
+ /*
+ * ---- events
+ */
+ var rootListeners = {
+
+ 'event:metaRuleCreatedSuccess': $rootScope.$on('event:metaRuleCreatedSuccess', metaRuleCreatedSuccess),
+ 'event:metaRuleCreatedError': $rootScope.$on('event:metaRuleCreatedError', metaRuleCreatedError)
+
+ };
+
+ for (var unbind in rootListeners) {
+ $scope.$on('$destroy', rootListeners[unbind]);
+ }
+
+
+ /*
+ *
+ */
+
+ function resolveMetaRules() {
+
+ map.metaRulesLoading = true;
+
+ metaRuleService.findAllWithCallback(
+ function(metaRules){
+ map.metaRules = metaRules;
+ map.metaRulesLoading = false;
+ }
+ );
+
+ }
+
+ function mapToModel() {
+
+ if (formService.isInvalid(map.form)) {
+
+ formService.checkFieldsValidity(map.form);
+
+ } else {
+
+ map.mappingLoading = true;
+
+ var modelToSend = angular.copy(map.model);
+
+ modelToSend.meta_rules.push(map.selectedMetaRule.id);
+
+ modelService.update(modelToSend, mapSuccess, mapError);
+
+ }
+
+ function mapSuccess(data) {
+
+ var modelReceived = utilService.transformOne(data, 'models');
+
+ metaRuleService.findSomeWithMetaData(modelReceived.meta_rules).then(function(metaRules){
+
+ modelReceived.meta_rules_values = metaRules;
+
+ $translate('moon.model.metarules.map.success', {
+
+ modelName: modelReceived.name,
+ metaRuleName: map.selectedMetaRule.name
+
+ }).then(function (translatedValue) {
+
+ alertService.alertSuccess(translatedValue);
+
+ });
+
+ map.mappingLoading = false;
+
+ $scope.$emit('event:metaRuleMapToModelSuccess', modelReceived);
+
+ });
+
+ }
+
+ function mapError(response) {
+
+ $translate('moon.model.metarules.map.error', {
+
+ modelName: map.model.name,
+ metaRuleName: map.selectedMetaRule.name
+
+ }).then(function (translatedValue) {
+
+ alertService.alertError(translatedValue);
+
+ });
+
+ map.mappingLoading = false;
+
+ }
+ }
+
+ function cleanSelectedValue(){
+
+ delete map.selectedMetaRule;
+
+ }
+
+
+ function deleteMetaRule(){
+
+ if(!map.selectedMetaRule){
+
+ return;
+
+ }
+
+ map.mappingLoading = true;
+
+ var metaRuleTodelete = angular.copy(map.selectedMetaRule);
+
+ metaRuleService.delete(metaRuleTodelete, deleteSuccess, deleteError);
+
+ function deleteSuccess(data) {
+
+ $translate('moon.model.metarules.delete.success', { metaRuleName: metaRuleTodelete.name }).then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ cleanSelectedValue();
+
+ map.mappingLoading = false;
+
+ resolveMetaRules();
+
+ // later this event will have to be catch, because the model can use the deleted MetaRule
+ $scope.$emit('event:deleteMetaRule', metaRuleTodelete);
+
+ }
+
+ function deleteError(reason) {
+
+ $translate('moon.model.metarules.delete.error', { metaRuleName: metaRuleTodelete.name }).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ map.mappingLoading = false;
+
+ }
+ }
+
+
+
+
+
+
+ /**
+ * This function will add a metaRule to the current list of metaRules
+ * @param event
+ * @param metaRule {...} metaRule to add
+ */
+ function metaRuleCreatedSuccess(event, metaRule) {
+
+ map.metaRules.push(metaRule);
+ showList();
+
+ }
+
+ /**
+ * This function hide the add MetaRule Modal
+ * @param event
+ */
+ function metaRuleCreatedError(event) {
+
+ }
+
+ function showList(){
+ map.addMetaRuleToList = false;
+ }
+
+ }
+
+
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.unmap.controller.js b/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.unmap.controller.js
new file mode 100755
index 00000000..30f32d51
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metarules/action/mapping/metarules.unmap.controller.js
@@ -0,0 +1,74 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('MetaRulesUnMapController', MetaRulesUnMapController);
+
+ MetaRulesUnMapController.$inject = ['$scope', '$translate', 'alertService', 'modelService'];
+
+ function MetaRulesUnMapController($scope, $translate, alertService, modelService) {
+
+ var unmap = this;
+
+ /*
+ *
+ */
+
+ unmap.model = $scope.model;
+ unmap.metaRule = $scope.metaRule;
+
+ unmap.unMappingLoading = false;
+
+ unmap.unmap = unMapModelToMetaRule;
+
+ /*
+ *
+ */
+
+ function unMapModelToMetaRule() {
+
+ unmap.unMappingLoading = true;
+
+ var modelToUpdate = angular.copy(unmap.model);
+
+ modelToUpdate.meta_rules = _.without(modelToUpdate.meta_rules, unmap.metaRule.id);
+
+ modelService.update(modelToUpdate, unMapSuccess, unMapError);
+
+ function unMapSuccess(data) {
+
+ $translate('moon.model.metarules.unmap.success', { modelName: unmap.model.name, metaRuleName: unmap.metaRule.name })
+ .then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ unmap.unMappingLoading = false;
+
+ $scope.$emit('event:metaRuleUnMappedToModelSuccess', modelToUpdate);
+
+ }
+
+ function unMapError(reason) {
+
+ $translate('moon.model.metarules.unmap.error', { modelName: unmap.model.name, metaRuleName: unmap.metaRule.name })
+ .then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ unmap.unMappingLoading = false;
+
+ $scope.$emit('event:metaRuleUnMappedToModelError');
+
+ }
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/model/edit/metarules/action/metarules-edit-basic.tpl.html b/old/moon_gui/static/app/model/edit/metarules/action/metarules-edit-basic.tpl.html
new file mode 100755
index 00000000..b6136195
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metarules/action/metarules-edit-basic.tpl.html
@@ -0,0 +1,67 @@
+<div class="row">
+
+ <form class="form-horizontal" role="form" name="edit.form">
+
+ <div class="form-group">
+
+ <label for="id" class="col-sm-3 control-label" data-translate="moon.model.metarules.edit.basic.form.id">Id</label>
+
+ <div class="col-sm-6">
+
+ <input name="id" id="id" disabled class="form-control" type="text" data-ng-model="edit.metaRuleToEdit.id" required />
+
+ </div>
+
+ </div>
+
+ <div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}">
+
+ <label for="name" class="col-sm-3 control-label" data-translate="moon.model.metarules.edit.basic.form.name">Name</label>
+
+ <div class="col-sm-6">
+
+ <input name="name" id="name" class="form-control" type="text" data-ng-model="edit.metaRuleToEdit.name" required />
+
+ <div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid">
+ <small class="error" ng-show="edit.form.name.$error.required" data-translate="moon.model.metarules.edit.basic.check.name.required">Name is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <label for="description" class="col-sm-3 control-label" data-translate="moon.model.metarules.edit.basic.form.description">Description</label>
+ <div class="col-sm-6">
+ <textarea id="description" name="description" class="form-control" data-ng-model="edit.metaRuleToEdit.description"></textarea>
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <div class="col-sm-2 col-sm-offset-3">
+
+ <a href="" ng-disabled="edit.loading" ng-click="edit.init()" class="btn btn-default">
+ <span data-translate="moon.model.metarules.edit.basic.action.init">Init</span>
+ </a>
+
+ </div>
+
+ <div class="col-sm-4 col-sm-offset-2">
+
+ <a href="" ng-disabled="edit.loading" ng-click="edit.editMetaRule()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-save"></span>
+ <span data-translate="moon.model.metarules.edit.basic.action.update">Update</span>
+ </a>
+
+ <moon-loader ng-if="edit.loading"></moon-loader>
+
+ </div>
+
+ </div>
+
+ </form>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/model/edit/metarules/action/metarules-edit.tpl.html b/old/moon_gui/static/app/model/edit/metarules/action/metarules-edit.tpl.html
new file mode 100755
index 00000000..7b074448
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metarules/action/metarules-edit.tpl.html
@@ -0,0 +1,62 @@
+<div ng-controller="MetaRulesEditController as edit" class="modal" tabindex="-1" data-role="modalViewProject">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.model.metarules.edit.title" data-translate-values="{metaRuleName: edit.metaRule.name}"></h4>
+ </div>
+
+ <div class="modal-body">
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4>
+ <span data-translate="moon.model.edit.basic.title" >Basic Information</span>
+ <a href="" ng-click="edit.editBasic = !edit.editBasic">
+ <span data-translate="moon.model.metarules.edit.update">Update</span>
+ <span class="glyphicon glyphicon-cog"></span>
+ </a>
+ </h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div ng-if="edit.editBasic">
+ <moon-meta-rules-edit-basic meta-rule="edit.metaRule"></moon-meta-rules-edit-basic>
+ </div>
+
+ <div ng-if="!edit.editBasic">
+ <dl class="dl-horizontal">
+ <dt>Id</dt>
+ <dd ng-bind="edit.metaRule.id"></dd>
+ <dt>Name</dt>
+ <dd ng-bind="edit.metaRule.name"></dd>
+ <dt>Description</dt>
+ <dd ng-bind="edit.metaRule.description"></dd>
+ </dl>
+ </div>
+ </div>
+
+ </div>
+
+ <moon-meta-data-list edit-mode="true" meta-rule="edit.metaRule"></moon-meta-data-list>
+
+ </div>
+
+ <div class="modal-footer top10">
+ <div class="btn-toolbar" style="float: right;">
+ <button ng-click="$hide()" class="btn btn-default" data-translate="moon.model.view.action.close">Close</button>
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+
+</div>
diff --git a/old/moon_gui/static/app/model/edit/metarules/action/metarules.controller.edit.js b/old/moon_gui/static/app/model/edit/metarules/action/metarules.controller.edit.js
new file mode 100755
index 00000000..de6965d0
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metarules/action/metarules.controller.edit.js
@@ -0,0 +1,49 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('MetaRulesEditController', MetaRulesEditController);
+
+ MetaRulesEditController.$inject = ['$scope', '$rootScope'];
+
+ function MetaRulesEditController($scope, $rootScope) {
+
+ var edit = this;
+
+ edit.metaRule = $scope.metaRule;
+
+ activate();
+
+ function activate(){
+ }
+
+
+ /*
+ * ---- events
+ */
+ var rootListeners = {
+
+ 'event:metaRuleBasicUpdatedSuccess': $rootScope.$on('event:metaRuleBasicUpdatedSuccess', metaRuleUpdatedSuccess)
+
+ };
+
+ for (var unbind in rootListeners) {
+ $scope.$on('$destroy', rootListeners[unbind]);
+ }
+
+ /**
+ * When the MetaRule is updated, this function refresh the current metaRule with the new changes
+ * @param event
+ * @param metaRule
+ */
+ function metaRuleUpdatedSuccess(event, metaRule){
+
+ angular.copy(metaRule, edit.metaRule);
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/model/edit/metarules/action/metarules.edit.basic.dir.js b/old/moon_gui/static/app/model/edit/metarules/action/metarules.edit.basic.dir.js
new file mode 100755
index 00000000..b9dcd19c
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metarules/action/metarules.edit.basic.dir.js
@@ -0,0 +1,100 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonMetaRulesEditBasic', moonMetaRulesEditBasic);
+
+ moonMetaRulesEditBasic.$inject = [];
+
+ function moonMetaRulesEditBasic() {
+
+ return {
+ templateUrl : 'html/model/edit/metarules/action/metarules-edit-basic.tpl.html',
+ bindToController : true,
+ controller : moonMetaRulesEditBasicController,
+ controllerAs : 'edit',
+ scope : {
+ metaRule : '='
+ },
+ restrict : 'E',
+ replace : true
+ };
+
+ }
+
+ angular
+ .module('moon')
+ .controller('moonMetaRulesEditBasicController', moonMetaRulesEditBasicController);
+
+ moonMetaRulesEditBasicController.$inject = ['$scope', 'metaRuleService', 'formService', 'alertService', '$translate', 'utilService'];
+
+ function moonMetaRulesEditBasicController($scope, metaRuleService, formService, alertService, $translate, utilService){
+
+ var edit = this;
+
+ edit.editMetaRule = editMetaRule;
+ edit.init = init;
+
+ edit.form = {};
+
+ activate();
+
+ function activate(){
+
+ edit.metaRule = $scope.edit.metaRule;
+
+ edit.metaRuleToEdit = angular.copy(edit.metaRule);
+
+ }
+
+ function editMetaRule(){
+
+ if(formService.isInvalid(edit.form)) {
+
+ formService.checkFieldsValidity(edit.form);
+
+ }else{
+
+ edit.loading = true;
+
+ metaRuleService.update(edit.metaRuleToEdit, updateSuccess, updateError);
+
+ }
+
+ function updateSuccess(data) {
+
+ var updatedMetaRule = utilService.transformOne(data, 'meta_rules');
+
+ angular.copy(updatedMetaRule, edit.metaRule);
+
+ $translate('moon.model.metarules.edit.basic.success', { metaRuleName: updatedMetaRule.name }).then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ edit.loading = false;
+
+ $scope.$emit('event:metaRuleBasicUpdatedSuccess', edit.metaRule);
+
+ }
+
+ function updateError(reason) {
+
+ $translate('moon.model.edit.basic.error', { metaRuleName: edit.metaRule.name }).then( function(translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ edit.loading = false;
+
+ }
+ }
+
+ function init(){
+
+ edit.metaRuleToEdit = angular.copy(edit.metaRule);
+
+ }
+ }
+
+})();
diff --git a/old/moon_gui/static/app/model/edit/metarules/metarules-list.tpl.html b/old/moon_gui/static/app/model/edit/metarules/metarules-list.tpl.html
new file mode 100755
index 00000000..ebe307c3
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metarules/metarules-list.tpl.html
@@ -0,0 +1,138 @@
+<div>
+
+
+ <div><h4 data-translate="moon.model.metarules.title">List of Meta Rules</h4></div>
+
+ <div class="table-responsive" data-role="table">
+ <table class="table table-striped table-hover" ng-table="list.table">
+
+ <colgroup>
+ <col class="col-md-2" />
+ <col class="col-md-2" />
+ <col class="col-md-1" />
+ <col class="col-md-1" />
+ <col class="col-md-1" />
+ <col class="col-md-2" />
+ </colgroup>
+
+ <thead>
+
+ <tr>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('name', 'asc'), 'sort-desc': list.table.isSortBy('name', 'desc') }"
+ ng-click="list.table.sorting('name', list.table.isSortBy('name', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.model.metarules.table.name">Name</div>
+ </th>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('description', 'asc'), 'sort-desc': list.table.isSortBy('description', 'desc') }"
+ ng-click="list.table.sorting('description', list.table.isSortBy('description', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.model.metarules.table.description">Description</div>
+ </th>
+
+ <th class="customTables sortable">
+ <div data-translate="moon.model.metarules.table.metadata.subject.number">Number of Subjects</div>
+ </th>
+
+ <th class="customTables sortable">
+ <div data-translate="moon.model.metarules.table.metadata.object.number">Number of Subjects</div>
+ </th>
+
+ <th class="customTables sortable">
+ <div data-translate="moon.model.metarules.table.metadata.action.number">Number of Actions</div>
+ </th>
+
+ <th class="customTables">
+ <div data-translate="moon.model.metarules.action.title">Actions</div>
+ </th>
+ </tr>
+
+ </thead>
+
+ <tbody ng-if="!list.hasMetaRules()">
+ <tr>
+ <td colspan="2"><span data-translate="moon.model.metarules.table.notFound">There is no Meta Rules</span></td>
+ </tr>
+ </tbody>
+
+ <tbody ng-if="list.hasMetaRules()">
+
+ <tr ng-repeat="aMetaRules in $data | filter:list.search.find | orderBy:sort:reverse">
+ <td ng-bind="aMetaRules.name"></td>
+ <td ng-bind="aMetaRules.description"></td>
+ <td ng-bind="aMetaRules.subject_categories.length"></td>
+ <td ng-bind="aMetaRules.object_categories.length"></td>
+ <td ng-bind="aMetaRules.action_categories.length"></td>
+ <td>
+
+ <div ng-if="list.editMode">
+
+ <div ng-if="!value.loader" class="dropdown">
+
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.model.metadata.table.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+
+ <ul class="dropdown-menu">
+
+ <li>
+ <a href="" ng-click="list.unmap.showModal(aMetaRules)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metarules.action.remove">Remove</span>
+ </a>
+ </li>
+
+ <li>
+ <a href="" ng-click="list.edit.showModal(aMetaRules)">
+ <span class="glyphicon glyphicon-cog"></span>
+ <span class="control-label" data-translate="moon.model.metarules.action.edit">Edit</span>
+ </a>
+ </li>
+
+ </ul>
+
+ </div>
+
+ </div>
+
+ <div ng-if="!list.editMode">
+
+ <a href="" ng-click="list.showDetail(aMetaRules)">
+
+ <span ng-if="aMetaRules.id !== list.getShowDetailValue().id">
+ <span class="glyphicon glyphicon-eye-open"></span>
+ <span class="control-label" data-translate="moon.model.metarules.action.detail.open">Consult</span>
+ </span>
+
+ <span ng-if="aMetaRules.id === list.getShowDetailValue().id">
+ <span class="glyphicon glyphicon-eye-close"></span>
+ <span class="control-label" data-translate="moon.model.metarules.action.detail.close">Close</span>
+ </span>
+
+ </a>
+
+ </div>
+
+ </td>
+ </tr>
+
+ </tbody>
+
+ </table>
+
+ <div ng-if="list.showDetailValue">
+ <moon-meta-data-list edit-mode="list.editMode" meta-rule="list.getShowDetailValue()"></moon-meta-data-list>
+ </div>
+
+ </div>
+
+ <div class="form-group" ng-if="list.editMode">
+ <a href="" ng-click="list.map.showModal()" class="btn btn-default">
+ <span class="glyphicon glyphicon-link"></span>
+ <span data-translate="moon.model.metarules.action.settings">Settings</span>
+ </a>
+ </div>
+
+</div>
diff --git a/old/moon_gui/static/app/model/edit/metarules/metarules.list.dir.js b/old/moon_gui/static/app/model/edit/metarules/metarules.list.dir.js
new file mode 100755
index 00000000..9c1bc72e
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/metarules/metarules.list.dir.js
@@ -0,0 +1,241 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonMetaRulesList', moonMetaRulesList);
+
+ moonMetaRulesList.$inject = [];
+
+ function moonMetaRulesList() {
+
+ return {
+ templateUrl : 'html/model/edit/metarules/metarules-list.tpl.html',
+ bindToController : true,
+ controller : moonMetaRulesListController,
+ controllerAs : 'list',
+ scope : {
+ // if edit and delete possibilities are displayed
+ // Value are True or False
+ editMode : '=',
+ mappedModel : '='
+ },
+ restrict : 'E',
+ replace : true
+ };
+ }
+
+ angular
+ .module('moon')
+ .controller('moonMetaRulesListController', moonMetaRulesListController);
+
+ moonMetaRulesListController.$inject = ['$scope', '$rootScope', 'NgTableParams', '$filter', '$modal', 'metaRuleService'];
+
+ function moonMetaRulesListController($scope, $rootScope, NgTableParams, $filter, $modal, metaRuleService ){
+
+ var list = this;
+
+ list.table = {};
+
+ list.editMode = $scope.list.editMode;
+ list.model = $scope.list.mappedModel;
+ list.metaRules = list.model.meta_rules_values;
+
+ list.getMetaRules = getMetaRules;
+ list.hasMetaRules = hasMetaRules;
+ list.showDetail = showDetail;
+ list.getSubjectList = getSubjectList;
+ list.getObjectList = getObjectList;
+ list.getActionlist = getActionlist;
+ list.getShowDetailValue = getShowDetailValue;
+
+ list.showDetailValue = false;
+
+ list.subject_list = [];
+ list.object_list = [];
+ list.action_list = [];
+
+ list.edit = { modal: $modal({ template: 'html/model/edit/metarules/action/metarules-edit.tpl.html', show: false }),
+ showModal: showEditModal };
+
+ /*list.edit.modal.result.finally(function(){
+ console.log('CATCHING');
+ });*/
+
+
+ list.map = { modal: $modal({ template: 'html/model/edit/metarules/action/mapping/metarules-map.tpl.html', show: false }),
+ showModal: showMapModal };
+
+ list.unmap = { modal: $modal({ template: 'html/model/edit/metarules/action/mapping/metarules-unmap.tpl.html', show: false }),
+ showModal: showUnmapModal };
+
+ activate();
+
+ function activate(){
+
+ newMetaRulesTable();
+
+ }
+
+ /*
+ * ---- events
+ */
+ var rootListeners = {
+
+ 'event:metaRuleMapToModelSuccess': $rootScope.$on('event:metaRuleMapToModelSuccess', updateModelFromMapSuccess),
+
+ 'event:metaRuleUnMappedToModelSuccess': $rootScope.$on('event:metaRuleUnMappedToModelSuccess', modelUnmappedSuccess),
+ 'event:metaRuleUnMappedToModelError': $rootScope.$on('event:metaRuleUnMappedToModelError', modelUnmappedError),
+
+
+ };
+
+ for (var unbind in rootListeners) {
+ $scope.$on('$destroy', rootListeners[unbind]);
+ }
+
+
+
+ function newMetaRulesTable() {
+
+ list.table = new NgTableParams({
+
+ page: 1, // show first page
+ count: 10, // count per page
+ sorting: {
+ name: 'asc' // initial sorting
+ }
+
+ }, {
+
+ total: function () { return list.getMetaRules().length; }, // length of data
+ getData: function($defer, params) {
+
+ var orderedData = params.sorting() ? $filter('orderBy')(list.getMetaRules(), params.orderBy()) : list.getMetaRules();
+ $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
+
+ },
+ $scope: { $data: {} }
+
+ });
+
+ return list.table;
+
+ }
+
+ /**
+ * If the directive is not in editMode and displaying MetaData Content, if the editMode change to true, MetaData Content need to be hidden
+ */
+ $scope.$watch('list.editMode', function(newValue, oldValue){
+ list.showDetailValue = false;
+ });
+
+ function getMetaRules() {
+ return (list.metaRules) ? list.metaRules : [];
+ }
+
+ function hasMetaRules() {
+ return list.getMetaRules().length > 0;
+ }
+
+ function showDetail(aMetaRule){
+
+ if(aMetaRule.id === getShowDetailValue().id){
+
+ list.showDetailValue = false;
+ list.subject_list = [];
+ list.object_list = [];
+ list.action_list = [];
+
+ }else{
+
+ list.subject_list = aMetaRule.subject_categories_values;
+ list.object_list = aMetaRule.object_categories_values;
+ list.action_list = aMetaRule.action_categories_values;
+ list.showDetailValue = aMetaRule;
+
+ }
+
+ }
+
+ function showEditModal(aMetaRule) {
+ list.edit.modal.$scope.metaRule = aMetaRule;
+ list.edit.modal.$promise.then(list.edit.modal.show);
+ }
+
+ function getShowDetailValue(){
+ return list.showDetailValue;
+ }
+
+ function getSubjectList(){
+ return list.subject_list;
+ }
+
+ function getObjectList(){
+ return list.object_list;
+ }
+
+ function getActionlist(){
+ return list.action_list;
+ }
+
+ /*
+ * ---- add
+ */
+ function showMapModal() {
+ list.map.modal.$scope.model = list.model;
+ list.map.modal.$promise.then(list.map.modal.show);
+ }
+
+ function refreshRules(){
+
+ list.metaRules = list.model.meta_rules_values;
+ list.table.total(list.getMetaRules().length);
+ list.table.reload();
+
+ }
+
+ function updateModelFromMapSuccess(event, model){
+
+ list.model = model;
+
+ refreshRules();
+
+ list.map.modal.hide();
+
+ }
+
+ /*
+ * ---- unmap
+ */
+
+ function showUnmapModal(metaRule) {
+
+ list.unmap.modal.$scope.model = list.model;
+ list.unmap.modal.$scope.metaRule = metaRule;
+ list.unmap.modal.$promise.then(list.unmap.modal.show);
+
+ }
+
+ function modelUnmappedSuccess(event, model) {
+
+ list.model = model;
+
+ metaRuleService.findSomeWithCallback(list.model.meta_rules, function(meta_rules){
+
+ list.model.meta_rules_values = meta_rules;
+ refreshRules();
+ list.unmap.modal.hide();
+
+ });
+
+ }
+
+ function modelUnmappedError(event) {
+ list.unmap.modal.hide();
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/model/edit/model-edit-basic.tpl.html b/old/moon_gui/static/app/model/edit/model-edit-basic.tpl.html
new file mode 100755
index 00000000..bd73b4ef
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/model-edit-basic.tpl.html
@@ -0,0 +1,65 @@
+<div class="row">
+
+ <form class="form-horizontal" role="form" name="edit.form">
+
+ <div class="form-group">
+
+ <label for="id" class="col-sm-3 control-label" data-translate="moon.model.edit.basic.form.id">Id</label>
+
+ <div class="col-sm-6">
+
+ <input name="id" id="id" disabled class="form-control" type="text" data-ng-model="edit.modelToEdit.id" required />
+
+ </div>
+
+ </div>
+
+ <div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}">
+
+ <label for="name" class="col-sm-3 control-label" data-translate="moon.model.edit.basic.form.name">Name</label>
+
+ <div class="col-sm-6">
+
+ <input name="name" id="name" class="form-control" type="text" data-ng-model="edit.modelToEdit.name" required />
+
+ <div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid">
+ <small class="error" ng-show="edit.form.name.$error.required" data-translate="moon.model.edit.basic.check.name.required">Name is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <label for="description" class="col-sm-3 control-label" data-translate="moon.model.edit.basic.form.description">Description</label>
+ <div class="col-sm-6">
+ <textarea id="description" name="description" class="form-control" data-ng-model="edit.modelToEdit.description"></textarea>
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <div class="col-sm-2 col-sm-offset-3">
+
+ <a href="" ng-disabled="edit.loading" ng-click="edit.init()" class="btn btn-default">
+ <span data-translate="moon.model.edit.basic.action.init">Init</span>
+ </a>
+ </div>
+
+ <div class="col-sm-4 col-sm-offset-2">
+
+ <a href="" ng-disabled="edit.loading" ng-click="edit.editModel()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-save"></span>
+ <span data-translate="moon.model.edit.basic.action.update">Update</span>
+ </a>
+
+ <moon-loader ng-if="edit.loading"></moon-loader>
+ </div>
+
+ </div>
+
+ </form>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/model/edit/model-edit.tpl.html b/old/moon_gui/static/app/model/edit/model-edit.tpl.html
new file mode 100755
index 00000000..4955f441
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/model-edit.tpl.html
@@ -0,0 +1,70 @@
+<div class="container">
+
+ <div class="row">
+ <h3 class="pull-left" data-translate="moon.model.edit.title" data-translate-values="{ modelName: edit.model.name }">Edit</h3>
+ </div>
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <span data-translate="moon.model.edit.basic.title" >Basic Information</span>
+ <a href="" ng-click="edit.editBasic = !edit.editBasic">
+ <span data-translate="moon.model.edit.update">Update</span>
+ <span class="glyphicon glyphicon-cog"></span>
+ </a>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div ng-if="edit.editBasic">
+ <moon-model-edit-basic model="edit.model"></moon-model-edit-basic>
+ </div>
+
+ <div ng-if="!edit.editBasic">
+ <dl class="dl-horizontal">
+
+ <dt data-translate="moon.model.edit.basic.form.id">Id</dt>
+ <dd ng-bind="edit.model.id"></dd>
+
+ <dt data-translate="moon.model.edit.basic.form.name">Name</dt>
+ <dd ng-bind="edit.model.name"></dd>
+
+ <dt data-translate="moon.model.edit.basic.form.description">Description</dt>
+ <dd ng-bind="edit.model.description"></dd>
+
+ </dl>
+ </div>
+ </div>
+
+ </div>
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <span data-translate="moon.model.edit.metarules.title" >Meta Rule</span>
+ <!--<a href="" ng-click="edit.editMetaRules = !edit.editMetaRules">
+ <span data-translate="moon.model.edit.update">Update</span>
+ <span class="glyphicon glyphicon-cog"></span>
+ </a>-->
+
+ </div>
+
+ <div class="panel-body" ng-if="edit.model.meta_rules_values">
+ <div class="">
+
+ <moon-meta-rules-list mapped-model="edit.model" edit-mode="edit.editMetaRules"></moon-meta-rules-list>
+
+ </div>
+ </div>
+
+ <div class="panel-body" ng-if="!edit.model.meta_rules_values">
+ <moon-loader></moon-loader>
+ </div>
+
+ </div>
+
+
+</div>
diff --git a/old/moon_gui/static/app/model/edit/model.controller.edit.js b/old/moon_gui/static/app/model/edit/model.controller.edit.js
new file mode 100755
index 00000000..3e10a533
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/model.controller.edit.js
@@ -0,0 +1,61 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('ModelEditController', ModelEditController);
+
+ ModelEditController.$inject = ['$scope', '$rootScope', 'model', 'metaRuleService'];
+
+ function ModelEditController($scope, $rootScope, model, metaRuleService) {
+
+ var edit = this;
+
+ edit.model = model;
+
+ edit.editBasic = false;
+
+ edit.editMetaRules = true;
+
+ activate();
+
+ function activate(){
+
+ }
+
+ /*
+ * ---- events
+ */
+ var rootListeners = {
+
+ 'event:modelUpdatedSuccess': $rootScope.$on('event:modelUpdatedSuccess', modelUpdatedSuccess),
+
+ 'event:updateModelFromMetaRuleAddSuccess': $rootScope.$on('event:updateModelFromMetaRuleAddSuccess', modelUpdatedSuccess)
+
+ };
+
+ for (var unbind in rootListeners) {
+ $scope.$on('$destroy', rootListeners[unbind]);
+ }
+
+ /**
+ * When the model is updated, this function refresh the current model with the new changes
+ * @param event
+ * @param model
+ */
+ function modelUpdatedSuccess(event, model){
+
+ edit.model = model;
+
+ metaRuleService.findSomeWithCallback(model.meta_rules, function(metaRules){
+
+ edit.model.meta_rules_values = metaRules;
+
+ });
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/model/edit/model.edit.basic.dir.js b/old/moon_gui/static/app/model/edit/model.edit.basic.dir.js
new file mode 100755
index 00000000..54bb7071
--- /dev/null
+++ b/old/moon_gui/static/app/model/edit/model.edit.basic.dir.js
@@ -0,0 +1,97 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonModelEditBasic', moonModelEditBasic);
+
+ moonModelEditBasic.$inject = [];
+
+ function moonModelEditBasic() {
+
+ return {
+ templateUrl : 'html/model/edit/model-edit-basic.tpl.html',
+ bindToController : true,
+ controller : moonModelEditBasicController,
+ controllerAs : 'edit',
+ scope : {
+ model : '='
+ },
+ restrict : 'E',
+ replace : true
+ };
+ }
+
+ angular
+ .module('moon')
+ .controller('moonModelEditBasicController', moonModelEditBasicController);
+
+ moonModelEditBasicController.$inject = ['$scope', 'modelService', 'formService', 'alertService', '$translate', 'utilService'];
+
+ function moonModelEditBasicController($scope, modelService, formService, alertService, $translate, utilService){
+
+ var edit = this;
+
+ edit.editModel = editModel;
+ edit.init = init;
+
+ edit.form = {};
+
+ activate();
+
+ function activate(){
+
+ edit.model = $scope.edit.model;
+
+ edit.modelToEdit = angular.copy(edit.model);
+
+ }
+
+ function editModel(){
+
+ if(formService.isInvalid(edit.form)) {
+
+ formService.checkFieldsValidity(edit.form);
+
+ }else{
+
+ edit.loading = true;
+
+ modelService.update(edit.modelToEdit, updateSuccess, updateError);
+
+ }
+
+ function updateSuccess(data) {
+
+ var updatedModel = utilService.transformOne(data, 'models');
+
+ $translate('moon.model.edit.basic.success', { modelName: updatedModel.name }).then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ edit.loading = false;
+
+ $scope.$emit('event:modelUpdatedSuccess', updatedModel);
+
+ }
+
+ function updateError(reason) {
+
+ $translate('moon.model.edit.basic.error', { modelName: edit.model.name }).then( function(translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ edit.loading = false;
+
+ }
+ }
+
+ function init(){
+
+ edit.modelToEdit = angular.copy(edit.model);
+
+ }
+ }
+
+})();
diff --git a/old/moon_gui/static/app/model/model-list.tpl.html b/old/moon_gui/static/app/model/model-list.tpl.html
new file mode 100755
index 00000000..89c682cc
--- /dev/null
+++ b/old/moon_gui/static/app/model/model-list.tpl.html
@@ -0,0 +1,123 @@
+<div class="container">
+
+ <div>
+ <form class="form-inline pull-right">
+ <div class="form-group">
+ <div>
+ <input id="searchProject" data-ng-model="list.search.query" type="text" class="form-control" placeholder="{{'moon.model.list.search.placeholder' | translate}}" />
+ </div>
+ </div>
+ <div class="form-group">
+ <div>
+ <button type="submit" class="btn btn-danger" data-ng-click="list.search.reset()" data-translate="moon.model.list.search.reset">Reset</button>
+ </div>
+ </div>
+ </form>
+ </div>
+
+ <div>&nbsp;</div>
+ <div>&nbsp;</div>
+ <div>&nbsp;</div>
+
+ <div class="row">
+
+ <div class="table-responsive" data-role="table">
+
+ <table class="table table-striped table-hover" ng-table="list.table">
+
+ <thead>
+
+ <tr>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('name', 'asc'), 'sort-desc': list.table.isSortBy('name', 'desc') }"
+ ng-click="list.table.sorting('name', list.table.isSortBy('name', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.model.list.table.name">Name</div>
+ </th>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('description', 'asc'), 'sort-desc': list.table.isSortBy('description', 'desc') }"
+ ng-click="list.table.sorting('description', list.table.isSortBy('description', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.model.list.table.description">Description</div>
+ </th>
+
+ <th class="customTables sortable">
+ <div data-translate="moon.model.list.table.metaRules.number">Number of Meta Rules</div>
+ </th>
+
+ <th class="customTables">
+ <div data-translate="moon.model.list.action.title">Actions</div>
+ </th>
+ </tr>
+
+ </thead>
+
+ <tbody ng-if="!list.hasModels()">
+ <tr>
+ <td colspan="2"><span data-translate="moon.model.list.table.notFound">There is no Models</span></td>
+ </tr>
+ </tbody>
+
+ <tbody ng-if="list.hasModels()">
+
+ <tr ng-repeat="aModel in $data | filter:list.search.find | orderBy:sort:reverse">
+ <td ng-bind="aModel.name"></td>
+ <td ng-bind="aModel.description"></td>
+ <td ng-bind="aModel.meta_rules.length"></td>
+ <td>
+ <div class="dropdown">
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.model.list.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu">
+
+ <!-- <li>
+ <a href="" ng-click="list.view.showModal(aModel)">
+ <span class="glyphicon glyphicon-eye-open"></span>
+ <span class="control-label" data-translate="moon.model.list.action.detail">Detail</span>
+ </a>
+ </li>-->
+
+ <li>
+ <a href="" ui-sref="moon.model.edit({id: aModel.id})">
+ <span class="glyphicon glyphicon-cog"></span>
+ <span class="control-label" data-translate="moon.model.list.action.edit">Edit</span>
+ </a>
+ </li>
+
+ <li class="divider"></li>
+
+ <li>
+ <a href="" ng-click="list.del.showModal(aModel)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.model.list.action.delete">Delete</span>
+ </a>
+ </li>
+
+ </ul>
+ </div>
+ </td>
+
+ </tr>
+
+ </tbody>
+
+ </table>
+
+ </div>
+
+ <div class="container">
+
+ <div class="form-inline form-group">
+ <a href="" ng-click="list.add.showModal()" class="btn btn-default">
+ <span class="glyphicon glyphicon-plus-sign"></span>
+ <span data-translate="moon.model.list.action.add">Add Model</span>
+ </a>
+ </div>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/model/model.controller.list.js b/old/moon_gui/static/app/model/model.controller.list.js
new file mode 100755
index 00000000..5021a57e
--- /dev/null
+++ b/old/moon_gui/static/app/model/model.controller.list.js
@@ -0,0 +1,195 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('ModelListController', ModelListController);
+
+ ModelListController.$inject = ['$scope', '$rootScope', 'models', 'NgTableParams', '$filter', '$modal'];
+
+ function ModelListController($scope, $rootScope, models, NgTableParams, $filter, $modal) {
+
+ var list = this;
+
+ list.models = models;
+
+ list.table = {};
+
+ list.search = { query: '',
+ find: searchModel,
+ reset: searchReset };
+
+ list.getModels = getModels;
+ list.hasModels = hasModels;
+ list.deleteModel = deleteModel;
+ list.refreshModels = refreshModels;
+
+ list.add = { modal: $modal({ template: 'html/model/action/model-add.tpl.html', show: false }),
+ showModal: showAddModal };
+
+ list.view = { modal: $modal({ template: 'html/model/action/model-view.tpl.html', show: false }),
+ showModal: showViewModal };
+
+ list.del = { modal: $modal({ template: 'html/model/action/model-delete.tpl.html', show: false }),
+ showModal: showDeleteModal };
+
+ activate();
+
+ function activate(){
+ newModelsTable();
+ }
+
+
+ /*
+ * ---- events
+ */
+ var rootListeners = {
+
+ 'event:modelCreatedSuccess': $rootScope.$on('event:modelCreatedSuccess', modelCreatedSuccess),
+ 'event:modelCreatedError': $rootScope.$on('event:modelCreatedError', modelCreatedError),
+
+ 'event:modelDeletedSuccess': $rootScope.$on('event:modelDeletedSuccess', modelDeletedSuccess),
+ 'event:modelDeletedError': $rootScope.$on('event:modelDeletedError', modelDeletedError)
+
+
+ };
+
+ for (var unbind in rootListeners) {
+ $scope.$on('$destroy', rootListeners[unbind]);
+ }
+
+
+ function newModelsTable() {
+
+ list.table = new NgTableParams({
+
+ page: 1, // show first page
+ count: 10, // count per page
+ sorting: {
+ name: 'asc' // initial sorting
+ }
+
+ }, {
+
+ total: function () { return list.getModels().length; }, // length of data
+ getData: function($defer, params) {
+
+ var orderedData = params.sorting() ? $filter('orderBy')(list.getModels(), params.orderBy()) : list.getModels();
+ $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
+
+ },
+ $scope: { $data: {} }
+
+ });
+
+ return list.table;
+
+ }
+
+ function getModels() {
+ return (list.models) ? list.models : [];
+ }
+
+ function hasModels() {
+ return list.getModels().length > 0;
+ }
+
+ /**
+ * Blank the search field
+ */
+ function searchReset() {
+ list.search.query = '';
+ }
+
+ /*
+ * ---- search
+ */
+
+ function searchModel(model){
+ return (model.name.indexOf(list.search.query) !== -1 || model.description.indexOf(list.search.query) !== -1);
+ }
+
+ /*
+ * ---- add
+ */
+ function showAddModal() {
+ list.add.modal.$promise.then(list.add.modal.show);
+ }
+
+ function addModel(model) {
+ list.models.push(model);
+ }
+
+ /**
+ * Refresh the table
+ */
+ function refreshModels(){
+ list.table.total(list.models.length);
+ list.table.reload();
+ }
+
+ /**
+ * This function will add a model to the current list of models and refresh the table
+ * @param event
+ * @param model
+ */
+ function modelCreatedSuccess(event, model) {
+ addModel(model);
+ refreshModels();
+ list.add.modal.hide();
+ }
+
+ /**
+ * This function hide the add modal
+ * @param event
+ */
+ function modelCreatedError(event) {
+ list.add.modal.hide();
+ }
+
+ /*
+ * ---- view
+ */
+
+ function showViewModal(model) {
+
+ list.view.modal.$scope.model = model;
+ list.view.modal.$promise.then(list.view.modal.show);
+
+ }
+
+
+ /*
+ * ---- delete
+ */
+
+ function showDeleteModal(model) {
+
+ list.del.modal.$scope.model = model;
+ list.del.modal.$promise.then(list.del.modal.show);
+
+ }
+
+ function deleteModel(model) {
+ list.models = _.chain(list.models).reject({id: model.id}).value();
+ }
+
+
+ function modelDeletedSuccess(event, model) {
+
+ list.deleteModel(model);
+ list.refreshModels();
+
+ list.del.modal.hide();
+
+ }
+
+ function modelDeletedError(event, model) {
+ list.del.modal.hide();
+ }
+
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/moon.constants.js b/old/moon_gui/static/app/moon.constants.js
new file mode 100644
index 00000000..9681e3dc
--- /dev/null
+++ b/old/moon_gui/static/app/moon.constants.js
@@ -0,0 +1,79 @@
+/**
+# Copyright 2014 Orange
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .constant('DEFAULT_CST', {
+ DOMAIN: {
+ DEFAULT: 'Default'
+ }
+ })
+ .constant('SECURITY_PIPELINE_CST', {
+ TYPE: {
+ POLICY: 'policy'
+ }
+ })
+ .constant('META_DATA_CST', {
+ TYPE: {
+ SUBJECT: 'SUBJECT',
+ OBJECT: 'OBJECT',
+ ACTION: 'ACTION'
+ }
+ })
+ .constant('PERIMETER_CST', {
+ TYPE: {
+ SUBJECT: 'SUBJECT',
+ OBJECT: 'OBJECT',
+ ACTION: 'ACTION'
+ }
+ })
+ .constant('DATA_CST', {
+ TYPE: {
+ SUBJECT: 'SUBJECT',
+ OBJECT: 'OBJECT',
+ ACTION: 'ACTION'
+ }
+ })
+ .constant('ASSIGNMENTS_CST', {
+ TYPE: {
+ SUBJECT: 'SUBJECT',
+ OBJECT: 'OBJECT',
+ ACTION: 'ACTION'
+ }
+ })
+ .constant('REST_URI', {
+ PDP : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/pdp/',
+ MODELS : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/models/',
+ METARULES: 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/meta_rules/',
+ RULES: 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/rules/',
+ POLICIES: 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/policies/',
+ METADATA: {
+ subject : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/subject_categories/',
+ object : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/object_categories/',
+ action : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/action_categories/'
+ },
+ PERIMETERS :{
+ subject : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/subjects/',
+ object : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/objects/',
+ action : 'http://{{MANAGER_HOST}}:{{MANAGER_PORT}}/actions/'
+ },
+ KEYSTONE : 'http://{{KEYSTONE_HOST}}:{{KEYSTONE_PORT}}/v3/'
+ });
+})();
diff --git a/old/moon_gui/static/app/moon.module.js b/old/moon_gui/static/app/moon.module.js
new file mode 100755
index 00000000..cc374f24
--- /dev/null
+++ b/old/moon_gui/static/app/moon.module.js
@@ -0,0 +1,362 @@
+/**
+# Copyright 2015 Orange
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+ */
+
+(function() {
+
+ 'use strict';
+
+ var moon = angular
+
+ .module('moon', ['ngResource',
+ 'ngRoute',
+ 'ui.router',
+ 'ngMessages',
+ 'ui.bootstrap',
+ 'ngTable',
+ 'ngCookies',
+ 'ngStorage',
+ 'pascalprecht.translate',
+ 'ngAnimate',
+ 'mgcrea.ngStrap',
+ 'NgSwitchery',
+ 'ui.select',
+ 'toaster'])
+
+ .config(configure)
+ .run(runner);
+
+ /*
+ * configure
+ */
+
+ configure.$inject = ['$urlRouterProvider', '$translateProvider', '$stateProvider', 'uiSelectConfig'];
+
+ function configure($urlRouterProvider, $translateProvider, $stateProvider, uiSelectConfig) {
+
+ /*
+ * translate
+ */
+
+ $translateProvider
+ .useStaticFilesLoader({
+ prefix: 'assets/i18n/',
+ suffix: '.json'
+ })
+ .preferredLanguage('en')
+ .useCookieStorage();
+
+ /*
+ * ui-select
+ */
+
+ uiSelectConfig.theme = 'selectize';
+
+ /*
+ * routes
+ */
+
+ $urlRouterProvider.when('', '/model');
+ $urlRouterProvider.when('/', '/model');
+ $urlRouterProvider.otherwise('/404');
+
+ configureDefaultRoutes($stateProvider);
+
+ configureDashboard($stateProvider);
+
+ configureAuthRoutes($stateProvider);
+
+ configureProjectRoutes($stateProvider);
+
+ configureModelRoutes($stateProvider);
+
+ configurePDPRoutes($stateProvider);
+
+ configurePolicyRoutes($stateProvider);
+
+ configureLogsRoutes($stateProvider);
+
+ }
+
+ function configureDefaultRoutes($stateProvider) {
+
+ $stateProvider
+
+ .state('moon', {
+ abstract: true,
+ template: '<div ui-view></div>'
+ })
+
+ .state('moon.404', {
+ url: '/404',
+ templateUrl: 'html/common/404/404.tpl.html'
+ });
+
+ return $stateProvider;
+
+ }
+
+ function configureDashboard($stateProvider){
+
+ $stateProvider
+
+ .state('moon.dashboard',{
+ url: '/dashboard',
+ templateUrl: 'html/dashboard/dashboard.tpl.html'
+ });
+
+ return $stateProvider;
+
+ }
+
+ function configureAuthRoutes($stateProvider){
+
+ $stateProvider
+
+ .state('moon.auth', {
+ abstract: true,
+ template: '<div ui-view></div>'
+ })
+
+ .state('moon.auth.login', {
+ url: '/login',
+ templateUrl: 'html/authentication/authentication.tpl.html',
+ controller: 'AuthenticationController',
+ controllerAs: 'auth'
+ });
+
+ return $stateProvider;
+ }
+
+ function configureModelRoutes($stateProvider) {
+
+ $stateProvider
+
+ .state('moon.model', {
+ abstract: true,
+ template: '<div ui-view></div>'
+ })
+
+ .state('moon.model.list', {
+ url: '/model',
+ templateUrl: 'html/model/model-list.tpl.html',
+ controller: 'ModelListController',
+ controllerAs: 'list',
+ resolve: {
+ models: ['modelService', function(modelService) {
+ return modelService.findAll();
+ }]
+ }
+ })
+
+ .state('moon.model.edit', {
+ url: '/model/:id',
+ templateUrl: 'html/model/edit/model-edit.tpl.html',
+ controller: 'ModelEditController',
+ controllerAs: 'edit',
+ resolve: {
+ model: ['$stateParams','modelService', function($stateParams, modelService) {
+ return modelService.findOneWithMetaRules($stateParams.id);
+ }]
+ }
+ });
+
+
+ return $stateProvider;
+
+ }
+
+ function configureProjectRoutes($stateProvider) {
+
+ $stateProvider
+
+ .state('moon.project', {
+ abstract: true,
+ template: '<div ui-view></div>'
+ })
+
+ .state('moon.project.list', {
+ url: '/project',
+ templateUrl: 'html/project/project-list.tpl.html',
+ controller: 'ProjectListController',
+ controllerAs: 'list',
+ resolve: {
+ projects: ['projectService', function(projectService) {
+ return projectService.findAll();
+ }]
+ }
+ });
+
+ return $stateProvider;
+
+ }
+
+ function configurePDPRoutes($stateProvider) {
+
+ $stateProvider
+
+ .state('moon.pdp', {
+ abstract: true,
+ template: '<div ui-view></div>'
+ })
+
+ .state('moon.pdp.list', {
+ url: '/pdp',
+ templateUrl: 'html/pdp/pdp-list.tpl.html',
+ controller: 'PDPListController',
+ controllerAs: 'list',
+ resolve: {
+ pdps: ['pdpService', function(pdpService) {
+ return pdpService.findAll();
+ }]
+ }
+ })
+
+ .state('moon.pdp.edit', {
+ url: '/pdp/:id',
+ templateUrl: 'html/pdp/edit/pdp-edit.tpl.html',
+ controller: 'PDPEditController',
+ controllerAs: 'edit',
+ resolve: {
+ pdp: ['$stateParams','pdpService', function($stateParams, pdpService) {
+ return pdpService.findOne($stateParams.id);
+ }]
+ }
+ });
+
+ return $stateProvider;
+
+ }
+
+ function configurePolicyRoutes($stateProvider) {
+
+ $stateProvider
+
+ .state('moon.policy', {
+ abstract: true,
+ template: '<div ui-view></div>'
+ })
+
+ .state('moon.policy.list', {
+ url: '/policy',
+ templateUrl: 'html/policy/policy-list.tpl.html',
+ controller: 'PolicyListController',
+ controllerAs: 'list',
+ resolve: {
+ policies: ['policyService', function(policyService) {
+ return policyService.findAll();
+ }]
+ }
+ })
+
+ .state('moon.policy.edit', {
+ url: '/policy/:id',
+ templateUrl: 'html/policy/edit/policy-edit.tpl.html',
+ controller: 'PolicyEditController',
+ controllerAs: 'edit',
+ resolve: {
+ policy: ['$stateParams','policyService', function($stateParams, policyService) {
+ return policyService.findOne($stateParams.id);
+ }]
+ }
+ });
+
+
+ return $stateProvider;
+
+ }
+
+ function configureLogsRoutes($stateProvider){
+
+ $stateProvider
+
+ .state('moon.logs', {
+ url: '/logs',
+ templateUrl: 'html/logs/logs.tpl.html',
+ controller: 'LogsController',
+ controllerAs: 'logs'
+ });
+
+ return $stateProvider;
+ }
+
+ /*
+ * runner
+ */
+
+ runner.$inject = ['$rootScope', '$modal', '$translate', 'alertService', 'authenticationService', '$sessionStorage', '$location'];
+
+ function runner($rootScope, $modal, $translate, alertService, authenticationService, $sessionStorage, $location) {
+
+ $rootScope.connected = authenticationService.IsConnected();
+
+ $rootScope.transitionModal = $modal({ scope: $rootScope, template: 'html/common/waiting/waiting.tpl.html', backdrop: 'static', show: false });
+
+ $rootScope.$on('$stateChangeStart', stateChangeStart);
+ $rootScope.$on('$stateChangeSuccess', stateChangeSuccess);
+ $rootScope.$on('$stateChangeError', stateChangeError);
+ $rootScope.$on('$locationChangeStart', locationChangeStart);
+
+ // keep user logged in after page refresh
+ if (authenticationService.IsConnected()) {
+ authenticationService.SetTokenHeader(authenticationService.GetTokenHeader());
+ }
+
+ // redirect to login page if not logged in and trying to access a restricted pages
+ function locationChangeStart(event, next, current) {
+ var publicPages = ['/login'];
+ var restrictedPage = publicPages.indexOf($location.path()) === -1;
+ if (restrictedPage && !$sessionStorage.currentUser) {
+ $location.path('/login');
+ }
+ }
+
+ function stateChangeStart() {
+ $rootScope.connected = authenticationService.IsConnected();
+ $rootScope.transitionModal.$promise.then($rootScope.transitionModal.show);
+ }
+
+ function stateChangeSuccess() {
+ $rootScope.transitionModal.hide();
+ }
+
+ function stateChangeError(event, toState, toParams, fromState, fromParams, error) {
+
+ var stacktrace = getStacktrace(event, toState, toParams, fromState, fromParams, error);
+
+ $translate('moon.global.error', { stacktrace: stacktrace }).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ $rootScope.transitionModal.hide();
+
+ }
+
+ function getStacktrace(event, toState, toParams, fromState, fromParams, error) {
+
+ var stacktrace = {};
+
+ stacktrace.status = error.status;
+ stacktrace.message = error.statusText;
+ stacktrace.state = toState;
+ stacktrace.params = toParams;
+
+ return stacktrace;
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/pdp/action/pdp-add.tpl.html b/old/moon_gui/static/app/pdp/action/pdp-add.tpl.html
new file mode 100755
index 00000000..f83fb85c
--- /dev/null
+++ b/old/moon_gui/static/app/pdp/action/pdp-add.tpl.html
@@ -0,0 +1,88 @@
+<div ng-controller="PDPAddController as add" class="modal" tabindex="-1" data-role="modalAddPDP">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.pdp.add.title"></h4>
+ </div>
+
+ <div class="modal-body">
+
+ <form class="form-horizontal" role="form" name="add.form">
+
+ <div class="form-group" ng-class="{'has-error': add.form.name.$invalid && add.form.name.$dirty}">
+
+ <label for="name" class="col-sm-3 control-label" data-translate="moon.pdp.add.form.name">Name</label>
+
+ <div class="col-sm-6">
+
+ <input name="name" id="name" class="form-control" type="text" data-ng-model="add.pdp.name" required />
+
+ <div class="help-block" ng-show="add.form.name.$dirty && add.form.name.$invalid">
+ <small class="error" ng-show="add.form.name.$error.required" data-translate="moon.pdp.add.check.name.required">Name is required</small>
+ </div>
+
+ </div>
+ </div>
+
+ <div class="form-group" ng-class="{'has-error': add.form.policy.$dirty && (add.form.policy.$invalid || !add.selectedPolicy)}">
+
+ <label class="col-sm-3 control-label" data-translate="moon.pdp.add.form.policy">Policy</label>
+
+ <div class="col-sm-6" ng-if="!add.loadingPolicies">
+
+ <ui-select ng-model="add.selectedPolicy" name="policy" required>
+ <ui-select-match placeholder="(None)">{{$select.selected.name}}</ui-select-match>
+ <ui-select-choices repeat="policy in add.policies">
+ <div ng-value="policy">{{policy.name}}</div>
+ </ui-select-choices>
+ </ui-select>
+
+ <div class="help-block" ng-show="add.form.policy.$dirty && (add.form.policy.$invalid || !add.selectedPolicy)">
+ <small class="error" ng-show="add.form.policy.$error.required" data-translate="moon.pdp.add.check.policy.required">Policy is required</small>
+ </div>
+
+ </div>
+
+ <div class="col-sm-6" ng-if="add.loadingPolicies">
+ <moon-loader ng-if="add.loadingPolicies" ></moon-loader>
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <label for="description" class="col-sm-3 control-label" data-translate="moon.pdp.add.form.description">Description</label>
+ <div class="col-sm-6">
+ <textarea name="description" id="description" class="form-control" ng-model="add.pdp.description"></textarea>
+ </div>
+
+ </div>
+
+ </form>
+
+ </div>
+
+ <div class="modal-footer">
+
+ <div class="btn-toolbar" style="float: right;">
+ <a href="" ng-click="$hide()" class="btn btn-default">
+ <span data-translate="moon.pdp.add.action.cancel">Cancel</span>
+ </a>
+ <a href="" ng-disabled="add.loading" ng-click="add.create(add.pdp)" class="btn btn-warning">
+ <span class="glyphicon glyphicon-save"></span>
+ <span data-translate="moon.pdp.add.action.create">Create</span>
+ </a>
+ <moon-loader ng-if="add.loading"></moon-loader>
+ </div>
+
+ </div>
+
+ </div>
+
+ </div>
+
+</div>
diff --git a/old/moon_gui/static/app/pdp/action/pdp-delete.tpl.html b/old/moon_gui/static/app/pdp/action/pdp-delete.tpl.html
new file mode 100755
index 00000000..167ba417
--- /dev/null
+++ b/old/moon_gui/static/app/pdp/action/pdp-delete.tpl.html
@@ -0,0 +1,35 @@
+<div ng-controller="PDPDeleteController as del" class="modal" tabindex="-1" data-role="modalDeletePDP">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.pdp.remove.title"></h4>
+ </div>
+
+ <div class="modal-body">
+ <span data-translate="moon.pdp.remove.content" data-translate-values="{ pdpName: del.pdp.name}"></span>
+ </div>
+
+ <div class="modal-footer">
+ <div class="btn-toolbar" style="float: right;">
+ <a href="" ng-click="$hide()" class="btn btn-default">
+ <span data-translate="moon.pdp.remove.action.cancel">Cancel</span>
+ </a>
+
+ <a href="" ng-disabled="del.loading" ng-click="del.remove()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span data-translate="moon.pdp.remove.action.delete">Delete</span>
+ </a>
+
+ <moon-loader ng-if="del.loading"></moon-loader>
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+
+</div>
diff --git a/old/moon_gui/static/app/pdp/action/pdp.controller.add.js b/old/moon_gui/static/app/pdp/action/pdp.controller.add.js
new file mode 100755
index 00000000..d1c34c79
--- /dev/null
+++ b/old/moon_gui/static/app/pdp/action/pdp.controller.add.js
@@ -0,0 +1,108 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('PDPAddController', PDPAddController);
+
+ PDPAddController.$inject = ['$scope', '$translate', 'alertService', 'formService', 'pdpService', 'policyService', 'utilService'];
+
+ function PDPAddController($scope, $translate, alertService, formService, pdpService, policyService, utilService) {
+
+ var add = this;
+
+ /*
+ *
+ */
+
+ add.form = {};
+
+ add.pdp = {};
+
+ add.policies = [];
+
+ add.selectedPolicy = null;
+
+ add.loading = false;
+ add.loadingPolicies = true;
+
+ add.create = createPDP;
+
+ resolvePolicies();
+
+ /*
+ *
+ */
+
+ /**
+ * This function return an array of all policies/template ids
+ */
+ function resolvePolicies() {
+
+ policyService.findAllWithCallback(function(policies){
+
+ add.policies = policies;
+ add.loadingPolicies = false;
+ });
+
+ }
+
+ function createPDP(pdp) {
+
+ if(formService.isInvalid(add.form)) {
+
+ formService.checkFieldsValidity(add.form);
+
+ } else {
+
+ add.loading = true;
+
+ pdpService.data.pdp.create({}, {
+
+ name: add.pdp.name,
+ description: add.pdp.description,
+ security_pipeline: [add.selectedPolicy.id],
+ keystone_project_id: null
+
+ }, createSuccess, createError);
+
+ }
+
+ function createSuccess(data) {
+
+ $translate('moon.pdp.add.success', { pdpName: pdp.name })
+ .then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ var createdPdp = utilService.transformOne(data, 'pdps');
+
+ add.loading = false;
+
+ $scope.$emit('event:pdpCreatedSuccess', createdPdp);
+
+ }
+
+ function createError(reason) {
+
+ $translate('moon.pdp.add.error', { pdpName: pdp.name })
+ .then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ add.loading = false;
+
+ $scope.$emit('event:pdpCreatedError');
+
+ }
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/pdp/action/pdp.controller.delete.js b/old/moon_gui/static/app/pdp/action/pdp.controller.delete.js
new file mode 100755
index 00000000..62557864
--- /dev/null
+++ b/old/moon_gui/static/app/pdp/action/pdp.controller.delete.js
@@ -0,0 +1,66 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('PDPDeleteController', PDPDeleteController);
+
+ PDPDeleteController.$inject = ['$scope', '$translate', 'alertService', 'pdpService'];
+
+ function PDPDeleteController($scope, $translate, alertService, pdpService) {
+
+ var del = this;
+
+ /*
+ *
+ */
+
+ del.pdp = $scope.pdp;
+ del.loading = false;
+ del.remove = deletePDP;
+
+ /*
+ *
+ */
+
+ function deletePDP() {
+ del.loading = true;
+
+ pdpService.data.pdp.remove({pdp_id: del.pdp.id}, deleteSuccess, deleteError);
+
+ function deleteSuccess(data) {
+
+ $translate('moon.pdp.remove.success', { pdpName: del.pdp.name })
+ .then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ del.loading = false;
+
+ $scope.$emit('event:pdpDeletedSuccess', del.pdp);
+
+ }
+
+ function deleteError(reason) {
+
+ $translate('moon.pdp.remove.error', { pdpName: del.pdp.name })
+ .then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ del.loading = false;
+
+ $scope.$emit('event:pdpDeletedError', del.pdp);
+
+ }
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/pdp/edit/pdp-edit-basic.tpl.html b/old/moon_gui/static/app/pdp/edit/pdp-edit-basic.tpl.html
new file mode 100755
index 00000000..887d81ca
--- /dev/null
+++ b/old/moon_gui/static/app/pdp/edit/pdp-edit-basic.tpl.html
@@ -0,0 +1,65 @@
+<div class="row">
+
+ <form class="form-horizontal" role="form" name="edit.form">
+
+ <div class="form-group">
+
+ <label for="id" class="col-sm-3 control-label" data-translate="moon.pdp.edit.basic.form.id">Id</label>
+
+ <div class="col-sm-6">
+
+ <input name="id" id="id" disabled class="form-control" type="text" data-ng-model="edit.pdpToEdit.id" required />
+
+ </div>
+
+ </div>
+
+ <div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}">
+
+ <label for="name" class="col-sm-3 control-label" data-translate="moon.pdp.edit.basic.form.name">Name</label>
+
+ <div class="col-sm-6">
+
+ <input name="name" id="name" class="form-control" type="text" data-ng-model="edit.pdpToEdit.name" required />
+
+ <div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid">
+ <small class="error" ng-show="edit.form.name.$error.required" data-translate="moon.pdp.edit.basic.check.name.required">Name is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <label for="description" class="col-sm-3 control-label" data-translate="moon.pdp.edit.basic.form.description">Description</label>
+ <div class="col-sm-6">
+ <textarea id="description" name="description" class="form-control" data-ng-model="edit.pdpToEdit.description"></textarea>
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <div class="col-sm-2 col-sm-offset-3">
+
+ <a href="" ng-disabled="edit.loading" ng-click="edit.init()" class="btn btn-default">
+ <span data-translate="moon.pdp.edit.basic.action.init">Init</span>
+ </a>
+ </div>
+
+ <div class="col-sm-4 col-sm-offset-2">
+
+ <a href="" ng-disabled="edit.loading" ng-click="edit.editPdp()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-save"></span>
+ <span data-translate="moon.pdp.edit.basic.action.update">Update</span>
+ </a>
+
+ <moon-loader ng-if="edit.loading"></moon-loader>
+ </div>
+
+ </div>
+
+ </form>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/pdp/edit/pdp-edit.tpl.html b/old/moon_gui/static/app/pdp/edit/pdp-edit.tpl.html
new file mode 100755
index 00000000..1fbd555a
--- /dev/null
+++ b/old/moon_gui/static/app/pdp/edit/pdp-edit.tpl.html
@@ -0,0 +1,64 @@
+<div class="container">
+
+ <div class="row">
+ <h3 class="pull-left" data-translate="moon.pdp.edit.title" data-translate-values="{ pdpName: edit.pdp.name }">Edit</h3>
+ </div>
+
+ <div class="row">
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4>
+ <span data-translate="moon.pdp.edit.basic.title" >Basic Information</span>
+ <a href="" ng-click="edit.editBasic = !edit.editBasic">
+ <span data-translate="moon.pdp.edit.update">Update</span>
+ <span class="glyphicon glyphicon-cog"></span>
+ </a>
+ </h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div ng-if="edit.editBasic">
+ <moon-p-d-p-edit-basic pdp="edit.pdp"></moon-p-d-p-edit-basic>
+ </div>
+
+ <div ng-if="!edit.editBasic">
+ <dl class="dl-horizontal">
+ <dt>Id</dt>
+ <dd ng-bind="edit.pdp.id"></dd>
+ <dt>Name</dt>
+ <dd ng-bind="edit.pdp.name"></dd>
+ <dt>Description</dt>
+ <dd ng-bind="edit.pdp.description"></dd>
+ </dl>
+ </div>
+
+ </div>
+
+ </div>
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.pdp.edit.policy.title" >Policies</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="row">
+
+ <moon-policy-mapped-list pdp="edit.pdp"></moon-policy-mapped-list>
+
+ </div>
+
+ </div>
+
+ </div>
+ </div>
+
+</div>
diff --git a/old/moon_gui/static/app/pdp/edit/pdp.controller.edit.js b/old/moon_gui/static/app/pdp/edit/pdp.controller.edit.js
new file mode 100755
index 00000000..41b73098
--- /dev/null
+++ b/old/moon_gui/static/app/pdp/edit/pdp.controller.edit.js
@@ -0,0 +1,50 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('PDPEditController', PDPEditController);
+
+ PDPEditController.$inject = ['$scope', '$rootScope', 'pdp', '$stateParams'];
+
+ function PDPEditController($scope, $rootScope, pdp, $stateParams) {
+
+ var edit = this;
+
+ edit.pdp = pdp;
+
+ edit.editBasic = false;
+
+ activate();
+
+ function activate(){
+
+ }
+
+ /*
+ * ---- events
+ */
+ var rootListeners = {
+
+ 'event:pdpUpdatedSuccess': $rootScope.$on('event:pdpUpdatedSuccess', pdpUpdatedSuccess)
+
+ };
+
+ for (var unbind in rootListeners) {
+ $scope.$on('$destroy', rootListeners[unbind]);
+ }
+
+ /**
+ * When the model is updated, this function refresh the current model with the new changes
+ * @param event
+ * @param pdp
+ */
+ function pdpUpdatedSuccess(event, pdp){
+
+ edit.pdp = pdp;
+
+ }
+ }
+
+})();
diff --git a/old/moon_gui/static/app/pdp/edit/pdp.edit.basic.dir.js b/old/moon_gui/static/app/pdp/edit/pdp.edit.basic.dir.js
new file mode 100755
index 00000000..402422b6
--- /dev/null
+++ b/old/moon_gui/static/app/pdp/edit/pdp.edit.basic.dir.js
@@ -0,0 +1,97 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonPDPEditBasic', moonPDPEditBasic);
+
+ moonPDPEditBasic.$inject = [];
+
+ function moonPDPEditBasic() {
+
+ return {
+ templateUrl : 'html/pdp/edit/pdp-edit-basic.tpl.html',
+ bindToController : true,
+ controller : moonPDPEditBasicController,
+ controllerAs : 'edit',
+ scope : {
+ pdp : '='
+ },
+ restrict : 'E',
+ replace : true
+ };
+ }
+
+ angular
+ .module('moon')
+ .controller('moonPDPEditBasicController', moonPDPEditBasicController);
+
+ moonPDPEditBasicController.$inject = ['$scope', 'pdpService', 'formService', 'alertService', '$translate', 'utilService'];
+
+ function moonPDPEditBasicController($scope, pdpService, formService, alertService, $translate, utilService){
+
+ var edit = this;
+
+ edit.editPdp = editPdp;
+ edit.init = init;
+
+ edit.form = {};
+
+ activate();
+
+ function activate(){
+
+ edit.pdp = $scope.edit.pdp;
+
+ edit.pdpToEdit = angular.copy(edit.pdp);
+
+ }
+
+ function editPdp(){
+
+ if(formService.isInvalid(edit.form)) {
+
+ formService.checkFieldsValidity(edit.form);
+
+ }else{
+
+ edit.loading = true;
+
+ pdpService.update(edit.pdpToEdit, updateSuccess, updateError);
+
+ }
+
+ function updateSuccess(data) {
+
+ var updatedPdp = utilService.transformOne(data, 'pdps');
+
+ $translate('moon.pdp.edit.basic.success', { pdpName: updatedPdp.name }).then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ edit.loading = false;
+
+ $scope.$emit('event:pdpUpdatedSuccess', updatedPdp);
+
+ }
+
+ function updateError(reason) {
+
+ $translate('moon.pdp.edit.basic.error', { pdpName: edit.pdp.name }).then( function(translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ edit.loading = false;
+
+ }
+ }
+
+ function init(){
+
+ edit.pdpToEdit = angular.copy(edit.pdp);
+
+ }
+ }
+
+})();
diff --git a/old/moon_gui/static/app/pdp/pdp-list.tpl.html b/old/moon_gui/static/app/pdp/pdp-list.tpl.html
new file mode 100755
index 00000000..8aa4e653
--- /dev/null
+++ b/old/moon_gui/static/app/pdp/pdp-list.tpl.html
@@ -0,0 +1,133 @@
+
+<div class="container">
+
+ <div>
+ <form class="form-inline pull-right">
+ <div class="form-group">
+ <div>
+ <input id="searchPDP" data-ng-model="list.search.query" type="text" class="form-control" placeholder="{{'moon.pdp.list.search.placeholder' | translate}}" />
+ </div>
+ </div>
+ <div class="form-group">
+ <div>
+ <button type="submit" class="btn btn-danger" data-ng-click="list.search.reset()" data-translate="moon.pdp.list.search.reset">Reset</button>
+ </div>
+ </div>
+ </form>
+ </div>
+
+ <div>&nbsp;</div>
+ <div>&nbsp;</div>
+ <div>&nbsp;</div>
+
+ <div class="row" >
+
+ <div class="table-responsive" data-role="table">
+
+ <table class="table table-striped table-hover" ng-table="list.table">
+
+ <thead>
+
+ <tr>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('name', 'asc'), 'sort-desc': list.table.isSortBy('name', 'desc') }"
+ ng-click="list.table.sorting('name', list.table.isSortBy('name', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.pdp.list.table.name">Name</div>
+ </th>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('security_pipeline', 'asc'), 'sort-desc': list.table.isSortBy('security_pipeline', 'desc') }"
+ ng-click="list.table.sorting('security_pipeline', list.table.isSortBy('policy', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.pdp.list.table.security_pipeline.number">Number of Securities</div>
+ </th>
+
+ <th class="customTables"
+ ng-class="{ 'sort-asc': list.table.isSortBy('project', 'asc'), 'sort-desc': list.table.isSortBy('project', 'desc') }"
+ ng-click="list.table.sorting('project', list.table.isSortBy('project', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.pdp.list.table.project">Project</div>
+ </th>
+
+ <th class="customTables">
+ <div data-translate="moon.pdp.list.action.title">Actions</div>
+ </th>
+
+ </tr>
+
+ </thead>
+
+ <tbody ng-if="!list.hasPDPs()">
+ <tr>
+ <td colspan="12"><span data-translate="moon.pdp.list.table.notFound">There is no PDP</span></td>
+ </tr>
+ </tbody>
+
+ <tbody ng-if="list.hasPDPs()">
+
+ <tr ng-repeat="pdp in $data | filter:list.search.find | orderBy:sort:reverse">
+ <td ng-bind="list.getPDPName(pdp)"></td>
+ <td ng-bind="list.getSecPipelineFromPdp(pdp).length"></td>
+ <td>
+ <div ng-if="list.isMapped(pdp)">
+
+ <div ng-if="!list.getProjectFromPDP(pdp)">
+ <moon-loader ng-if="!list.getProjectFromPDP(pdp)" ></moon-loader>
+ <em data-translate="moon.pdp.list.table.loading.project">Loading Project</em>
+ </div>
+
+ <div ng-if="list.getProjectFromPDP(pdp)">
+ <span ng-bind="pdp.project.name"></span>
+ </div>
+
+ </div>
+
+ <div ng-if="!list.isMapped(pdp)">
+ <span data-translate="moon.pdp.list.table.mapping.map">Is not mapped</span>
+ </div>
+ </td>
+ <td>
+ <div class="dropdown">
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.pdp.list.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu">
+
+ <li>
+ <a href="" ui-sref="moon.pdp.edit({id: pdp.id})">
+ <span class="glyphicon glyphicon-cog"></span>
+ <span class="control-label" data-translate="moon.pdp.list.action.edit">Edit</span>
+ </a>
+ </li>
+
+ <li class="divider"></li>
+
+ <li>
+ <a href="" ng-click="list.del.showModal(pdp)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.pdp.list.action.delete">Delete</span>
+ </a>
+ </li>
+ </ul>
+ </div>
+ </td>
+
+ </tr>
+
+ </tbody>
+
+ </table>
+
+ </div>
+
+ <div class="container">
+ <div class="form-inline form-group">
+ <a href="" ng-click="list.add.showModal()" class="btn btn-default">
+ <span class="glyphicon glyphicon-plus-sign"></span>
+ <span data-translate="moon.pdp.list.action.add">Add PDP</span>
+ </a>
+ </div>
+ </div>
+
+ </div>
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/pdp/pdp.controller.list.js b/old/moon_gui/static/app/pdp/pdp.controller.list.js
new file mode 100755
index 00000000..a831cfe3
--- /dev/null
+++ b/old/moon_gui/static/app/pdp/pdp.controller.list.js
@@ -0,0 +1,284 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('PDPListController', PDPListController);
+
+ PDPListController.$inject = [
+ '$rootScope',
+ '$scope',
+ '$filter',
+ '$modal',
+ 'NgTableParams',
+ 'pdps',
+ 'projectService'];
+
+ function PDPListController($rootScope,
+ $scope,
+ $filter,
+ $modal,
+ NgTableParams,
+ pdps,
+ projectService) {
+
+ var list = this;
+
+ list.pdps = pdps;
+ list.mappings = [];
+
+
+ list.getPDPs = getPDPs;
+ list.hasPDPs = hasPDPs;
+ list.getPDPName = getPDPName;
+ list.isMapped = isMapped;
+ list.getProjectFromPDP = getProjectFromPDP;
+ list.getidFromPDP = getidFromPDP;
+
+ list.table = {};
+
+ list.addPDP = addPDP;
+ list.deletePDP = deletePDP;
+ list.refreshPDPs = refreshPDPs;
+ list.updatePDPs = updatePDPs;
+
+ list.getMappedProjectName = getMappedProjectName;
+ list.getSecPipelineFromPdp = getSecPipelineFromPdp;
+
+ list.search = { query: '',
+ find: searchPDP,
+ reset: searchReset };
+
+ list.add = { modal: $modal({ template: 'html/pdp/action/pdp-add.tpl.html', show: false }),
+ showModal: showAddModal };
+
+ list.del = { modal: $modal({ template: 'html/pdp/action/pdp-delete.tpl.html', show: false }),
+ showModal: showDeleteModal };
+
+ activate();
+
+ function activate(){
+ newPDPsTable();
+ }
+
+ /*
+ * ---- events
+ */
+
+ var rootListeners = {
+
+ 'event:pdpCreatedSuccess': $rootScope.$on('event:pdpCreatedSuccess', pdpCreatedSuccess),
+ 'event:pdpCreatedError': $rootScope.$on('event:pdpCreatedError', pdpCreatedError),
+
+ 'event:pdpDeletedSuccess': $rootScope.$on('event:pdpDeletedSuccess', pdpDeletedSuccess),
+ 'event:pdpDeletedError': $rootScope.$on('event:pdpDeletedError', pdpDeletedError),
+
+ };
+
+ _.each(rootListeners, function(unbind){
+ $scope.$on('$destroy', rootListeners[unbind]);
+ });
+
+ /*
+ *
+ */
+
+ /**
+ * Function getting an array of PDP JSON
+ * @return An array of valid pdp.
+ */
+ function getPDPs() {
+ return (list.pdps) ? list.pdps : [];
+ }
+
+ function hasPDPs() {
+ return list.getPDPs().length > 0;
+ }
+
+ function addPDP(pdp) {
+ list.pdps.push(pdp);
+ }
+
+ function deletePDP(pdp) {
+
+ list.pdps = _.chain(list.pdps).reject({id: pdp.id}).value();
+
+ }
+
+ function refreshPDPs() {
+
+ list.table.total(list.pdps.length);
+ list.table.reload();
+
+ }
+
+ function updatePDPs(pdp) {
+
+ _(_.values(list.getPDPs())).each(function(anPDP) {
+ if(anPDP.id === pdp.id) {
+ //@todo: Determine what this code should have been designed to do
+ anPDP = _.clone(pdp);
+ }
+ });
+
+ return list.pdps;
+
+ }
+
+ /**
+ * Get the id from an PDP
+ * @param pdp The inspected pdp
+ * @returns {*} Its UUID
+ */
+ function getidFromPDP(pdp) {
+ return pdp.id;
+ }
+
+ function getMappedProjectName(pdp) {
+ return pdp.tenant.name;
+ }
+
+ /**
+ * Get the name of the PDP
+ * @param pdp The PDP to inspect
+ * @returns {*} Its name.
+ */
+ function getPDPName(pdp) {
+ return (pdp) ? pdp.name : '';
+ }
+
+ function isMapped(pdp) {
+ return !_.isNull(pdp.keystone_project_id);
+ }
+
+ /**
+ * Prerequisite : before calling this method, isMapped should return true before
+ * @param pdp
+ * @returns false or {*}, false if the project is currently loading
+ */
+ function getProjectFromPDP(pdp) {
+
+ if(_.has(pdp, 'project')){
+ return pdp.project;
+ }
+
+ // if the call has not been made
+ if(!_.has(pdp, 'callPdpInProgress')){
+
+ pdp.callPdpInProgress = true;
+
+ projectService.findOne(pdp.keystone_project_id, function(project){
+ pdp.callPdpInProgress = false;
+ pdp.project = project;
+ return pdp.project;
+ });
+ }
+
+ // if the call is in progress return false
+ return false;
+ }
+
+ /**
+ * Generate a table item, directly usable by the rendering engine
+ * @returns {{}|*} the table
+ */
+ function newPDPsTable() {
+
+ list.table = new NgTableParams({
+
+ page: 1, // show first page
+ count: 10, // count per page
+
+ }, {
+
+ total: function () { return list.getPDPs().length; }, // length of data
+ getData: function($defer, params) {
+
+ var orderedData = params.sorting() ? $filter('orderBy')(list.getPDPs(), params.orderBy()) : list.getPDPs();
+ $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
+
+ },
+ $scope: { $data: {} }
+
+ });
+
+ return list.table;
+
+ }
+
+
+ /*
+ * --- search
+ */
+
+ /**
+ * Indicate if an pdp having a specified name exists
+ * @param pdp Searched name
+ * @returns {boolean} True if a corresponding pdp is found, false otherwise
+ */
+ function searchPDP(pdp){
+ return list.getPDPName(pdp).indexOf(list.search.query) !== -1 || list.getSecPipelineFromPdp(pdp).indexOf(list.search.query) !== -1 ;
+ }
+
+ function getSecPipelineFromPdp(pdp){
+ return (pdp.security_pipeline) ? pdp.security_pipeline : [];
+ }
+
+ /**
+ * Blank the search field
+ */
+ function searchReset() {
+ list.search.query = '';
+ }
+
+ /*
+ * ---- add
+ */
+
+ function showAddModal() {
+ list.add.modal.$promise.then(list.add.modal.show);
+ }
+
+ function pdpCreatedSuccess(event, pdp) {
+
+ list.addPDP(pdp);
+ list.refreshPDPs();
+
+ list.add.modal.hide();
+
+ }
+
+ function pdpCreatedError(event, pdp) {
+ list.add.modal.hide();
+ }
+
+ /*
+ * ---- delete
+ */
+
+ function showDeleteModal(pdp) {
+ list.del.modal.$scope.pdp = pdp;
+ list.del.modal.$promise.then(list.del.modal.show);
+ }
+
+ function pdpDeletedSuccess(event, pdp) {
+
+ list.deletePDP(pdp);
+ list.refreshPDPs();
+
+ list.del.modal.hide();
+
+ }
+
+ function pdpDeletedError() {
+ list.del.modal.hide();
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/policy/action/mapping/policy-map.tpl.html b/old/moon_gui/static/app/policy/action/mapping/policy-map.tpl.html
new file mode 100755
index 00000000..8b787f14
--- /dev/null
+++ b/old/moon_gui/static/app/policy/action/mapping/policy-map.tpl.html
@@ -0,0 +1,64 @@
+<div ng-controller="PolicyMapController as map" class="modal" tabindex="-1" data-role="modalMappingPolicy">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.policy.map.title" data-translate-values="{ pdpName: map.pdp.name}"></h4>
+ </div>
+
+ <div class="modal-body">
+
+ <form class="form-horizontal" role="form" name="map.form">
+
+ <div class="form-group" ng-class="{'has-error': map.form.policy.$dirty && (map.form.policy.$invalid || !map.selectedPolicy)}">
+
+ <label class="col-sm-3 control-label" data-translate="moon.policy.map.form.list">List of Policies</label>
+
+ <div class="col-sm-6">
+
+ <ui-select ng-model="map.selectedPolicy" name="policy" required>
+ <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match>
+ <ui-select-choices repeat="policy in map.policies">
+ <div ng-bind="policy.name" ng-value="policy"></div>
+ </ui-select-choices>
+ </ui-select>
+
+ <moon-loader ng-if="map.policiesLoading"></moon-loader>
+
+ <div class="help-block" ng-show="map.form.policy.$dirty && (map.form.policy.$invalid || !map.selectedPolicy)">
+ <small class="error" ng-show="map.form.policy.$error.required" data-translate="moon.policy.map.check.policy.required">Policy is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+ </form>
+
+ </div>
+
+ <div class="modal-footer">
+ <div class="btn-toolbar" style="float: right;">
+
+ <a href="" ng-click="$hide()" class="btn btn-default">
+ <span data-translate="moon.policy.map.action.cancel">Cancel</span>
+ </a>
+
+ <a href="" ng-disabled="map.mappingLoading" ng-click="map.map()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-link"></span>
+ <span data-translate="moon.policy.map.action.map">Map</span>
+ </a>
+
+ <moon-loader ng-if="map.mappingLoading"></moon-loader>
+
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+
+</div>
diff --git a/old/moon_gui/static/app/policy/action/mapping/policy-unmap.tpl.html b/old/moon_gui/static/app/policy/action/mapping/policy-unmap.tpl.html
new file mode 100755
index 00000000..a2cda52a
--- /dev/null
+++ b/old/moon_gui/static/app/policy/action/mapping/policy-unmap.tpl.html
@@ -0,0 +1,33 @@
+<div ng-controller="PolicyUnMapController as unmap" class="modal" tabindex="-1" data-role="modalUnmapPolicy">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.policy.unmap.title"></h4>
+ </div>
+
+ <div class="modal-body">
+ <span data-translate="moon.policy.unmap.content" data-translate-values="{ policyName: unmap.policy.name, pdpName: unmap.pdp.name }"></span>
+ </div>
+
+ <div class="modal-footer">
+ <div class="btn-toolbar" style="float: right;">
+ <a href="" ng-click="$hide()" class="btn btn-default">
+ <span data-translate="moon.policy.unmap.action.cancel">Cancel</span>
+ </a>
+ <a href="" ng-disabled="unmap.unMappingLoading" ng-click="unmap.unmap()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span data-translate="moon.policy.unmap.action.unmap">Unmap</span>
+ </a>
+ <moon-loader ng-if="unmap.unMappingLoading"></moon-loader>
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/action/mapping/policy.controller.map.js b/old/moon_gui/static/app/policy/action/mapping/policy.controller.map.js
new file mode 100755
index 00000000..6ad8caa7
--- /dev/null
+++ b/old/moon_gui/static/app/policy/action/mapping/policy.controller.map.js
@@ -0,0 +1,106 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('PolicyMapController', PolicyMapController);
+
+ PolicyMapController.$inject = ['$scope', 'alertService', '$translate', 'formService', 'policyService', 'pdpService', 'utilService'];
+
+ function PolicyMapController($scope, alertService, $translate, formService, policyService, pdpService, utilService ) {
+
+ var map = this;
+
+ /*
+ *
+ */
+
+ map.pdps = [];
+
+ map.pdp = $scope.pdp;
+
+ map.addPolicyToList = false;
+
+ map.map = mapToPdp;
+
+ activate();
+
+ function activate() {
+
+ resolvePolicies();
+
+ }
+
+ function resolvePolicies() {
+
+ map.policiesLoading = true;
+
+ policyService.findAllWithCallback(function(policies){
+ map.policies = policies;
+ map.policiesLoading = false;
+ }
+ );
+
+ }
+
+ function mapToPdp() {
+
+ if (formService.isInvalid(map.form)) {
+
+ formService.checkFieldsValidity(map.form);
+
+ } else {
+
+ map.mappingLoading = true;
+
+ var pdpToSend = angular.copy(map.pdp);
+
+ pdpToSend.security_pipeline.push(map.selectedPolicy.id);
+
+ pdpService.update(pdpToSend, mapSuccess, mapError);
+
+ }
+
+ function mapSuccess(data) {
+
+ var pdpReceived = utilService.transformOne(data, 'pdps');
+
+
+ $translate('moon.policy.map.success', {pdpName: pdpReceived.name, policyName: map.selectedPolicy.name}).then(function (translatedValue) {
+
+ alertService.alertSuccess(translatedValue);
+
+ });
+
+ map.mappingLoading = false;
+
+ $scope.$emit('event:policyMapToPdpSuccess', pdpReceived);
+
+ }
+
+ function mapError(response) {
+
+ $translate('moon.policy.map.error', {
+
+ pdpName: map.pdp.name,
+ policyName: map.selectedPolicy.name
+
+ }).then(function (translatedValue) {
+
+ alertService.alertError(translatedValue);
+
+ });
+
+ map.mappingLoading = false;
+
+ $scope.$emit('event:policyMapToPdpError');
+
+ }
+ }
+
+
+
+ }
+
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/action/mapping/policy.controller.unmap.js b/old/moon_gui/static/app/policy/action/mapping/policy.controller.unmap.js
new file mode 100755
index 00000000..d309ec0f
--- /dev/null
+++ b/old/moon_gui/static/app/policy/action/mapping/policy.controller.unmap.js
@@ -0,0 +1,74 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('PolicyUnMapController', PolicyUnMapController);
+
+ PolicyUnMapController.$inject = ['$scope', '$translate', 'alertService', 'pdpService', 'utilService'];
+
+ function PolicyUnMapController($scope, $translate, alertService, pdpService, utilService) {
+
+ var unmap = this;
+
+ /*
+ *
+ */
+
+ unmap.pdp = $scope.pdp;
+ unmap.policy = $scope.policy;
+
+ unmap.unMappingLoading = false;
+
+ unmap.unmap = unMapPolicyToPdp;
+
+ /*
+ *
+ */
+
+ function unMapPolicyToPdp() {
+
+ unmap.unMappingLoading = true;
+
+ var pdpToUpdate = angular.copy(unmap.pdp);
+
+ pdpToUpdate.security_pipeline = _.without(pdpToUpdate.security_pipeline, unmap.policy.id);
+
+ pdpService.update(pdpToUpdate, unMapSuccess, unMapError);
+
+ function unMapSuccess(data) {
+
+ $translate('moon.policy.unmap.success', { pdpName: unmap.pdp.name, policyName: unmap.policy.name })
+ .then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ unmap.unMappingLoading = false;
+
+ $scope.$emit('event:policyUnMappedToPdpSuccess', utilService.transformOne(data, 'pdps'));
+
+ }
+
+ function unMapError(reason) {
+
+ $translate('moon.policy.unmap.error', { pdpName: unmap.pdp.name, policyName: unmap.policy.name })
+ .then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ unmap.unMappingLoading = false;
+
+ $scope.$emit('event:policyUnMappedToPdpError');
+
+ }
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/policy/action/policy-add.tpl.html b/old/moon_gui/static/app/policy/action/policy-add.tpl.html
new file mode 100755
index 00000000..d20c41be
--- /dev/null
+++ b/old/moon_gui/static/app/policy/action/policy-add.tpl.html
@@ -0,0 +1,113 @@
+<div ng-controller="PolicyAddController as add" class="modal" tabindex="-1" data-role="modalAddPolicy">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.policy.add.title"></h4>
+ </div>
+
+ <div class="modal-body">
+
+ <form class="form-horizontal" role="form" name="add.form">
+
+ <div class="form-group" ng-class="{'has-error': add.form.name.$invalid && add.form.name.$dirty}">
+
+ <label for="name" class="col-sm-3 control-label" data-translate="moon.policy.add.form.name">Name</label>
+
+ <div class="col-sm-6">
+
+ <input name="name" id="name" class="form-control" type="text" data-ng-model="add.policy.name" required />
+
+ <div class="help-block" ng-show="add.form.name.$dirty && add.form.name.$invalid">
+ <small class="error" ng-show="add.form.name.$error.required" data-translate="moon.policy.add.check.name.required">Name is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+
+ <div class="form-group" ng-class="{'has-error': add.form.genre.$dirty && (add.form.genre.$invalid || !add.selectedGenre)}">
+
+ <label class="col-sm-3 control-label" data-translate="moon.policy.add.form.genre">Genre</label>
+
+ <div class="col-sm-6">
+
+ <ui-select ng-model="add.selectedGenre" name="genre" required>
+ <ui-select-match placeholder="(None)">{{$select.selected}}</ui-select-match>
+ <ui-select-choices repeat="genre in add.genres">
+ <div ng-value="genre">{{genre}}</div>
+ </ui-select-choices>
+ </ui-select>
+
+ <div class="help-block" ng-show="add.form.genre.$dirty && (add.form.genre.$invalid || !add.selectedPolicy)">
+ <small class="error" ng-show="add.form.genre.$error.required" data-translate="moon.policy.add.check.genre.required">Genre is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+ <div class="form-group" ng-class="{'has-error': add.form.model.$dirty && (add.form.model.$invalid || !add.selectedModel)}">
+
+ <label class="col-sm-3 control-label" data-translate="moon.policy.add.form.model">Models</label>
+
+ <div class="col-sm-6">
+
+ <ui-select ng-model="add.selectedModel" name="model" required>
+ <ui-select-match placeholder="(None)">{{$select.selected.name}}</ui-select-match>
+ <ui-select-choices repeat="model in add.models">
+ <div ng-value="model">{{model.name}}</div>
+ </ui-select-choices>
+ </ui-select>
+
+ <moon-loader ng-if="add.modelsLoading"></moon-loader>
+
+ <div class="help-block" ng-show="add.form.model.$dirty && (add.form.model.$invalid || !add.selectedModel)">
+ <small class="error" ng-show="add.form.model.$error.required" data-translate="moon.policy.add.check.model.required">Model is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+
+ <div class="form-group">
+
+ <label for="description" class="col-sm-3 control-label" data-translate="moon.policy.add.form.description">Description</label>
+ <div class="col-sm-6">
+ <textarea id="description" name="description" class="form-control" data-ng-model="add.policy.description"></textarea>
+ </div>
+
+ </div>
+
+ </form>
+
+ </div>
+
+ <div class="modal-footer">
+
+ <div class="btn-toolbar" style="float: right;">
+
+ <a href="" ng-click="$hide()" class="btn btn-default">
+ <span data-translate="moon.policy.add.action.cancel">Cancel</span>
+ </a>
+
+ <a href="" ng-disabled="add.loading" ng-click="add.create()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-save"></span>
+ <span data-translate="moon.policy.add.action.create">Create Policy</span>
+ </a>
+ <moon-loader ng-if="add.loading"></moon-loader>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ </div>
+
+</div>
diff --git a/old/moon_gui/static/app/policy/action/policy-delete.tpl.html b/old/moon_gui/static/app/policy/action/policy-delete.tpl.html
new file mode 100755
index 00000000..3b5df88b
--- /dev/null
+++ b/old/moon_gui/static/app/policy/action/policy-delete.tpl.html
@@ -0,0 +1,40 @@
+<div ng-controller="PolicyDeleteController as del" class="modal" tabindex="-1" data-role="modalDeletePolicy">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.policy.remove.title"></h4>
+ </div>
+
+ <div class="modal-body">
+ <p><span data-translate="moon.policy.remove.content.query" data-translate-values="{ policyName: del.policy.name }"></span></p>
+
+ </div>
+
+ <div class="modal-footer">
+
+ <div class="btn-toolbar" style="float: right;">
+
+ <a href="" ng-click="$hide()" class="btn btn-default">
+ <span data-translate="moon.policy.remove.action.cancel">Cancel</span>
+ </a>
+
+ <a href="" ng-disabled="del.loading" ng-click="del.remove()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span data-translate="moon.policy.remove.action.delete">Delete</span>
+ </a>
+
+ <moon-loader ng-if="del.loading" ></moon-loader>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/action/policy.controller.add.js b/old/moon_gui/static/app/policy/action/policy.controller.add.js
new file mode 100755
index 00000000..0320c2e9
--- /dev/null
+++ b/old/moon_gui/static/app/policy/action/policy.controller.add.js
@@ -0,0 +1,113 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('PolicyAddController', PolicyAddController);
+
+ PolicyAddController.$inject = ['$scope', '$translate', 'alertService', 'formService', 'policyService', 'utilService', 'modelService'];
+
+ function PolicyAddController($scope, $translate, alertService, formService, policyService, utilService, modelService) {
+
+ var add = this;
+
+ /*
+ *
+ */
+
+ add.loading = false;
+
+ add.form = {};
+
+ add.policy = {name: null, genre: null, description: null, model_id: null};
+
+ add.genres = ['admin', 'authz'];
+
+ add.models = [];
+
+ add.modelsLoading = true;
+
+ add.create = createPolicy;
+
+
+ activate();
+
+ function activate(){
+
+ resolveModels();
+
+ }
+
+ /*
+ *
+ */
+
+ function resolveModels() {
+
+ modelService.findAllWithCallBack(resolveModelsCallback);
+
+ }
+
+ function resolveModelsCallback(models) {
+
+ add.models = models;
+
+ add.modelsLoading = false;
+
+ }
+
+
+ function createPolicy() {
+
+ if(formService.isInvalid(add.form)) {
+
+ formService.checkFieldsValidity(add.form);
+
+ } else {
+
+
+ add.loading = true;
+
+ policyService.data.policy.create({}, {
+
+ name: add.policy.name,
+ description: add.policy.description,
+ genre: [add.selectedGenre],
+ model_id: add.selectedModel.id
+
+ }, createSuccess, createError);
+
+ }
+
+ function createSuccess(data) {
+
+ var createdPolicy = utilService.transformOne(data, 'policies');
+
+ $translate('moon.policy.add.success', { policyName: createdPolicy.name }).then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ add.loading = false;
+
+ $scope.$emit('event:policyCreatedSuccess', createdPolicy);
+
+ }
+
+ function createError(reason) {
+
+ $translate('moon.policy.add.error', { policyName: add.model.name }).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ add.loading = false;
+
+ $scope.$emit('event:policyCreatedError', add.project);
+
+ }
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/policy/action/policy.controller.delete.js b/old/moon_gui/static/app/policy/action/policy.controller.delete.js
new file mode 100755
index 00000000..9a718ddc
--- /dev/null
+++ b/old/moon_gui/static/app/policy/action/policy.controller.delete.js
@@ -0,0 +1,69 @@
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('PolicyDeleteController', PolicyDeleteController);
+
+ PolicyDeleteController.$inject = ['$scope', '$translate', 'alertService', 'policyService'];
+
+ function PolicyDeleteController($scope, $translate, alertService, policyService) {
+
+ var del = this;
+
+ /*
+ *
+ */
+
+ del.policy = $scope.policy;
+ del.loading = false;
+
+ del.remove = deletePolicy;
+
+ activate();
+
+ /**
+ *
+ */
+
+ function activate(){
+
+ }
+
+
+ function deletePolicy(){
+
+ del.loading = true;
+
+ policyService.delete(del.policy, deleteSuccess, deleteError);
+
+ function deleteSuccess(data) {
+
+ $translate('moon.policy.remove.success', { policyName: del.policy.name }).then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ del.loading = false;
+
+ $scope.$emit('event:policyDeletedSuccess', del.policy);
+
+ }
+
+ function deleteError(reason) {
+
+ $translate('moon.policy.remove.error', { policyName: del.policy.name, errorCode: reason.data.error.code, message : reason.data.error.message } ).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ del.loading = false;
+
+ $scope.$emit('event:policyDeletedError', del.policy);
+
+ }
+
+ }
+ }
+
+})();
diff --git a/old/moon_gui/static/app/policy/edit/parameter/assignments/assignments-edit.tpl.html b/old/moon_gui/static/app/policy/edit/parameter/assignments/assignments-edit.tpl.html
new file mode 100755
index 00000000..9069dcd0
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/assignments/assignments-edit.tpl.html
@@ -0,0 +1,165 @@
+<div>
+
+ <div class="col-md-12 col-sm-12 col-xs-12">
+
+ <form ng-if="!edit.fromList" class="form-horizontal" role="form" name="edit.form">
+
+ <!-- Select Policy -->
+ <div class="form-group" ng-class="{'has-error': edit.form.policyList.$invalid && edit.form.policyList.$dirty}" >
+
+ <label for="policyList" class="col-sm-3 control-label" data-translate="moon.policy.assignments.edit.policies">Policy List</label>
+
+ <div class="col-sm-6" ng-if="edit.loadingPolicies" >
+ <moon-loader></moon-loader>
+ </div>
+
+ <div class="col-sm-6" ng-if="!edit.loadingPolicies" >
+
+ <ui-select ng-model="edit.selectedPolicy" name="policyList" id="policyList" required>
+
+ <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match>
+ <ui-select-choices repeat="aPolicy in edit.policyList">
+ <div ng-value="aPolicy" ng-bind="aPolicy.name"></div>
+ </ui-select-choices>
+
+ </ui-select>
+
+ <div class="help-block" ng-show="edit.form.policyList.$dirty && edit.form.policyList.$invalid">
+ <small class="error" ng-show="edit.form.policyList.$error.required" data-translate="moon.policy.assignments.edit.check.policy.required">Policy is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+ <!-- Select Perimeter -->
+ <div class="form-group" ng-class="{'has-error': edit.form.perimeterList.$invalid && edit.form.perimeterList.$dirty}" >
+
+ <label for="perimeterList" class="col-sm-3 control-label" data-translate="moon.policy.assignments.edit.perimeters">Perimeter List</label>
+
+ <div class="col-sm-6" ng-if="edit.loadingPerimeters" >
+ <moon-loader></moon-loader>
+ </div>
+
+ <div class="col-sm-6" ng-if="!edit.loadingPerimeters" >
+
+ <ui-select ng-model="edit.selectedPerimeter" name="perimeterList" id="perimeterList" required>
+
+ <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match>
+ <ui-select-choices repeat="aPerimeter in edit.perimeterList">
+ <div ng-value="aPerimeter" ng-bind="aPerimeter.name"></div>
+ </ui-select-choices>
+
+ </ui-select>
+
+ <div class="help-block" ng-show="edit.form.perimeterList.$dirty && edit.form.perimeterList.$invalid">
+ <small class="error" ng-show="edit.form.perimeterList.$error.required" data-translate="moon.policy.assignments.edit.check.perimeter.required">Perimeter is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+ <!-- Select Category -->
+ <div class="form-group" ng-class="{'has-error': edit.form.categoryList.$invalid && edit.form.categoryList.$dirty}" >
+
+ <label for="categoryList" class="col-sm-3 control-label" data-translate="moon.policy.assignments.edit.categories">Category List</label>
+
+ <div class="col-sm-6" ng-if="edit.loadingCategories" >
+ <moon-loader></moon-loader>
+ </div>
+
+ <div class="col-sm-6" ng-if="!edit.loadingCategories" >
+
+ <ui-select ng-model="edit.selectedCategory" name="categoryList" id="categoryList" required>
+
+ <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match>
+ <ui-select-choices repeat="aCategory in edit.categoryList">
+ <div ng-value="aCategory" ng-bind="aCategory.name"></div>
+ </ui-select-choices>
+
+ </ui-select>
+
+ <div class="help-block" ng-show="edit.form.categoryList.$dirty && edit.form.categoryList.$invalid">
+ <small class="error" ng-show="edit.form.categoryList.$error.required" data-translate="moon.policy.assignments.edit.check.category.required">Category is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+ <!-- Select Data -->
+ <div class="form-group" ng-if="edit.selectedCategory" ng-class="{'has-error': edit.form.dataList.$invalid && edit.form.dataList.$dirty}" >
+
+ <label for="dataList" class="col-sm-3 control-label" data-translate="moon.policy.assignments.edit.data">Data List</label>
+
+ <div class="col-sm-6" ng-if="edit.loadingData" >
+ <moon-loader></moon-loader>
+ </div>
+
+ <div class="col-sm-4" ng-if="!edit.loadingData" >
+
+ <ui-select ng-model="edit.selectedData" name="dataList" id="dataList">
+
+ <ui-select-match placeholder="(None)" ng-bind="edit.getName($select.selected)"></ui-select-match>
+ <ui-select-choices repeat="aData in edit.dataToBeSelected">
+ <div ng-value="aData" ng-bind="edit.getName(aData)"></div>
+ </ui-select-choices>
+
+ </ui-select>
+
+ <div class="help-block" ng-show="edit.form.dataList.$dirty && edit.form.dataList.$invalid || !edit.assignementsAttributeValid">
+ <small class="error" ng-show="edit.form.dataList.$error.required || !edit.assignementsAttributeValid" data-translate="moon.policy.assignments.edit.check.data.required">Data is required</small>
+ </div>
+
+ </div>
+
+ <div class="col-sm-2 text-center">
+ <a href="" ng-if="edit.selectedData"
+ ng-click="edit.addSelectedData()"><span style="font-size:1.5em; line-height: 1.5em;" class="glyphicon glyphicon-plus-sign"></span></a>
+ </div>
+
+ </div>
+
+ <!-- Selected DataList -->
+ <div class="form-group" ng-if="!edit.loadingData">
+
+ <label class="col-sm-3 control-label" data-translate="moon.policy.assignments.edit.selectedData">Selected Data)</label>
+
+ <div class="col-sm-6">
+
+ <ul>
+
+ <li ng-repeat="(key, value) in edit.selectedDataList">
+
+ <span ng-bind="edit.getName(value)" ></span> <a href="" ng-click="edit.removeSelectedData(value)"><span style="font-size:1.5em; line-height: 1.5em" class="glyphicon glyphicon-remove"></span></a>
+
+ </li>
+
+ </ul>
+
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <div class="pull-right">
+
+ <a href="" ng-disabled="edit.loading" ng-click="edit.create()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-save"></span>
+ <span data-translate="moon.policy.assignments.edit.action.create">Create</span>
+ </a>
+
+ <moon-loader ng-if="edit.loading"></moon-loader>
+
+ </div>
+
+ </div>
+
+
+ </form>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/parameter/assignments/assignments-list.tpl.html b/old/moon_gui/static/app/policy/edit/parameter/assignments/assignments-list.tpl.html
new file mode 100755
index 00000000..34bbc7a8
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/assignments/assignments-list.tpl.html
@@ -0,0 +1,335 @@
+<div>
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.assignments.subject.title">List of associated Subjects</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive">
+
+ <table class="table table-striped">
+
+ <thead>
+ <tr>
+ <th data-translate="moon.policy.assignments.table.perimeter.name">Perimeter name</th>
+ <th data-translate="moon.policy.assignments.table.category.name">Category name</th>
+ <th data-translate="moon.policy.assignments.table.data.name">Data name</th></tr>
+ </thead>
+
+ <moon-loader ng-if="list.loadingSub"></moon-loader>
+
+ <tbody ng-if="!list.loadingSub && list.getSubjects().length > 0">
+
+ <tr ng-repeat="(key, value) in list.subjects">
+
+ <td>
+
+ <div ng-if="!list.getPerimeterFromAssignment(value, list.typeOfSubject)">
+ <moon-loader ng-if="!list.getPerimeterFromAssignment(value)" ></moon-loader>
+ <em data-translate="moon.policy.assignments.table.loading.perimeter">Loading </em>
+ </div>
+
+ <div ng-if="list.getPerimeterFromAssignment(value)">
+ <span ng-bind="value.perimeter.name"></span>
+ </div>
+
+ </td>
+
+ <td>
+
+ <div ng-if="!list.getCategoryFromAssignment(value, list.typeOfSubject)">
+ <moon-loader ng-if="!list.getCategoryFromAssignment(value)" ></moon-loader>
+ <em data-translate="moon.policy.assignments.table.loading.category">Loading </em>
+ </div>
+
+ <div ng-if="list.getCategoryFromAssignment(value)">
+ <span ng-bind="value.category.name"></span>
+ </div>
+
+ </td>
+
+ <td>
+
+ <span ng-repeat="(index, id) in value.assignments">
+
+ <span ng-if="!list.getDataFromAssignmentsIndex(index, value, list.typeOfSubject)">
+ <moon-loader ng-if="!list.getDataFromAssignmentsIndex(index, value, list.typeOfSubject)" ></moon-loader>
+ </span>
+
+ <span ng-if="list.getDataFromAssignmentsIndex(index, value, list.typeOfSubject)">
+ <span ng-bind="value.assignments_value[index].data.name"></span>
+ <a href="" ng-if="!value.loader" ng-click="list.deleteSub(value, value.assignments_value[index].data.id)" >
+ <span>(</span><span class="glyphicon glyphicon-transfer"></span><span>)</span>
+ </a>
+ <span ng-if="index < value.assignments.length-1">,&nbsp;</span>
+ </span>
+
+ </span>
+
+ </td>
+
+ <td>
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>
+
+ </tr>
+ </tbody>
+
+
+ <tbody ng-if="!list.loadingSub && list.getSubjects().length === 0">
+ <tr>
+ <td data-translate="moon.policy.assignments.subject.notFound">There is no Subjects</td>
+ <td></td>
+ <td></td>
+ </tr>
+ </tbody>
+
+ </table>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div ng-if="list.editMode" class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.assignments.subject.add.title">Add a Subject Category</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <moon-assignments-edit policy="list.policy" assignments-type="list.typeOfSubject"></moon-assignments-edit>
+
+ </div>
+
+ </div>
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.assignments.object.title">List associated of Objects</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive">
+
+ <table class="table table-striped">
+
+ <thead>
+ <tr>
+ <th data-translate="moon.policy.assignments.table.perimeter.name">Perimeter name</th>
+ <th data-translate="moon.policy.assignments.table.category.name">Category name</th>
+ <th data-translate="moon.policy.assignments.table.data.name">Data name</th>
+ </tr>
+ </thead>
+
+ <moon-loader ng-if="list.loadingObj"></moon-loader>
+
+ <tbody ng-if="!list.loadingObj && list.getObjects().length > 0">
+ <tr ng-repeat="(key, value) in list.objects">
+ <td>
+
+ <div ng-if="!list.getPerimeterFromAssignment(value, list.typeOfObject)">
+ <moon-loader ng-if="!list.getPerimeterFromAssignment(value)" ></moon-loader>
+ <em data-translate="moon.policy.assignments.table.loading.perimeter">Loading </em>
+ </div>
+
+ <div ng-if="list.getPerimeterFromAssignment(value)">
+ <span ng-bind="value.perimeter.name"></span>
+ </div>
+
+ </td>
+
+ <td>
+
+ <div ng-if="!list.getCategoryFromAssignment(value, list.typeOfObject)">
+ <moon-loader ng-if="!list.getCategoryFromAssignment(value)" ></moon-loader>
+ <em data-translate="moon.policy.assignments.table.loading.category">Loading </em>
+ </div>
+
+ <div ng-if="list.getCategoryFromAssignment(value)">
+ <span ng-bind="value.category.name"></span>
+ </div>
+
+ </td>
+
+ <td>
+ <span ng-repeat="(index, id) in value.assignments">
+
+ <span ng-if="!list.getDataFromAssignmentsIndex(index, value, list.typeOfObject)">
+ <moon-loader ng-if="!list.getDataFromAssignmentsIndex(index, value, list.typeOfObject)" ></moon-loader>
+ </span>
+
+ <span ng-if="list.getDataFromAssignmentsIndex(index, value, list.typeOfObject)">
+
+ <span ng-if="value.assignments_value[index].data.name" ng-bind="value.assignments_value[index].data.name"></span>
+ <span ng-if="value.assignments_value[index].data.value.name" ng-bind="value.assignments_value[index].data.value.name"></span>
+ <a href="" ng-if="!value.loader" ng-click="list.deleteObj(value, value.assignments_value[index].data.id)" >
+ <span>(</span><span class="glyphicon glyphicon-transfer"></span><span>)</span>
+ </a>
+ <span ng-if="index < value.assignments.length-1">,&nbsp;</span>
+ </span>
+
+ </span>
+ </td>
+
+ </tr>
+ </tbody>
+
+ <tbody ng-if="!list.loadingObj && list.getObjects().length === 0">
+ <tr>
+ <td data-translate="moon.policy.assignments.object.notFound">There is no Objects</td>
+ <td></td>
+ <td></td>
+ </tr>
+ </tbody>
+
+ </table>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div ng-if="list.editMode" class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.assignments.object.add.title">Add an Object Category</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <moon-assignments-edit policy="list.policy" assignments-type="list.typeOfObject"></moon-assignments-edit>
+
+ </div>
+
+ </div>
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.assignments.action.title">List associated of Actions</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive">
+
+ <table class="table table-striped">
+
+ <thead>
+ <tr>
+ <th data-translate="moon.policy.assignments.table.perimeter.name">Perimeter name</th>
+ <th data-translate="moon.policy.assignments.table.category.name">Category name</th>
+ <th data-translate="moon.policy.assignments.table.data.name">Data name</th>
+ </tr>
+ </thead>
+
+ <moon-loader ng-if="list.loadingAct"></moon-loader>
+
+ <tbody ng-if="!list.loadingAct && list.getActions().length > 0">
+ <tr ng-repeat="(key, value) in list.actions">
+
+ <td>
+ <div ng-if="!list.getPerimeterFromAssignment(value, list.typeOfAction)">
+ <moon-loader ng-if="!list.getPerimeterFromAssignment(value)" ></moon-loader>
+ <em data-translate="moon.policy.assignments.table.loading.perimeter">Loading </em>
+ </div>
+
+ <div ng-if="list.getPerimeterFromAssignment(value)">
+ <span ng-bind="value.perimeter.name"></span>
+ </div>
+ </td>
+
+ <td>
+
+ <div ng-if="!list.getCategoryFromAssignment(value, list.typeOfAction)">
+ <moon-loader ng-if="!list.getCategoryFromAssignment(value)" ></moon-loader>
+ <em data-translate="moon.policy.assignments.table.loading.category">Loading </em>
+ </div>
+
+ <div ng-if="list.getCategoryFromAssignment(value)">
+ <span ng-bind="value.category.name"></span>
+ </div>
+
+ </td>
+
+ <td>
+
+ <span ng-repeat="(index, id) in value.assignments">
+
+ <span ng-if="!list.getDataFromAssignmentsIndex(index, value, list.typeOfAction)">
+ <moon-loader ng-if="!list.getDataFromAssignmentsIndex(index, value, list.typeOfAction)" ></moon-loader>
+ </span>
+
+ <span ng-if="list.getDataFromAssignmentsIndex(index, value, list.typeOfAction)">
+ <span ng-if="value.assignments_value[index].data.name" ng-bind="value.assignments_value[index].data.name"></span>
+ <span ng-if="value.assignments_value[index].data.value.name" ng-bind="value.assignments_value[index].data.value.name"></span>
+ <a href="" ng-if="!value.loader" ng-click="list.deleteAct(value, value.assignments_value[index].data.id)" >
+ <span>(</span><span class="glyphicon glyphicon-transfer"></span><span>)</span>
+ </a>
+ <span ng-if="index < value.assignments.length-1">,&nbsp;</span>
+ </span>
+
+ </span>
+
+ </td>
+ </tr>
+ </tbody>
+
+ <tbody ng-if="!list.loadingAct && list.getActions().length === 0">
+ <tr>
+ <td data-translate="moon.policy.assignments.action.notFound">There is no Actions</td>
+ <td></td>
+ <td></td>
+ </tr>
+ </tbody>
+
+ </table>
+
+ </div>
+
+
+ </div>
+
+ </div>
+
+ <div ng-if="list.editMode" class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.assignments.action.add.title">Add an Action Category</h4>
+
+ </div>
+
+ <div class="panel-body">.
+
+ <moon-assignments-edit policy="list.policy" assignments-type="list.typeOfAction"></moon-assignments-edit>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/parameter/assignments/assignments.edit.dir.js b/old/moon_gui/static/app/policy/edit/parameter/assignments/assignments.edit.dir.js
new file mode 100755
index 00000000..5297eccb
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/assignments/assignments.edit.dir.js
@@ -0,0 +1,439 @@
+(function () {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonAssignmentsEdit', moonAssignmentsEdit);
+
+ moonAssignmentsEdit.$inject = [];
+
+ function moonAssignmentsEdit() {
+
+ return {
+ templateUrl: 'html/policy/edit/parameter/assignments/assignments-edit.tpl.html',
+ bindToController: true,
+ controller: moonAssignmentsEditController,
+ controllerAs: 'edit',
+ scope: {
+ //Type can be 'ACTION', 'OBJECT', 'SUBJECT'
+ assignmentsType: '=',
+ policy: '='
+ },
+ restrict: 'E',
+ replace: true
+ };
+ }
+
+ angular
+ .module('moon')
+ .controller('moonAssignmentsEditController', moonAssignmentsEditController);
+
+ moonAssignmentsEditController.$inject = ['$scope', 'assignmentsService', 'alertService', '$translate', 'formService',
+ 'policyService', 'utilService', 'perimeterService', 'ASSIGNMENTS_CST',
+ 'metaDataService', 'dataService'];
+
+ function moonAssignmentsEditController($scope, assignmentsService, alertService, $translate, formService,
+ policyService, utilService, perimeterService, ASSIGNMENTS_CST,
+ metaDataService, dataService ) {
+
+ var edit = this;
+
+ edit.assignmentsType = $scope.edit.assignmentsType;
+ edit.policy = $scope.edit.policy;
+
+ edit.laoading = false;
+
+ edit.form = {};
+
+ edit.policyList = [];
+ edit.loadingPolicies = true;
+
+ edit.categoryList = [];
+ edit.loadingCategories = true;
+
+ edit.perimeterList = [];
+ edit.loadingPerimeters = true;
+
+ edit.dataList = [];
+ edit.dataToBeSelected = [];
+ edit.selectedDataList = [];
+ edit.loadingData = true;
+
+ edit.assignementsAttributeValid = true;
+
+ edit.addSelectedData = addSelectedData;
+ edit.removeSelectedData = removeSelectedData;
+ edit.getName = getName;
+ edit.create = createAssignments;
+
+ activate();
+
+ /*
+ *
+ */
+
+ function activate() {
+
+ edit.assignments = {id: null, category_id: null, data_id: null, policy_id: null};
+
+ loadAllPolicies();
+ loadAllCategories();
+
+ }
+
+ function createAssignments() {
+
+ edit.assignementsAttributeValid = true;
+
+ manageSelectedDataListy();
+
+ if(formService.isInvalid(edit.form)) {
+
+ formService.checkFieldsValidity(edit.form);
+
+ }else if(edit.assignementsAttributeValid){
+
+ startLoading();
+
+ var throwEvent = false;
+ edit.assignments.id = edit.selectedPerimeter.id;
+ edit.assignments.category_id = edit.selectedCategory.id;
+ edit.assignments.policy_id = edit.selectedPolicy.id;
+
+ var selectedDataListTemp = angular.copy(edit.selectedDataList);
+
+ _.each(selectedDataListTemp, function(elem){
+
+ edit.assignments.data_id = elem.id;
+
+ var assignmentsToSend = angular.copy(edit.assignments);
+
+ switch(edit.assignmentsType){
+
+ case ASSIGNMENTS_CST.TYPE.SUBJECT:
+
+ assignmentsService.subject.add(assignmentsToSend, edit.policy.id, createSuccess, createError);
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.OBJECT:
+
+ assignmentsService.object.add(assignmentsToSend, edit.policy.id, createSuccess, createError);
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.ACTION:
+
+ assignmentsService.action.add(assignmentsToSend, edit.policy.id, createSuccess, createError);
+ break;
+
+ default :
+
+ break;
+
+ }
+
+ });
+
+ throwEvent = true;
+
+ }
+
+ function createSuccess(data) {
+
+ var created = {};
+
+ switch(edit.assignmentsType){
+
+ case ASSIGNMENTS_CST.TYPE.SUBJECT:
+
+ created = utilService.transformOne(data, 'subject_assignments');
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.OBJECT:
+
+ created = utilService.transformOne(data, 'object_assignments');
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.ACTION:
+
+ created = utilService.transformOne(data, 'action_assignments');
+ break;
+
+ default:
+
+ break;
+
+ }
+
+ $translate('moon.policy.assignments.edit.create.success').then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ if(throwEvent && created.policy_id === edit.policy.id){
+
+ $scope.$emit('event:createAssignmentsFromAssignmentsEditSuccess', edit.assignmentsType);
+
+ activate();
+
+ stopLoading();
+
+ }else if(throwEvent){
+
+ activate();
+
+ stopLoading();
+
+ }
+
+ }
+
+ function createError(reason) {
+
+ $translate('moon.policy.rules.edit.action.add.create.error').then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ stopLoading();
+
+ }
+
+ }
+
+ $scope.$watch('edit.selectedPolicy', function(newValue){
+
+ if(!_.isUndefined(newValue)){
+
+ loadRelatedPerimeters();
+
+ }
+
+ });
+
+
+ $scope.$watch('edit.selectedCategory', function(newValue){
+
+ clearSelectedCategories();
+
+ if(!_.isUndefined(newValue)){
+
+ loadRelatedData(newValue.id);
+
+ }
+
+ });
+
+ function loadAllPolicies() {
+
+ edit.policyList = [];
+ edit.loadingPolicies = true;
+
+ policyService.findAllWithCallback( function(data) {
+
+ _.each(data, function(element){
+
+ if(element.id === edit.policy.id){
+ edit.selectedPolicy = element;
+ }
+
+ });
+
+ edit.policyList = data;
+ edit.loadingPolicies = false;
+
+ });
+ }
+
+ function loadRelatedPerimeters(){
+
+ edit.perimeterList = [];
+ edit.loadingPerimeters = true;
+
+ switch(edit.assignmentsType){
+
+ case ASSIGNMENTS_CST.TYPE.SUBJECT:
+
+ perimeterService.subject.findAllFromPolicyWithCallback(edit.selectedPolicy.id, callBackList);
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.OBJECT:
+
+ perimeterService.object.findAllFromPolicyWithCallback(edit.selectedPolicy.id,callBackList);
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.ACTION:
+
+ perimeterService.action.findAllFromPolicyWithCallback(edit.selectedPolicy.id, callBackList);
+ break;
+
+ default :
+
+ edit.perimeterList = [];
+ edit.loadingPerimeters = false;
+ break;
+
+ }
+
+ function callBackList(list){
+
+ edit.perimeterList = list;
+
+ edit.loadingPerimeters = false;
+
+ }
+ }
+
+ function loadAllCategories(){
+
+ edit.categoryList = [];
+ edit.loadingCategories = true;
+
+ switch(edit.assignmentsType){
+
+ case ASSIGNMENTS_CST.TYPE.SUBJECT:
+
+ metaDataService.subject.findAllWithCallback(callBackList);
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.OBJECT:
+
+ metaDataService.object.findAllWithCallback(callBackList);
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.ACTION:
+
+ metaDataService.action.findAllWithCallback(callBackList);
+ break;
+
+ default :
+
+ edit.categoryList = [];
+ edit.loadingCategories = false;
+ break;
+
+ }
+
+ function callBackList(list){
+
+ edit.categoryList = list;
+ edit.loadingCategories = false;
+
+ }
+ }
+
+ function loadRelatedData(categoryId){
+
+ edit.dataList = [];
+ edit.dataToBeSelected = [];
+ edit.selectedDataList = [];
+ edit.loadingData = true;
+
+ switch(edit.assignmentsType){
+
+ case ASSIGNMENTS_CST.TYPE.SUBJECT:
+
+ dataService.subject.findAllFromCategoriesWithCallback(edit.selectedPolicy.id, categoryId, callBackList);
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.OBJECT:
+
+ dataService.object.findAllFromCategoriesWithCallback(edit.selectedPolicy.id, categoryId, callBackList);
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.ACTION:
+
+ dataService.action.findAllFromCategoriesWithCallback(edit.selectedPolicy.id, categoryId, callBackList);
+ break;
+
+ default :
+
+ edit.loadingData = false;
+ break;
+
+ }
+
+ function callBackList(list){
+
+ edit.dataList = list;
+ edit.dataToBeSelected = angular.copy(edit.dataList);
+ edit.selectedDataList = [];
+ edit.loadingData = false;
+
+ }
+
+ }
+
+ function addSelectedData(){
+
+ edit.dataToBeSelected = _.without(edit.dataToBeSelected, edit.selectedData);
+ edit.selectedDataList.push(edit.selectedData);
+ clearSelectedCategories();
+
+ }
+
+ function removeSelectedData(data){
+
+ edit.dataToBeSelected.push(data);
+ edit.selectedDataList = _.without(edit.selectedDataList, data);
+
+ }
+
+ function clearSelectedCategories(){
+
+ edit.selectedData = undefined;
+
+ }
+
+ function getName(assignment){
+
+ if(_.isUndefined(assignment)) return '(None)';
+
+ switch(edit.assignmentsType){
+
+ case ASSIGNMENTS_CST.TYPE.SUBJECT:
+
+ return assignment.name;
+
+ case ASSIGNMENTS_CST.TYPE.OBJECT:
+
+ return assignment.value.name;
+
+
+ case ASSIGNMENTS_CST.TYPE.ACTION:
+
+ return assignment.value.name;
+
+ default :
+
+ return assignment.name;
+
+ }
+
+ }
+
+ function manageSelectedDataListy(){
+
+ if (edit.selectedDataList.length >= 1 ){
+
+ edit.assignementsAttributeValid = true;
+
+ }else{
+
+ edit.assignementsAttributeValid = false;
+
+ }
+ }
+
+ function startLoading(){
+
+ edit.loading = true;
+
+ }
+
+ function stopLoading(){
+
+ edit.loading = false;
+
+ }
+ }
+
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/parameter/assignments/assignments.list.dir.js b/old/moon_gui/static/app/policy/edit/parameter/assignments/assignments.list.dir.js
new file mode 100755
index 00000000..22931e4d
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/assignments/assignments.list.dir.js
@@ -0,0 +1,393 @@
+(function () {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonAssignmentsList', moonAssignmentsList);
+
+ moonAssignmentsList.$inject = [];
+
+ function moonAssignmentsList() {
+
+ return {
+ templateUrl: 'html/policy/edit/parameter/assignments/assignments-list.tpl.html',
+ bindToController: true,
+ controller: moonAssignmentsListController,
+ controllerAs: 'list',
+ scope: {
+ policy: '=',
+ editMode: '='
+ },
+ restrict: 'E',
+ replace: true
+ };
+ }
+
+ angular
+ .module('moon')
+ .controller('moonAssignmentsListController', moonAssignmentsListController);
+
+ moonAssignmentsListController.$inject = ['$scope', '$rootScope', 'assignmentsService', '$translate', 'alertService',
+ 'policyService', 'ASSIGNMENTS_CST', 'utilService', 'metaDataService', 'perimeterService', 'dataService'];
+
+ function moonAssignmentsListController($scope, $rootScope, assignmentsService, $translate, alertService,
+ policyService, ASSIGNMENTS_CST, utilService, metaDataService, perimeterService, dataService) {
+
+ var list = this;
+
+ list.policy = $scope.list.policy;
+ list.editMode = $scope.list.editMode;
+
+ list.typeOfSubject = ASSIGNMENTS_CST.TYPE.SUBJECT;
+ list.typeOfObject = ASSIGNMENTS_CST.TYPE.OBJECT;
+ list.typeOfAction = ASSIGNMENTS_CST.TYPE.ACTION;
+
+ list.deleteSub = deleteSub;
+ list.deleteObj = deleteObj;
+ list.deleteAct = deleteAct;
+
+ list.getSubjects = getSubjects;
+ list.getObjects = getObjects;
+ list.getActions = getActions;
+
+ list.getCategoryFromAssignment = getCategoryFromAssignment;
+ list.getPerimeterFromAssignment = getPerimeterFromAssignment;
+ list.getDataFromAssignmentsIndex = getDataFromAssignmentsIndex;
+
+ activate();
+
+ function activate() {
+
+ manageSubjects();
+
+ manageObjects();
+
+ manageActions();
+
+ }
+
+ var rootListeners = {
+
+ 'event:createAssignmentsFromAssignmentsEditSuccess': $rootScope.$on('event:createAssignmentsFromAssignmentsEditSuccess', updateList)
+
+ };
+
+ _.each(rootListeners, function(unbind){
+ $scope.$on('$destroy', rootListeners[unbind]);
+ });
+
+ function manageSubjects() {
+
+ list.loadingSub = true;
+
+ assignmentsService.subject.findAllFromPolicyWithCallback(list.policy.id, function (data) {
+
+ list.subjects = data;
+ list.loadingSub = false;
+
+ });
+ }
+
+ function manageObjects() {
+
+ list.loadingObj = true;
+
+ assignmentsService.object.findAllFromPolicyWithCallback(list.policy.id, function (data) {
+
+ list.objects = data;
+ list.loadingObj = false;
+
+ });
+
+ }
+
+ function manageActions() {
+
+ list.loadingAct = true;
+
+ assignmentsService.action.findAllFromPolicyWithCallback(list.policy.id, function (data) {
+
+ list.actions = data;
+ list.loadingAct = false;
+
+ });
+
+ }
+
+ function getPerimeterFromAssignment(assignment, type) {
+
+ if (_.has(assignment, 'perimeter')) {
+ return assignment.perimeter;
+ }
+
+ // if the call has not been made
+ if (!_.has(assignment, 'callPerimeterInProgress')) {
+
+ assignment.callPerimeterInProgress = true;
+
+ switch (type) {
+
+ case ASSIGNMENTS_CST.TYPE.SUBJECT:
+ perimeterService.subject.findOneFromPolicyWithCallback(list.policy.id, assignment.subject_id, setPerimeterToAssignment);
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.OBJECT:
+ perimeterService.object.findOneFromPolicyWithCallback(list.policy.id, assignment.object_id, setPerimeterToAssignment);
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.ACTION:
+ perimeterService.action.findOneFromPolicyWithCallback(list.policy.id, assignment.action_id, setPerimeterToAssignment);
+ break;
+
+ }
+
+ }
+
+ // if the call is in progress return false
+ return false;
+
+ function setPerimeterToAssignment(perimeter) {
+
+ assignment.callPerimeterInProgress = false;
+ assignment.perimeter = perimeter;
+
+ }
+ }
+
+ function getCategoryFromAssignment(data, type) {
+
+ if (_.has(data, 'category')) {
+ return data.category;
+ }
+
+ // if the call has not been made
+ if (!_.has(data, 'callCategoryInProgress')) {
+
+ data.callCategoryInProgress = true;
+
+ switch (type) {
+
+ case ASSIGNMENTS_CST.TYPE.SUBJECT:
+ metaDataService.subject.findOne(data.subject_cat_id, setCategoryToData);
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.OBJECT:
+ metaDataService.object.findOne(data.object_cat_id, setCategoryToData);
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.ACTION:
+ metaDataService.action.findOne(data.action_cat_id, setCategoryToData);
+ break;
+
+ }
+
+ }
+
+ // if the call is in progress return false
+ return false;
+
+ function setCategoryToData(category) {
+
+ data.callCategoryInProgress = false;
+ data.category = category;
+
+ }
+ }
+
+ /**
+ * @param index
+ * @param assignment
+ * @param type
+ */
+ function getDataFromAssignmentsIndex(index, assignment, type) {
+
+ if (!_.has(assignment, 'assignments_value')) {
+ // setting an array which will contains every value of the category
+ assignment.assignments_value = Array.apply(null, new Array(assignment.assignments.length)).map(function () {
+ return {
+ data: {}
+ };
+ });
+ }
+
+ if (_.has(assignment.assignments_value[index], 'callDataInProgress') && !assignment.assignments_value[index].callDataInProgress) {
+ return assignment.assignments_value[index].data;
+ }
+
+ // if the call has not been made
+ if (!_.has(assignment.assignments_value[index], 'callDataInProgress')) {
+
+ assignment.assignments_value[index].callDataInProgress = true;
+
+ switch (type) {
+
+ case ASSIGNMENTS_CST.TYPE.SUBJECT:
+ dataService.subject.data.findOne(list.policy.id, assignment.category_id, assignment.assignments[index], setDataToAssignment);
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.OBJECT:
+ dataService.object.data.findOne(list.policy.id, assignment.category_id, assignment.assignments[index], setDataToAssignment);
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.ACTION:
+ dataService.action.data.findOne(list.policy.id, assignment.category_id, assignment.assignments[index], setDataToAssignment);
+ break;
+
+ }
+
+ }
+
+ // if the call is in progress return false
+ return false;
+
+ function setDataToAssignment(data) {
+
+ assignment.assignments_value[index].callDataInProgress = false;
+ assignment.assignments_value[index].data = data;
+
+ }
+ }
+
+ /**
+ * Delete
+ */
+
+ function deleteSub(subject, dataId) {
+
+ subject.loader = true;
+
+ assignmentsService.subject.delete(list.policy.id, subject.subject_id, subject.subject_cat_id, dataId, deleteSubSuccess, deleteSubError);
+
+ function deleteSubSuccess(data) {
+
+ $translate('moon.policy.assignments.subject.delete.success').then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ manageSubjects();
+
+ subject.loader = false;
+
+ }
+
+ function deleteSubError(reason) {
+
+ $translate('moon.policy.assignments.subject.delete.error', {
+ subjectName: subject.name,
+ reason: reason.message
+ }).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ subject.loader = false;
+
+ }
+ }
+
+ function deleteObj(object, dataId) {
+
+ object.loader = true;
+
+ assignmentsService.object.delete(list.policy.id, object.object_id, object.object_cat_id, dataId, deleteObjSuccess, deleteObjError);
+
+ function deleteObjSuccess(data) {
+
+ $translate('moon.policy.assignments.object.delete.success').then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ manageObjects();
+
+ object.loader = false;
+
+ }
+
+ function deleteObjError(reason) {
+
+ $translate('moon.policy.assignments.object.delete.error', {
+ objectName: object.name,
+ reason: reason.message
+ }).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ object.loader = false;
+ }
+ }
+
+ function deleteAct(action, dataId) {
+
+ action.loader = true;
+
+ assignmentsService.action.delete(list.policy.id, action.action_id, action.action_cat_id, dataId, deleteActSuccess, deleteActError);
+
+ function deleteActSuccess(data) {
+
+ $translate('moon.policy.assignments.action.delete.success').then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ manageActions();
+
+ action.loader = false;
+
+ }
+
+ function deleteActError(reason) {
+
+ $translate('moon.policy.assignments.action.delete.error', {
+ actionName: action.name,
+ reason: reason.message
+ }).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ action.loader = false;
+
+ }
+ }
+
+ function getSubjects() {
+ return list.subjects ? list.subjects : [];
+ }
+
+ function getObjects() {
+ return list.objects ? list.objects : [];
+ }
+
+ function getActions() {
+ return list.actions ? list.actions : [];
+ }
+
+ function updateList(event, type) {
+
+ switch(type){
+
+ case ASSIGNMENTS_CST.TYPE.SUBJECT:
+
+ manageSubjects();
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.OBJECT:
+
+ manageObjects();
+ break;
+
+ case ASSIGNMENTS_CST.TYPE.ACTION:
+
+ manageActions();
+ break;
+
+ default :
+
+ activate();
+ break;
+
+ }
+
+ }
+
+ }
+
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/parameter/data/data-edit.tpl.html b/old/moon_gui/static/app/policy/edit/parameter/data/data-edit.tpl.html
new file mode 100755
index 00000000..fae647e3
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/data/data-edit.tpl.html
@@ -0,0 +1,83 @@
+<div>
+
+ <div class="col-md-12 col-sm-12 col-xs-12">
+
+ <form ng-if="!edit.fromList" class="form-horizontal" role="form" name="edit.form">
+
+ <div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}">
+
+ <label for="name" class="col-sm-3 control-label"
+ data-translate="moon.policy.data.edit.name">Name</label>
+
+ <div class="col-sm-6">
+
+ <input name="name" id="name" class="form-control" type="text" data-ng-model="edit.data.name"
+ required/>
+
+ <div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid">
+ <small class="error" ng-show="edit.form.name.$error.required"
+ data-translate="moon.policy.data.edit.check.name.required">Name is required
+ </small>
+ </div>
+
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <label for="description" class="col-sm-3 control-label"
+ data-translate="moon.policy.data.edit.description">Description</label>
+ <div class="col-sm-6">
+ <textarea id="description" name="description" class="form-control"
+ data-ng-model="edit.data.description"></textarea>
+ </div>
+
+ </div>
+
+ <div class="form-group"
+ ng-class="{'has-error': edit.form.categoryList.$invalid && edit.form.categoryList.$dirty}">
+
+ <label for="categoryList" class="col-sm-3 control-label"
+ data-translate="moon.policy.data.edit.categories">Category List </label>
+
+ <div class="col-sm-6">
+
+ <ui-select ng-model="edit.selectedCategory" name="categoryList" id="categoryList" required>
+
+ <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match>
+ <ui-select-choices repeat="aCategory in edit.categoriesToBeSelected">
+ <div ng-value="aCategory" ng-bind="aCategory.name"></div>
+ </ui-select-choices>
+
+ </ui-select>
+
+ <div class="help-block" ng-show="edit.form.categoryList.$dirty && edit.form.categoryList.$invalid">
+ <small class="error" ng-show="edit.form.categoryList.$error.required"
+ data-translate="moon.policy.data.edit.check.category.required">Category is required
+ </small>
+ </div>
+
+ </div>
+ </div>
+
+ <div class="form-group">
+
+ <div class="pull-right">
+
+ <a href="" ng-disabled="edit.loading" ng-click="edit.create()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-save"></span>
+ <span data-translate="moon.policy.data.edit.action.create">Create</span>
+ </a>
+
+ <moon-loader ng-if="edit.loading"></moon-loader>
+
+ </div>
+
+ </div>
+
+ </form>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/parameter/data/data-list.tpl.html b/old/moon_gui/static/app/policy/edit/parameter/data/data-list.tpl.html
new file mode 100755
index 00000000..b69a4eed
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/data/data-list.tpl.html
@@ -0,0 +1,390 @@
+<div>
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.data.subject.title">List of associated Subjects</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive">
+
+ <table class="table table-striped">
+
+ <thead>
+ <tr>
+ <th data-translate="moon.policy.data.table.name">Name</th>
+ <th data-translate="moon.policy.data.table.description">Description</th>
+ <th data-translate="moon.policy.data.table.category.name">Category</th>
+ <th data-translate="moon.policy.data.table.action.title"></th>
+ </tr>
+ </thead>
+
+ <moon-loader ng-if="list.loadingSub"></moon-loader>
+
+ <tbody ng-if="!list.loadingSub && list.getSubjects().length > 0">
+ <tr ng-repeat="(key, value) in list.subjects">
+ <td ng-bind="value.name"></td>
+ <td ng-bind="value.description"></td>
+ <td>
+
+ <div ng-if="!list.getCategoryFromData(value, list.typeOfSubject)">
+ <moon-loader ng-if="!list.getCategoryFromData(value)" ></moon-loader>
+ <em data-translate="moon.policy.list.table.loading.category">Loading </em>
+ </div>
+
+ <div ng-if="list.getCategoryFromData(value)">
+ <span ng-bind="value.category.name"></span>
+ </div>
+
+ </td>
+
+ <td>
+
+ <a href="" ng-if="!value.loader" ng-click="list.deleteSub(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.policy.data.table.action.delete">Delete</span>
+ </a>
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>
+
+
+ <!--<td>
+
+ <div class="dropdown">
+
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.policy.data.table.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+
+ <ul class="dropdown-menu">
+
+ <li>
+ <a href="" ng-click="list.unMapSub(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metarules.action.unmap">Unmap</span>
+ </a>
+ </li>
+
+ <li class="divider"></li>
+
+ <li>
+ <a href="" ng-click="list.deleteSub(value)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.policy.data.table.action.delete">Delete</span>
+ </a>
+ </li>
+
+ </ul>
+
+ </div>
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>-->
+
+ </tr>
+ </tbody>
+
+
+ <tbody ng-if="!list.loadingSub && list.getSubjects().length === 0">
+ <tr>
+ <td colspan="4" data-translate="moon.policy.data.subject.notFound">There is no Subjects</td>
+ </tr>
+ </tbody>
+
+ </table>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div ng-if="list.editMode" class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.data.subject.add.title">Add a Subject Category</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <moon-data-edit policy="list.policy" mn-data-type="list.typeOfSubject"></moon-data-edit>
+
+ </div>
+
+ </div>
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.data.object.title">List associated of Objects</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive">
+
+ <table class="table table-striped">
+
+ <thead>
+ <tr>
+ <th data-translate="moon.policy.data.table.name">Name</th>
+ <th data-translate="moon.policy.data.table.description">Description</th>
+ <th data-translate="moon.policy.data.table.category.name">Category</th>
+ <th data-translate="moon.policy.data.table.action.title">Actions</th>
+ </tr>
+ </thead>
+
+ <moon-loader ng-if="list.loadingObj"></moon-loader>
+
+ <tbody ng-if="!list.loadingObj && list.getObjects().length > 0">
+ <tr ng-repeat="(key, value) in list.objects">
+ <td ng-bind="value.value.name"></td>
+ <td ng-bind="value.value.description"></td>
+ <td>
+
+ <div ng-if="!list.getCategoryFromData(value, list.typeOfObject)">
+ <moon-loader ng-if="!list.getCategoryFromData(value)" ></moon-loader>
+ <em data-translate="moon.policy.list.table.loading.category">Loading </em>
+ </div>
+
+ <div ng-if="list.getCategoryFromData(value)">
+ <span ng-bind="value.category.name"></span>
+ </div>
+
+ </td>
+
+ <td>
+
+ <a href="" ng-if="!value.loader" ng-click="list.deleteObj(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.policy.data.table.action.delete">Delete</span>
+ </a>
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>
+ <!--<td>
+
+ <div class="dropdown">
+
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.policy.data.table.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+
+ <ul class="dropdown-menu">
+
+ <li>
+ <a href="" ng-click="list.unMapObj(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metarules.action.unmap">Unmap</span>
+ </a>
+ </li>
+
+ <li class="divider"></li>
+
+ <li>
+ <a href="" ng-click="list.deleteObj(value)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.policy.data.table.action.delete">Delete</span>
+ </a>
+ </li>
+
+ </ul>
+
+ </div>
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>
+ </tr>-->
+ </tbody>
+
+ <tbody ng-if="!list.loadingObj && list.getObjects().length === 0">
+ <tr>
+
+ <td colspan="4" data-translate="moon.policy.data.object.notFound">There is no Objects</td>
+
+ </tr>
+ </tbody>
+
+ </table>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div ng-if="list.editMode" class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.data.object.add.title">Add an Object Category</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <moon-data-edit policy="list.policy" mn-data-type="list.typeOfObject"></moon-data-edit>
+
+ </div>
+
+ </div>
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.data.action.title">List associated of Actions</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive">
+
+ <table class="table table-striped">
+
+ <thead>
+ <tr>
+ <th data-translate="moon.policy.data.table.name">Name</th>
+ <th data-translate="moon.policy.data.table.description">Description</th>
+ <th data-translate="moon.policy.data.table.category.name">Category</th>
+ <th data-translate="moon.policy.data.table.action.title">Actions</th>
+ </tr>
+ </thead>
+
+ <moon-loader ng-if="list.loadingAct"></moon-loader>
+
+ <tbody ng-if="!list.loadingAct && list.getActions().length > 0">
+ <tr ng-repeat="(key, value) in list.actions">
+ <td ng-bind="value.value.name"></td>
+ <td ng-bind="value.value.description"></td>
+ <td>
+
+ <div ng-if="!list.getCategoryFromData(value, list.typeOfAction)">
+ <moon-loader ng-if="!list.getCategoryFromData(value)" ></moon-loader>
+ <em data-translate="moon.policy.list.table.loading.category">Loading </em>
+ </div>
+
+ <div ng-if="list.getCategoryFromData(value)">
+ <span ng-bind="value.category.name"></span>
+ </div>
+
+ </td>
+
+ <td>
+
+ <a href="" ng-if="!value.loader" ng-click="list.deleteSub(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.policy.data.table.action.delete">Delete</span>
+ </a>
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>
+ <!--<td>
+
+ <div class="dropdown">
+
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.policy.data.table.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+
+ <ul class="dropdown-menu">
+
+ <li>
+ <a href="" ng-click="list.unMapAct(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.model.metarules.action.unmap">Unmap</span>
+ </a>
+ </li>
+
+ <li class="divider"></li>
+
+ <li>
+ <a href="" ng-click="list.deleteAct(value)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.policy.data.table.action.delete">Delete</span>
+ </a>
+ </li>
+
+ </ul>
+
+ </div>
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>-->
+ </tr>
+ </tbody>
+
+ <tbody ng-if="!list.loadingAct && list.getActions().length === 0">
+ <tr>
+ <td colspan="4" data-translate="moon.policy.data.action.notFound">There is no Actions</td>
+ </tr>
+ </tbody>
+
+ </table>
+
+ </div>
+
+
+ </div>
+
+ </div>
+
+ <div ng-if="list.editMode" class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.data.action.add.title">Add an Action Category</h4>
+
+ </div>
+
+ <div class="panel-body">.
+
+ <moon-data-edit policy="list.policy" mn-data-type="list.typeOfAction"></moon-data-edit>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/parameter/data/data.edit.dir.js b/old/moon_gui/static/app/policy/edit/parameter/data/data.edit.dir.js
new file mode 100755
index 00000000..2ae08177
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/data/data.edit.dir.js
@@ -0,0 +1,258 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonDataEdit', moonDataEdit);
+
+ moonDataEdit.$inject = [];
+
+ function moonDataEdit() {
+
+ return {
+ templateUrl : 'html/policy/edit/parameter/data/data-edit.tpl.html',
+ bindToController : true,
+ controller : moonDataEditController,
+ controllerAs : 'edit',
+ scope : {
+ //Type can be 'ACTION', 'OBJECT', 'SUBJECT'
+ mnDataType: '=',
+ policy : '='
+ },
+ restrict : 'E',
+ replace : true
+ };
+
+ }
+
+ angular
+ .module('moon')
+ .controller('moonDataEditController', moonDataEditController);
+
+ moonDataEditController.$inject = ['$scope', 'dataService', 'DATA_CST', 'alertService', '$translate',
+ 'formService', 'policyService', 'utilService', 'metaDataService', 'modelService', 'metaRuleService'];
+
+ function moonDataEditController($scope, dataService, DATA_CST, alertService, $translate,
+ formService, policyService, utilService, metaDataService, modelService, metaRuleService) {
+
+ var edit = this;
+
+ edit.dataType = $scope.edit.mnDataType;
+ edit.policy = $scope.edit.policy;
+
+ edit.fromList = false;
+
+ edit.loading = false;
+
+ edit.form = {};
+
+ edit.data = { name: null, description: null};
+
+ edit.list = [];
+ edit.categoriesToBeSelected = [];
+
+ edit.create = createData;
+
+ activate();
+
+ /*
+ *
+ */
+
+ function activate(){
+
+ loadAllCategories();
+
+ switch(edit.dataType){
+
+ case DATA_CST.TYPE.SUBJECT:
+
+ dataService.subject.findAllFromPolicyWithCallback(edit.policy.id, callBackList);
+ break;
+
+ case DATA_CST.TYPE.OBJECT:
+
+ dataService.object.findAllFromPolicyWithCallback(edit.policy.id, callBackList);
+ break;
+
+ case DATA_CST.TYPE.ACTION:
+
+ dataService.action.findAllFromPolicyWithCallback(edit.policy.id, callBackList);
+ break;
+
+ default :
+
+ edit.list = [];
+ break;
+
+ }
+
+ function callBackList(list){
+
+ // For each Data, there is a check about the mapping between the Data and the policy
+ _.each(list, function (element) {
+ if (element.policy_id !== edit.policy.id) {
+
+ edit.list.push(element);
+
+ }
+ });
+
+ }
+
+ }
+
+
+ function loadAllCategories(){
+
+ modelService.findOneWithCallback(edit.policy.model_id, function(model){
+
+ metaRuleService.findSomeWithCallback(model.meta_rules, function(metaRules){
+
+ switch(edit.dataType){
+
+ case DATA_CST.TYPE.SUBJECT:
+ var subjectCategoryList = _.reduce(metaRules, function(result, metaRule) {
+ return result.concat(metaRule.subject_categories);
+ }, [])
+ metaDataService.subject.findSomeWithCallback(subjectCategoryList, callBackList);
+ break;
+
+ case DATA_CST.TYPE.OBJECT:
+ var objectCategoryList = _.reduce(metaRules, function(result, metaRule) {
+ return result.concat(metaRule.object_categories);
+ }, [])
+ metaDataService.object.findSomeWithCallback(objectCategoryList, callBackList);
+ break;
+
+ case DATA_CST.TYPE.ACTION:
+ var actionCategoryList = _.reduce(metaRules, function(result, metaRule) {
+ return result.concat(metaRule.action_categories);
+ }, [])
+ metaDataService.action.findSomeWithCallback(actionCategoryList, callBackList);
+ break;
+
+ default :
+
+ edit.categoriesToBeSelected = [];
+ break;
+
+ }
+
+ function callBackList(list){
+
+ edit.categoriesToBeSelected = list;
+
+ }
+ });
+
+ });
+
+
+ }
+
+ /**
+ * Create
+ */
+
+ function createData() {
+
+ if(formService.isInvalid(edit.form)) {
+
+ formService.checkFieldsValidity(edit.form);
+
+ } else {
+
+ startLoading();
+
+ var dataToSend = angular.copy(edit.data);
+
+ switch(edit.dataType){
+
+ case DATA_CST.TYPE.SUBJECT:
+
+ dataService.subject.add(dataToSend, edit.policy.id, edit.selectedCategory.id, createSuccess, createError);
+ break;
+
+ case DATA_CST.TYPE.OBJECT:
+
+ dataService.object.add(dataToSend, edit.policy.id, edit.selectedCategory.id, createSuccess, createError);
+ break;
+
+ case DATA_CST.TYPE.ACTION:
+
+ dataService.action.add(dataToSend, edit.policy.id, edit.selectedCategory.id, createSuccess, createError);
+ break;
+ }
+
+ }
+
+ /**
+ * @param data
+ */
+ function createSuccess(data) {
+
+ var created = {};
+ var name = '';
+
+ switch(edit.dataType){
+
+ case DATA_CST.TYPE.SUBJECT:
+
+ created = utilService.transformOne(data['subject_data'], 'data');
+ name = created.name;
+ break;
+
+ case DATA_CST.TYPE.OBJECT:
+
+ created = utilService.transformOne(data['object_data'], 'data');
+ name = created.value.name;
+ break;
+
+ case DATA_CST.TYPE.ACTION:
+
+ created = utilService.transformOne(data['action_data'], 'data');
+ name = created.value.name;
+ break;
+ }
+
+ $translate('moon.policy.data.edit.create.success', { name: name }).then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ $scope.$emit('event:createDataFromDataEditSuccess', created, edit.dataType);
+
+ stopLoading();
+
+ edit.list.push(created);
+
+ }
+
+ function createError(reason) {
+
+ $translate('moon.policy.data.edit.create.error', { name: dataToSend.name }).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ stopLoading();
+
+ }
+
+ }
+
+ function startLoading(){
+
+ edit.loading = true;
+
+ }
+
+ function stopLoading(){
+
+ edit.loading = false;
+
+ }
+
+ }
+
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/parameter/data/data.list.dir.js b/old/moon_gui/static/app/policy/edit/parameter/data/data.list.dir.js
new file mode 100755
index 00000000..23a7e535
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/data/data.list.dir.js
@@ -0,0 +1,293 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonDataList', moonDataList);
+
+ moonDataList.$inject = [];
+
+ function moonDataList() {
+
+ return {
+ templateUrl : 'html/policy/edit/parameter/data/data-list.tpl.html',
+ bindToController : true,
+ controller : moonDataListController,
+ controllerAs : 'list',
+ scope : {
+ policy: '=',
+ editMode : '='
+ },
+ restrict : 'E',
+ replace : true
+ };
+ }
+
+ angular
+ .module('moon')
+ .controller('moonDataListController', moonDataListController);
+
+ moonDataListController.$inject = ['$scope', '$rootScope', 'dataService', '$translate', 'alertService', 'DATA_CST', 'metaDataService'];
+
+ function moonDataListController($scope, $rootScope, dataService, $translate, alertService, DATA_CST, metaDataService){
+
+ var list = this;
+
+ list.policy = $scope.list.policy;
+ list.editMode = $scope.list.editMode;
+
+ list.typeOfSubject = DATA_CST.TYPE.SUBJECT;
+ list.typeOfObject = DATA_CST.TYPE.OBJECT;
+ list.typeOfAction = DATA_CST.TYPE.ACTION;
+
+ list.deleteSub = deleteSub;
+ list.deleteObj = deleteObj;
+ list.deleteAct = deleteAct;
+
+ list.getSubjects = getSubjects;
+ list.getObjects = getObjects;
+ list.getActions = getActions;
+
+ list.getCategoryFromData = getCategoryFromData;
+
+ activate();
+
+ function activate(){
+
+ manageSubjects();
+
+ manageObjects();
+
+ manageActions();
+
+ }
+
+ var rootListeners = {
+
+ 'event:createDataFromDataEditSuccess': $rootScope.$on('event:createDataFromDataEditSuccess', addDataToList)
+
+ };
+
+ _.each(rootListeners, function(unbind){
+ $scope.$on('$destroy', rootListeners[unbind]);
+ });
+
+
+ function manageSubjects(){
+
+ list.loadingSub = true;
+
+ dataService.subject.findAllFromPolicyWithCallback(list.policy.id, function(data){
+
+ list.subjects = data;
+ list.loadingSub = false;
+
+ });
+ }
+
+ function manageObjects(){
+
+ list.loadingObj = true;
+
+ dataService.object.findAllFromPolicyWithCallback(list.policy.id, function(data){
+
+ list.objects = data;
+ list.loadingObj = false;
+
+ });
+
+ }
+
+ function manageActions(){
+
+ list.loadingAct = true;
+
+ dataService.action.findAllFromPolicyWithCallback(list.policy.id, function(data){
+
+ list.actions = data;
+ list.loadingAct = false;
+
+ });
+
+ }
+
+ function getCategoryFromData(data, type) {
+
+ if(_.has(data, 'category')){
+ return data.category;
+ }
+
+ // if the call has not been made
+ if(!_.has(data, 'callCategoryInProgress')){
+
+ data.callCategoryInProgress = true;
+
+ switch(type){
+
+ case DATA_CST.TYPE.SUBJECT:
+ metaDataService.subject.findOne(data.category_id, setCategoryToData);
+ break;
+
+ case DATA_CST.TYPE.OBJECT:
+ metaDataService.object.findOne(data.category_id, setCategoryToData);
+ break;
+
+ case DATA_CST.TYPE.ACTION:
+ metaDataService.action.findOne(data.category_id, setCategoryToData);
+ break;
+
+ }
+
+ }
+
+ // if the call is in progress return false
+ return false;
+
+ function setCategoryToData(category){
+
+ data.callCategoryInProgress = false;
+ data.category = category;
+
+ }
+ }
+
+ /**
+ * Delete
+ */
+
+ function deleteSub(subject){
+
+ subject.loader = true;
+
+ dataService.subject.delete(subject, list.policy.id, subject.category_id, deleteSubSuccess, deleteSubError);
+
+ function deleteSubSuccess(data){
+
+ $translate('moon.policy.data.subject.delete.success', { subjectName: subject.name }).then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ removeSubFromSubList(subject);
+
+ subject.loader = false;
+
+ }
+
+ function deleteSubError(reason){
+
+ $translate('moon.policy.data.subject.delete.error', { subjectName: subject.name, reason: reason.message}).then( function(translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ subject.loader = false;
+
+ }
+ }
+
+ function deleteObj(object){
+
+ object.loader = true;
+
+ dataService.object.delete(object, list.policy.id, object.category_id, deleteObjSuccess, deleteObjError);
+
+ function deleteObjSuccess(data){
+
+ $translate('moon.policy.data.object.delete.success', { objectName: object.name }).then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ removeObjFromObjList(object);
+
+ object.loader = false;
+
+ }
+
+ function deleteObjError(reason){
+
+ $translate('moon.policy.data.object.delete.error', { objectName: object.name, reason: reason.message}).then( function(translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ object.loader = false;
+ }
+ }
+
+ function deleteAct(action){
+
+ action.loader = true;
+
+ dataService.action.delete(action, list.policy.id, action.category_id, deleteActSuccess, deleteActError);
+
+ function deleteActSuccess(data){
+
+ $translate('moon.policy.data.action.delete.success', { actionName: action.name }).then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ removeActFromActList(action);
+
+ action.loader = false;
+
+ }
+
+ function deleteActError(reason){
+
+ $translate('moon.policy.data.action.delete.error', { actionName: action.name, reason: reason.message}).then( function(translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ action.loader = false;
+
+ }
+ }
+
+ function getSubjects(){
+ return list.subjects ? list.subjects : [];
+ }
+
+ function getObjects(){
+ return list.objects ? list.objects : [];
+ }
+
+ function getActions(){
+ return list.actions ? list.actions : [];
+ }
+
+ function removeSubFromSubList(subject){
+ list.subjects = _.without(list.subjects, subject);
+ }
+
+ function removeObjFromObjList(object){
+ list.objects = _.without(list.objects, object);
+ }
+
+ function removeActFromActList(action){
+ list.actions = _.without(list.actions, action);
+ }
+
+ function addDataToList( event, data, typeOfData){
+
+ switch(typeOfData){
+
+ case DATA_CST.TYPE.SUBJECT:
+
+ list.subjects.push(data);
+ break;
+
+ case DATA_CST.TYPE.OBJECT:
+
+ list.objects.push(data);
+ break;
+
+ case DATA_CST.TYPE.ACTION:
+
+ list.actions.push(data);
+ break;
+ }
+
+ }
+
+ }
+
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-edit.tpl.html b/old/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-edit.tpl.html
new file mode 100755
index 00000000..fa2f93c0
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-edit.tpl.html
@@ -0,0 +1,166 @@
+<div>
+
+ <div class="col-md-4 col-sm-4 col-xs-4">
+ <a class="btn btn-primary" type="button" style="white-space: normal;" ng-click="edit.fromList = !edit.fromList">
+ <span ng-if="!edit.fromList" data-translate="moon.policy.perimeter.edit.action.list">Add from the list</span>
+ <span ng-if="edit.fromList" data-translate="moon.policy.perimeter.edit.action.new">Add a new Perimeter</span>
+ </a>
+ </div>
+
+ <div class="col-md-8 col-sm-8 col-xs-8">
+
+ <form name="selectMetaData" ng-if="edit.fromList" class="form-horizontal" role="form" >
+
+ <div class="form-group" >
+
+ <ui-select ng-model="edit.selectedPerimeter" name="object">
+
+ <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match>
+ <ui-select-choices repeat="aPerimeter in edit.list">
+ <div ng-value="aPerimeter" ng-bind="aPerimeter.name"></div>
+ </ui-select-choices>
+
+ </ui-select>
+
+ </div>
+
+ <div class="form-group">
+
+ <div class="pull-left col-md-4 col-sm-4 col-xs-4">
+
+ <a href="" ng-disabled="edit.loading || !edit.selectedPerimeter" ng-click="edit.deletePerimeter()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span data-translate="moon.policy.perimeter.edit.action.delete">Delete</span>
+ </a>
+
+ </div>
+
+ <div class="pull-right col-md-7 col-md-offset-1 col-sm-7 col-sm-offset-1 col-xs-7 col-xs-offset-1 ">
+
+ <a href="" ng-disabled="edit.loading || !edit.selectedPerimeter" ng-click="edit.addToPolicy()" class="btn btn-warning" style="white-space: normal;">
+ <span class="glyphicon glyphicon-link"></span>
+ <span data-translate="moon.policy.perimeter.edit.action.add">Add the selected Perimeter</span>
+ </a>
+
+ </div>
+
+ </div>
+
+ <moon-loader ng-if="edit.loading"></moon-loader>
+
+ </form>
+
+ <form ng-if="!edit.fromList" class="form-horizontal" role="form" name="edit.form">
+
+ <div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}">
+
+ <label for="name" class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.name">Name</label>
+
+ <div class="col-sm-6">
+
+ <input name="name" id="name" class="form-control" type="text" data-ng-model="edit.perimeter.name" required />
+
+ <div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid">
+ <small class="error" ng-show="edit.form.name.$error.required" data-translate="moon.policy.perimeter.edit.check.name.required">Name is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <label for="description" class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.description">Description</label>
+ <div class="col-sm-6">
+ <textarea id="description" name="description" class="form-control" data-ng-model="edit.perimeter.description"></textarea>
+ </div>
+
+ </div>
+
+ <!--
+ <div class="form-group">
+
+ <label for="partnerId" class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.partnerId">Partner Id</label>
+
+ <div class="col-sm-6">
+ <input name="partnerId" id="partnerId" class="form-control" type="text" data-ng-model="edit.perimeter.partnerId" />
+ </div>
+
+ </div>
+ -->
+
+
+ <div class="form-group" ng-if="edit.perimeterType === edit.subjectType" ng-class="{'has-error': edit.form.email.$invalid && edit.form.email.$dirty}">
+
+ <label for="email" class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.email">Email</label>
+
+ <div class="col-sm-6">
+ <input name="email" id="email" class="form-control" type="email" data-ng-model="edit.perimeter.email" />
+ </div>
+
+ </div>
+
+
+ <div class="form-group" >
+
+ <label for="policyList" class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.policies">Policy List </label>
+
+ <div class="col-sm-5">
+
+ <ui-select ng-model="edit.selectedPolicy" id="policyList">
+
+ <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match>
+ <ui-select-choices repeat="aPolicy in edit.policiesToBeSelected">
+ <div ng-value="aPolicy" ng-bind="aPolicy.name"></div>
+ </ui-select-choices>
+
+ </ui-select>
+
+ </div>
+
+ <div class="col-sm-1 text-center">
+ <a href="" ng-click="edit.addPolicyToPerimeter()"><span style="font-size:1.5em; line-height: 1.5em;" class="glyphicon glyphicon-plus-sign"></span></a>
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <label class="col-sm-3 control-label" data-translate="moon.policy.perimeter.edit.selectedPolicies">Selected Policies</label>
+
+ <div class="col-sm-6">
+
+ <ul>
+
+ <li ng-repeat="(key, value) in edit.selectedPolicyList">
+
+ <span ng-bind="value.name" ></span> <a href="" ng-click="edit.removeSelectedPolicy(value)"><span style="font-size:1.5em; line-height: 1.5em" class="glyphicon glyphicon-remove"></span></a>
+
+ </li>
+
+ </ul>
+
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <div class="pull-right">
+
+ <a href="" ng-disabled="edit.loading" ng-click="edit.create()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-save"></span>
+ <span data-translate="moon.policy.perimeter.edit.action.create">Create</span>
+ </a>
+
+ <moon-loader ng-if="edit.loading"></moon-loader>
+
+ </div>
+
+ </div>
+
+ </form>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-list.tpl.html b/old/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-list.tpl.html
new file mode 100755
index 00000000..a94d663e
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-list.tpl.html
@@ -0,0 +1,240 @@
+<div>
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.perimeter.subject.title">List of associated Subjects</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive">
+
+ <table class="table table-striped">
+
+ <thead>
+ <tr>
+ <th data-translate="moon.policy.perimeter.table.name">Name</th>
+ <th data-translate="moon.policy.perimeter.table.description">Description</th>
+ <th data-translate="moon.policy.perimeter.table.email">Email</th>
+ <th data-translate="moon.policy.perimeter.table.action.title"></th>
+ </tr>
+ </thead>
+
+ <moon-loader ng-if="list.loadingSub"></moon-loader>
+
+ <tbody ng-if="!list.loadingSub && list.getSubjects().length > 0">
+ <tr ng-repeat="(key, value) in list.subjects">
+ <td ng-bind="value.name"></td>
+ <td ng-bind="value.description"></td>
+ <td ng-bind="value.email"></td>
+ <td>
+
+ <a href="" ng-if="!value.loader" ng-click="list.unMapSub(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.policy.perimeter.table.action.unmap">Unmap</span>
+ </a>
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>
+
+ </tr>
+ </tbody>
+
+
+ <tbody ng-if="!list.loadingSub && list.getSubjects().length === 0">
+ <tr>
+ <td data-translate="moon.policy.perimeter.subject.notFound">There is no Subjects</td>
+ <td></td>
+ <td></td>
+ <td></td>
+ </tr>
+ </tbody>
+
+ </table>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div ng-if="list.editMode" class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.perimeter.subject.add.title">Add a Subject Category</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <moon-perimeter-edit policy="list.policy" perimeter-type="list.typeOfSubject"></moon-perimeter-edit>
+
+ </div>
+
+ </div>
+
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.perimeter.object.title">List associated of Objects</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive">
+
+ <table class="table table-striped">
+
+ <thead>
+ <tr>
+ <th data-translate="moon.policy.perimeter.table.name">Name</th>
+ <th data-translate="moon.policy.perimeter.table.description">Description</th>
+ <th data-translate="moon.policy.perimeter.table.action.title"></th>
+ </tr>
+ </thead>
+
+ <moon-loader ng-if="list.loadingObj"></moon-loader>
+
+ <tbody ng-if="!list.loadingObj && list.getObjects().length > 0">
+ <tr ng-repeat="(key, value) in list.objects">
+ <td ng-bind="value.name"></td>
+ <td ng-bind="value.description"></td>
+ <td>
+
+ <a href="" ng-if="!value.loader" ng-click="list.unMapObj(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.policy.perimeter.table.action.unmap">Unmap</span>
+ </a>
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>
+ </tr>
+ </tbody>
+
+ <tbody ng-if="!list.loadingObj && list.getObjects().length === 0">
+ <tr>
+ <td data-translate="moon.policy.perimeter.object.notFound">There is no Objects</td>
+ <td></td>
+ <td></td>
+ </tr>
+ </tbody>
+
+ </table>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div ng-if="list.editMode" class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.perimeter.object.add.title">Add an Object Category</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <moon-perimeter-edit policy="list.policy" perimeter-type="list.typeOfObject"></moon-perimeter-edit>
+
+ </div>
+
+ </div>
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.perimeter.action.title">List associated of Actions</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive">
+
+ <table class="table table-striped">
+
+ <thead>
+ <tr>
+ <th data-translate="moon.policy.perimeter.table.name">Name</th>
+ <th data-translate="moon.policy.perimeter.table.description">Description</th>
+ <th data-translate="moon.policy.perimeter.table.action.title"></th>
+ </tr>
+ </thead>
+
+ <moon-loader ng-if="list.loadingAct"></moon-loader>
+
+ <tbody ng-if="!list.loadingAct && list.getActions().length > 0">
+ <tr ng-repeat="(key, value) in list.actions">
+ <td ng-bind="value.name"></td>
+ <td ng-bind="value.description"></td>
+ <td>
+
+ <a href="" ng-if="!value.loader" ng-click="list.unMapAct(value)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.policy.perimeter.table.action.unmap">Unmap</span>
+ </a>
+
+ <div ng-if="value.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>
+ </tr>
+ </tbody>
+
+ <tbody ng-if="!list.loadingAct && list.getActions().length === 0">
+ <tr>
+ <td data-translate="moon.policy.perimeter.action.notFound">There is no Actions</td>
+ <td></td>
+ <td></td>
+ </tr>
+ </tbody>
+
+ </table>
+
+ </div>
+
+
+ </div>
+
+ </div>
+
+ <div ng-if="list.editMode" class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.perimeter.action.add.title">Add an Action Category</h4>
+
+ </div>
+
+ <div class="panel-body">.
+
+ <moon-perimeter-edit policy="list.policy" perimeter-type="list.typeOfAction"></moon-perimeter-edit>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.edit.dir.js b/old/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.edit.dir.js
new file mode 100755
index 00000000..d72e23b7
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.edit.dir.js
@@ -0,0 +1,437 @@
+(function () {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonPerimeterEdit', moonPerimeterEdit);
+
+ moonPerimeterEdit.$inject = [];
+
+ function moonPerimeterEdit() {
+
+ return {
+ templateUrl: 'html/policy/edit/parameter/perimeter/perimeter-edit.tpl.html',
+ bindToController: true,
+ controller: moonPerimeterEditController,
+ controllerAs: 'edit',
+ scope: {
+ //Type can be 'ACTION', 'OBJECT', 'SUBJECT'
+ perimeterType: '=',
+ policy: '='
+ },
+ restrict: 'E',
+ replace: true
+ };
+ }
+
+
+ angular
+ .module('moon')
+ .controller('moonPerimeterEditController', moonPerimeterEditController);
+
+ moonPerimeterEditController.$inject = ['$scope', '$rootScope',
+ 'perimeterService', 'PERIMETER_CST', 'alertService',
+ '$translate', 'formService', 'policyService', 'utilService'];
+
+ function moonPerimeterEditController($scope, $rootScope,
+ perimeterService, PERIMETER_CST, alertService,
+ $translate, formService, policyService, utilService) {
+
+ var edit = this;
+
+ edit.perimeterType = $scope.edit.perimeterType;
+ // This variable is used in the view in order to display or not display email field
+ edit.subjectType = PERIMETER_CST.TYPE.SUBJECT;
+ edit.policy = $scope.edit.policy;
+
+ edit.fromList = true;
+
+ edit.loading = false;
+
+ edit.form = {};
+
+ edit.perimeter = {name: null, description: null, partner_id: null, policy_list: [], email: null};
+
+ edit.list = [];
+ edit.policyList = [];
+ edit.policiesToBeSelected = [];
+ edit.selectedPolicyList = []; // List of Policies to be added to a new perimeter
+
+ edit.create = createPerimeter;
+ edit.addToPolicy = addToPolicy;
+ edit.addPolicyToPerimeter = addPolicyToPerimeter;
+ edit.clearSelectedPolicies = clearSelectedPolicies;
+ edit.removeSelectedPolicy = removeSelectedPolicy;
+ edit.deletePerimeter = deletePerimeter;
+
+ activate();
+
+ /*
+ *
+ */
+
+ function activate() {
+
+ loadAllPolicies();
+
+ switch (edit.perimeterType) {
+
+ case PERIMETER_CST.TYPE.SUBJECT:
+
+ perimeterService.subject.findAllWithCallback(callBackList);
+ break;
+
+ case PERIMETER_CST.TYPE.OBJECT:
+
+ perimeterService.object.findAllWithCallback(callBackList);
+ break;
+
+ case PERIMETER_CST.TYPE.ACTION:
+
+ perimeterService.action.findAllWithCallback(callBackList);
+ break;
+
+ default :
+
+ edit.list = [];
+ break;
+
+ }
+
+ function callBackList(list) {
+
+ // For each Perimeter, there is a check about the mapping between the perimeter and the policy
+ _.each(list, function (element) {
+
+ if (_.indexOf(element.policy_list, edit.policy.id) === -1) {
+
+ edit.list.push(element);
+
+ }
+
+ });
+
+ }
+
+ }
+
+ var rootListeners = {
+
+ 'event:unMapPerimeterFromPerimeterList': $rootScope.$on('event:unMapPerimeterFromPerimeterList', manageUnMappedPerimeter)
+
+ };
+
+ _.each(rootListeners, function(unbind){
+ $scope.$on('$destroy', rootListeners[unbind]);
+ });
+
+
+ function loadAllPolicies() {
+
+ edit.policyList = [];
+
+ policyService.findAllWithCallback( function(data) {
+
+ edit.policyList = data;
+ edit.policiesToBeSelected = angular.copy(edit.policyList);
+
+ });
+ }
+
+ function addPolicyToPerimeter() {
+
+ if (!edit.selectedPolicy || _.contains(edit.perimeter.policy_list, edit.selectedPolicy.id)) {
+ return;
+ }
+
+ edit.perimeter.policy_list.push(edit.selectedPolicy.id);
+ edit.selectedPolicyList.push(edit.selectedPolicy);
+ edit.policiesToBeSelected = _.without(edit.policiesToBeSelected, edit.selectedPolicy);
+
+ }
+
+ function clearSelectedPolicies() {
+
+ edit.perimeter.policy_list = [];
+ edit.selectedPolicyList = [];
+ edit.policiesToBeSelected = angular.copy(edit.policyList);
+
+ }
+
+ function removeSelectedPolicy(policy) {
+
+ edit.policiesToBeSelected.push(policy);
+ edit.perimeter.policy_list = _.without(edit.perimeter.policy_list, policy.id);
+ edit.selectedPolicyList = _.without(edit.selectedPolicyList, policy);
+
+ }
+
+ /**
+ * Add
+ */
+
+ function addToPolicy() {
+
+ if (!edit.selectedPerimeter) {
+
+ return;
+
+ }
+
+ startLoading();
+
+ var perimeterToSend = edit.selectedPerimeter;
+
+ perimeterToSend.policy_list.push(edit.policy.id);
+
+ switch (edit.perimeterType) {
+
+ case PERIMETER_CST.TYPE.SUBJECT:
+
+ perimeterService.subject.update(perimeterToSend, updatePerimeterSuccess, updatePerimeterError);
+ break;
+
+ case PERIMETER_CST.TYPE.OBJECT:
+
+ perimeterService.object.update(perimeterToSend, updatePerimeterSuccess, updatePerimeterError);
+ break;
+
+ case PERIMETER_CST.TYPE.ACTION:
+
+ perimeterService.action.update(perimeterToSend, updatePerimeterSuccess, updatePerimeterError);
+ break;
+ }
+
+
+ function updatePerimeterSuccess(data) {
+
+ $translate('moon.perimeter.update.success', {policyName: perimeterToSend.name}).then(function (translatedValue) {
+
+ alertService.alertSuccess(translatedValue);
+
+ });
+
+ stopLoading();
+
+ }
+
+ function updatePerimeterError(reason) {
+
+ $translate('moon.policy.update.error', {
+ policyName: perimeterToSend.name,
+ reason: reason.message
+ }).then(function (translatedValue) {
+
+ alertService.alertError(translatedValue);
+
+ });
+
+ stopLoading();
+
+ }
+
+ }
+
+ /**
+ * Create
+ */
+
+ function createPerimeter() {
+
+ if (formService.isInvalid(edit.form)) {
+
+ formService.checkFieldsValidity(edit.form);
+
+ } else {
+
+ startLoading();
+
+ var perimeterToSend = angular.copy(edit.perimeter);
+
+ switch (edit.perimeterType) {
+
+ case PERIMETER_CST.TYPE.SUBJECT:
+
+ perimeterService.subject.add(perimeterToSend, createSuccess, createError);
+ break;
+
+ case PERIMETER_CST.TYPE.OBJECT:
+
+ perimeterService.object.add(perimeterToSend, createSuccess, createError);
+ break;
+
+ case PERIMETER_CST.TYPE.ACTION:
+
+ perimeterService.action.add(perimeterToSend, createSuccess, createError);
+ break;
+ }
+
+ }
+
+ function createSuccess(data) {
+
+ var created = {};
+
+ switch (edit.perimeterType) {
+
+ case PERIMETER_CST.TYPE.SUBJECT:
+
+ created = utilService.transformOne(data, 'subjects');
+ break;
+
+ case PERIMETER_CST.TYPE.OBJECT:
+
+ created = utilService.transformOne(data, 'objects');
+ break;
+
+ case PERIMETER_CST.TYPE.ACTION:
+
+ created = utilService.transformOne(data, 'actions');
+ break;
+ }
+
+ $translate('moon.policy.perimeter.edit.create.success', {name: created.name}).then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ stopLoading();
+
+ /**
+ * If during the creating the created assignments has be mapped with the current policy, then it is not required to push the new Assignments in the list
+ */
+ if (_.indexOf(created.policy_list, edit.policy.id) === -1) {
+
+ edit.list.push(created);
+
+ }else{
+
+ $scope.$emit('event:createAssignmentsFromAssignmentsEditSuccess', created, edit.perimeterType);
+
+ }
+
+ displayList();
+
+ clearSelectedPolicies();
+
+ }
+
+ function createError(reason) {
+
+ $translate('moon.policy.perimeter.edit.create.error', {name: perimeterToSend.name}).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ stopLoading();
+
+ }
+
+ }
+
+ /**
+ * Delete
+ */
+ function deletePerimeter() {
+
+ if (!edit.selectedPerimeter) {
+
+ return;
+
+ }
+
+ startLoading();
+
+ var perimeterToDelete = angular.copy(edit.selectedPerimeter);
+
+ switch (edit.perimeterType) {
+ case PERIMETER_CST.TYPE.SUBJECT:
+
+ perimeterService.subject.delete(perimeterToDelete, deleteSuccess, deleteError);
+ break;
+
+ case PERIMETER_CST.TYPE.OBJECT:
+
+ perimeterService.object.delete(perimeterToDelete, deleteSuccess, deleteError);
+ break;
+
+ case PERIMETER_CST.TYPE.ACTION:
+
+ perimeterService.action.delete(perimeterToDelete, deleteSuccess, deleteError);
+ break;
+ }
+
+
+ function deleteSuccess(data) {
+
+ $translate('moon.policy.perimeter.edit.delete.success', {name: perimeterToDelete.name})
+ .then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ policyService.findOneReturningPromise(edit.policy.id).then(function (data) {
+
+ edit.policy = utilService.transformOne(data, 'policies');
+
+ cleanSelectedValue();
+ activate();
+ stopLoading();
+
+ $scope.$emit('event:deletePerimeterFromPerimeterAddSuccess', edit.policy);
+
+ });
+
+ }
+
+ function deleteError(reason) {
+
+ $translate('moon.policy.perimeter.edit.delete.error', {name: perimeterToDelete.name}).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ stopLoading();
+
+ }
+ }
+
+ function cleanSelectedValue() {
+ edit.list = _.without(edit.list, edit.selectedPerimeter);
+ delete edit.selectedPerimeter;
+
+ }
+
+ function startLoading() {
+
+ edit.loading = true;
+
+ }
+
+ function stopLoading() {
+
+ edit.loading = false;
+
+ }
+
+ function displayList() {
+
+ edit.fromList = true;
+
+ }
+
+ /**
+ * If A perimeter has been unMapped, maybe it has to be display into the available list of Perimeter
+ * @param perimeter
+ * @param type
+ */
+ function manageUnMappedPerimeter(event, perimeter, type){
+
+ if(type === edit.perimeterType && _.indexOf(perimeter.policy_list, edit.policy.id) === -1){
+
+ edit.list.push(perimeter);
+
+ }
+
+ }
+
+ }
+
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.list.dir.js b/old/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.list.dir.js
new file mode 100755
index 00000000..dffa7783
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.list.dir.js
@@ -0,0 +1,284 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonPerimeterList', moonPerimeterList);
+
+ moonPerimeterList.$inject = [];
+
+ function moonPerimeterList() {
+
+ return {
+ templateUrl : 'html/policy/edit/parameter/perimeter/perimeter-list.tpl.html',
+ bindToController : true,
+ controller : moonPerimeterListController,
+ controllerAs : 'list',
+ scope : {
+ policy: '=',
+ editMode : '='
+ },
+ restrict : 'E',
+ replace : true
+ };
+
+ }
+
+ angular
+ .module('moon')
+ .controller('moonPerimeterListController', moonPerimeterListController);
+
+ moonPerimeterListController.$inject = ['$scope', '$rootScope', 'perimeterService', '$translate', 'alertService', 'PERIMETER_CST'];
+
+ function moonPerimeterListController($scope, $rootScope, perimeterService, $translate, alertService, PERIMETER_CST){
+
+ var list = this;
+
+ list.policy = $scope.list.policy;
+ list.editMode = $scope.list.editMode;
+
+ list.typeOfSubject = PERIMETER_CST.TYPE.SUBJECT;
+ list.typeOfObject = PERIMETER_CST.TYPE.OBJECT;
+ list.typeOfAction = PERIMETER_CST.TYPE.ACTION;
+
+ list.unMapSub = unMapSub;
+ list.unMapObj = unMapObj;
+ list.unMapAct = unMapAct;
+
+ list.getSubjects = getSubjects;
+ list.getObjects = getObjects;
+ list.getActions = getActions;
+
+ activate();
+
+ function activate(){
+
+ manageSubjects();
+
+ manageObjects();
+
+ manageActions();
+
+ }
+
+ var rootListeners = {
+
+ 'event:deletePerimeterFromPerimeterAddSuccess': $rootScope.$on('event:deletePerimeterFromPerimeterAddSuccess', deletePolicy),
+ 'event:createAssignmentsFromAssignmentsEditSuccess': $rootScope.$on('event:createAssignmentsFromAssignmentsEditSuccess', addAssignmentsToPolicy)
+
+ };
+
+ _.each(rootListeners, function(unbind){
+ $scope.$on('$destroy', rootListeners[unbind]);
+ });
+
+
+ function manageSubjects(){
+
+ list.loadingSub = true;
+
+ perimeterService.subject.findAllFromPolicyWithCallback(list.policy.id, function(perimeters){
+
+ list.subjects = perimeters;
+ list.loadingSub = false;
+
+ });
+ }
+
+ function manageObjects(){
+
+ list.loadingObj = true;
+
+ perimeterService.object.findAllFromPolicyWithCallback(list.policy.id, function(perimeters){
+
+ list.objects = perimeters;
+ list.loadingObj = false;
+
+ });
+
+ }
+
+ function manageActions(){
+
+ list.loadingAct = true;
+
+ perimeterService.action.findAllFromPolicyWithCallback(list.policy.id, function(perimeters){
+
+ list.actions = perimeters;
+ list.loadingAct = false;
+
+ });
+
+ }
+
+ /**
+ * UnMap
+ */
+
+ function unMapSub(perimeter){
+
+ perimeter.policy_list = _.without(perimeter.policy_list, list.policy.id);
+
+ perimeter.loader = true;
+
+ var perimeterToSend = angular.copy(perimeter);
+
+ perimeterService.subject.unMapPerimeterFromPolicy(list.policy.id , perimeter.id, updatePerimeterSuccess, updatePerimeterError);
+
+ function updatePerimeterSuccess(data){
+
+ $translate('moon.policy.perimeter.update.success', { perimeterName: perimeterToSend.name }).then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ $scope.$emit('event:unMapPerimeterFromPerimeterList', perimeter, PERIMETER_CST.TYPE.SUBJECT);
+
+ activate();
+
+ perimeter.loader = false;
+ }
+
+ function updatePerimeterError(reason){
+
+ $translate('moon.policy.perimeter.update.error', { perimeterName: perimeter.name, reason: reason.message}).then( function(translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ perimeter.loader = false;
+
+ }
+
+ }
+
+ function unMapObj(perimeter){
+
+ perimeter.policy_list = _.without(perimeter.policy_list, list.policy.id);
+
+ perimeter.loader = true;
+
+ var perimeterToSend = angular.copy(perimeter);
+
+ perimeterService.object.unMapPerimeterFromPolicy(list.policy.id , perimeter.id, updatePerimeterSuccess, updatePerimeterError);
+
+ function updatePerimeterSuccess(data){
+
+ $translate('moon.policy.perimeter.update.success', { perimeterName: perimeterToSend.name }).then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ $scope.$emit('event:unMapPerimeterFromPerimeterList', perimeter, PERIMETER_CST.TYPE.OBJECT);
+
+ activate();
+
+ perimeter.loader = false;
+ }
+
+ function updatePerimeterError(reason){
+
+ $translate('moon.policy.perimeter.update.error', { perimeterName: perimeter.name, reason: reason.message}).then( function(translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ perimeter.loader = false;
+
+ }
+
+ }
+
+ function unMapAct(perimeter){
+
+ perimeter.policy_list = _.without(perimeter.policy_list, list.policy.id);
+
+ perimeter.loader = true;
+
+ var perimeterToSend = angular.copy(perimeter);
+
+ perimeterService.action.unMapPerimeterFromPolicy(list.policy.id , perimeter.id, updatePerimeterSuccess, updatePerimeterError);
+
+ function updatePerimeterSuccess(data){
+
+ $translate('moon.policy.perimeter.update.success', { perimeterName: perimeterToSend.name }).then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ $scope.$emit('event:unMapPerimeterFromPerimeterList', perimeter, PERIMETER_CST.TYPE.ACTION);
+
+ activate();
+
+ perimeter.loader = false;
+ }
+
+ function updatePerimeterError(reason){
+
+ $translate('moon.policy.perimeter.update.error', { perimeterName: perimeter.name, reason: reason.message}).then( function(translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ perimeter.loader = false;
+
+ }
+
+ }
+
+ function getSubjects(){
+ return list.subjects ? list.subjects : [];
+ }
+
+ function getObjects(){
+ return list.objects ? list.objects : [];
+ }
+
+ function getActions(){
+ return list.actions ? list.actions : [];
+ }
+
+ function removeSubFromSubList(subject){
+ list.subjects = _.without(list.subjects, subject);
+ }
+
+ function removeObjFromObjList(object){
+ list.objects = _.without(list.objects, object);
+ }
+
+ function removeActFromActList(action){
+ list.actions = _.without(list.actions, action);
+ }
+
+ function deletePolicy( event, policy){
+
+ list.policy = policy;
+
+ activate();
+
+ }
+
+ function addAssignmentsToPolicy( event, assignments, type){
+
+ switch (type) {
+
+ case PERIMETER_CST.TYPE.SUBJECT:
+
+ list.subjects.push(assignments);
+ break;
+
+ case PERIMETER_CST.TYPE.OBJECT:
+
+ list.objects.push(assignments);
+ break;
+
+ case PERIMETER_CST.TYPE.ACTION:
+
+ list.actions.push(assignments);
+ break;
+
+ default :
+ break;
+
+ }
+
+ }
+
+ }
+
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/parameter/rules/rules-edit.tpl.html b/old/moon_gui/static/app/policy/edit/parameter/rules/rules-edit.tpl.html
new file mode 100755
index 00000000..685046a5
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/rules/rules-edit.tpl.html
@@ -0,0 +1,341 @@
+<div>
+
+ <div class="col-md-12 col-sm-12 col-xs-12">
+
+ <form ng-if="!edit.fromList" class="form-horizontal" role="form" name="edit.form">
+
+ <!-- Select Policy -->
+ <div class="form-group" ng-class="{'has-error': edit.form.policyList.$invalid && edit.form.policyList.$dirty}" >
+
+ <label for="policyList" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.policies">Policy List</label>
+
+ <div class="col-sm-6" >
+
+ <ui-select ng-model="edit.selectedPolicy" name="policyList" id="policyList" required>
+
+ <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match>
+ <ui-select-choices repeat="aPolicy in edit.policyList">
+ <div ng-value="aPolicy" ng-bind="aPolicy.name"></div>
+ </ui-select-choices>
+
+ </ui-select>
+
+ <div class="help-block" ng-show="edit.form.policyList.$dirty && edit.form.policyList.$invalid">
+ <small class="error" ng-show="edit.form.policyList.$error.required" data-translate="moon.policy.rules.edit.action.add.check.policy.required">Policy is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+ <div ng-if="!edit.selectedPolicy.meta_rules_values">
+ <div class="col-sm-6 col-sm-offset-3">
+ <moon-loader></moon-loader>
+ </div>
+ </div>
+
+ <div ng-if="edit.selectedPolicy.meta_rules_values">
+
+ <!-- Select Meta Rules -->
+ <div class="form-group" ng-class="{'has-error': edit.form.metaRulesList.$invalid && edit.form.metaRulesList.$dirty}" >
+
+ <label for="metaRulesList" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.metarules">MetaRules List</label>
+
+ <div class="col-sm-6" >
+
+ <ui-select ng-model="edit.selectedMetaRules" name="metaRulesList" id="metaRulesList" required>
+
+ <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match>
+ <ui-select-choices repeat="aMetaRules in edit.selectedPolicy.meta_rules_values">
+ <div ng-value="aMetaRules" ng-bind="aMetaRules.name"></div>
+ </ui-select-choices>
+
+ </ui-select>
+
+ <div class="help-block" ng-show="edit.form.metaRulesList.$dirty && edit.form.metaRulesList.$invalid">
+ <small class="error" ng-show="edit.form.metaRulesList.$error.required" data-translate="moon.policy.rules.edit.action.add.check.metarules.required">A MetaRules is required</small>
+ </div>
+
+ </div>
+
+ <div>
+ <a href="" ng-if="edit.selectedMetaRules" ng-click="edit.showDetailselectedMetaRules = !edit.showDetailselectedMetaRules">
+
+ <span ng-if="!edit.showDetailselectedMetaRules">
+ <span data-translate="moon.policy.rules.edit.action.add.details.show">Show</span>
+ <span class="glyphicon glyphicon-eye-open"></span>
+ </span>
+
+ <span ng-if="edit.showDetailselectedMetaRules">
+ <span data-translate="moon.policy.rules.edit.action.add.details.close">Close</span>
+ <span class="glyphicon glyphicon-eye-close"></span>
+ </span>
+
+ </a>
+ </div>
+
+ </div>
+
+ <div class="form-group" ng-if="edit.showDetailselectedMetaRules && edit.selectedMetaRules">
+ <moon-meta-data-list edit-mode="edit.editMode" meta-rule="edit.selectedMetaRules" short-display="true"></moon-meta-data-list>
+ </div>
+
+ <!-- Select Data -->
+ <div class="form-group" ng-if="edit.selectedMetaRules">
+
+ <div class="col-md-4">
+
+ <div ng-if="edit.selectedMetaRules.subject_categories.length > 0">
+
+ <div class="row">
+
+ <div ng-if="!edit.data.loadingSubjects">
+
+ <label for="subjectsList" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.categories.subject" data-translate-values="{ number: edit.selectedMetaRules.subject_categories.length }">Select Subject(s)</label>
+
+ <div class="col-sm-7" >
+
+ <ui-select ng-model="edit.selectedSubject" name="subjectsList" id="subjectsList" required>
+
+ <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match>
+ <ui-select-choices repeat="aSubject in edit.data.subjectsToBeSelected">
+ <div ng-value="aSubject" ng-bind="aSubject.name"></div>
+ </ui-select-choices>
+
+ </ui-select>
+
+ <div class="help-block" ng-show="edit.form.subjectsList.$dirty && edit.form.subjectsList.$invalid || !edit.numberOfSelectedSubjectValid">
+ <small class="error" ng-show="edit.form.subjectsList.$error.required || !edit.numberOfSelectedSubjectValid" data-translate="moon.policy.rules.edit.action.add.check.subject.required" data-translate-values="{ number: edit.selectedMetaRules.subject_categories.length }">Some subject are required</small>
+ </div>
+
+ </div>
+
+ <div class="col-sm-2 text-center">
+ <a href="" ng-if="edit.selectedSubject && !edit.isNumberSelectedDataAtMaximum(edit.data.subjectCST)"
+ ng-click="edit.addDataToRules(edit.data.subjectCST)"><span style="font-size:1.5em; line-height: 1.5em;" class="glyphicon glyphicon-plus-sign"></span></a>
+ </div>
+
+ </div>
+
+ <div ng-if="edit.data.loadingSubjects">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </div>
+
+ <div class="row" ng-if="!edit.data.loadingSubjects">
+
+ <div class="form-group">
+
+ <label class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.selectedSubjects">Selected Subjcet(s)</label>
+
+ <div class="col-sm-6">
+
+ <ul>
+
+ <li ng-repeat="(key, value) in edit.data.selectedSubjectsList">
+
+ <span ng-bind="value.name" ></span> <a href="" ng-click="edit.removeSelectedDataFromRules(value, edit.data.subjectCST)"><span style="font-size:1.5em; line-height: 1.5em" class="glyphicon glyphicon-remove"></span></a>
+
+ </li>
+
+ </ul>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div ng-if="edit.selectedMetaRules.subject_categories.length === 0">
+
+ </div>
+
+ </div>
+
+ <div class="col-md-4">
+
+ <div ng-if="edit.selectedMetaRules.object_categories.length > 0">
+
+ <div class="row">
+
+ <div ng-if="!edit.data.loadingObjects">
+
+ <label for="objectsList" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.categories.object" data-translate-values="{ number: edit.selectedMetaRules.object_categories.length }">Select Object(s)</label>
+
+ <div class="col-sm-7" >
+
+ <ui-select ng-model="edit.selectedObject" name="objectsList" id="objectsList" required>
+
+ <ui-select-match placeholder="(None)" ng-bind="$select.selected.value.name"></ui-select-match>
+ <ui-select-choices repeat="aObject in edit.data.objectsToBeSelected">
+ <div ng-value="aObject" ng-bind="aObject.value.name"></div>
+ </ui-select-choices>
+
+ </ui-select>
+
+ <div class="help-block" ng-show="edit.form.objectsList.$dirty && edit.form.objectsList.$invalid || !edit.numberOfSelectedObjecttValid">
+ <small class="error" ng-show="edit.form.objectsList.$error.required || !edit.numberOfSelectedObjecttValid" data-translate="moon.policy.rules.edit.action.add.check.object.required" data-translate-values="{ number: edit.selectedMetaRules.object_categories.length }">Some objects are required</small>
+ </div>
+
+ </div>
+
+ <div class="col-sm-2 text-center">
+ <a href="" ng-if="edit.selectedObject && !edit.isNumberSelectedDataAtMaximum(edit.data.objectCST)"
+ ng-click="edit.addDataToRules(edit.data.objectCST)"><span style="font-size:1.5em; line-height: 1.5em;" class="glyphicon glyphicon-plus-sign"></span></a>
+ </div>
+
+ </div>
+
+ <div ng-if="edit.data.loadingObjects">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </div>
+
+ <div class="row" ng-if="!edit.data.loadingObjects">
+
+ <div class="form-group">
+
+ <label class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.selectedObjects">Selected Objcet(s)</label>
+
+ <div class="col-sm-6">
+
+ <ul>
+
+ <li ng-repeat="(key, value) in edit.data.selectedObjectsList">
+
+ <span ng-bind="value.value.name" ></span> <a href="" ng-click="edit.removeSelectedDataFromRules(value, edit.data.objectCST)"><span style="font-size:1.5em; line-height: 1.5em" class="glyphicon glyphicon-remove"></span></a>
+
+ </li>
+
+ </ul>
+
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+
+ <div ng-if="edit.selectedMetaRules.object_categories.length === 0">
+
+ </div>
+
+ </div>
+
+ <div class="col-md-4">
+
+ <div ng-if="edit.selectedMetaRules.action_categories.length > 0">
+
+ <div class="row">
+
+ <div ng-if="!edit.data.loadingActions">
+
+ <label for="actionsList" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.categories.action" data-translate-values="{ number: edit.selectedMetaRules.action_categories.length }">Select Action(s)</label>
+
+ <div class="col-sm-7" >
+
+ <ui-select ng-model="edit.selectedAction" name="actionsList" id="actionsList" required>
+
+ <ui-select-match placeholder="(None)" ng-bind="$select.selected.value.name"></ui-select-match>
+ <ui-select-choices repeat="aAction in edit.data.actionsToBeSelected">
+ <div ng-value="aAction" ng-bind="aAction.value.name"></div>
+ </ui-select-choices>
+
+ </ui-select>
+
+ <div class="help-block" ng-show="edit.form.actionsList.$dirty && edit.form.actionsList.$invalid || !edit.numberOfSelectedActionsValid">
+ <small class="error" ng-show="edit.form.actionsList.$error.required || !edit.numberOfSelectedActionsValid" data-translate="moon.policy.rules.edit.action.add.check.action.required" data-translate-values="{ number: edit.selectedMetaRules.action_categories.length }">Some action are required</small>
+ </div>
+ </div>
+
+ <div class="col-sm-2 text-center">
+ <a href="" ng-if="edit.selectedAction && !edit.isNumberSelectedDataAtMaximum(edit.data.actionCST)"
+ ng-click="edit.addDataToRules(edit.data.actionCST)"><span style="font-size:1.5em; line-height: 1.5em;" class="glyphicon glyphicon-plus-sign"></span></a>
+ </div>
+
+ </div>
+
+ <div ng-if="edit.data.loadingActions">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </div>
+
+ <div class="row" ng-if="!edit.data.loadingActions">
+
+ <div class="form-group">
+
+ <label class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.selectedActions">Selected Action(s)</label>
+
+ <div class="col-sm-6">
+
+ <ul>
+
+ <li ng-repeat="(key, value) in edit.data.selectedActionsList">
+
+ <span ng-bind="value.value.name" ></span> <a href="" ng-click="edit.removeSelectedDataFromRules(value, edit.data.actionCST)"><span style="font-size:1.5em; line-height: 1.5em" class="glyphicon glyphicon-remove"></span></a>
+
+ </li>
+
+ </ul>
+
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+
+ <div ng-if="edit.selectedMetaRules.action_categories.length === 0">
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div class="form-group" ng-class="{'has-error': edit.form.instructions.$invalid && edit.form.instructions.$dirty || !edit.instructionsValid}">
+
+ <label for="instructions" class="col-sm-3 control-label" data-translate="moon.policy.rules.edit.action.add.instructions">Instruction</label>
+
+ <div class="col-sm-6">
+ <textarea id="instructions" name="instructions" class="form-control" ng-model="edit.rules.instructions" rows="6" required></textarea>
+ <div class="help-block" ng-show="edit.form.instructions.$dirty && edit.form.instructions.$invalid || !edit.instructionsValid ">
+ <small class="error" data-translate="moon.policy.rules.edit.action.add.check.instructions.required">An instructions is required</small>
+ </div>
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <div class="pull-right">
+
+ <a href="" ng-disabled="edit.loading" ng-click="edit.create()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-save"></span>
+ <span data-translate="moon.policy.rules.edit.action.create">Create</span>
+ </a>
+
+ <moon-loader ng-if="edit.loading"></moon-loader>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ </form>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/parameter/rules/rules-list.tpl.html b/old/moon_gui/static/app/policy/edit/parameter/rules/rules-list.tpl.html
new file mode 100755
index 00000000..7f556f93
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/rules/rules-list.tpl.html
@@ -0,0 +1,134 @@
+<div>
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.rules.edit.title">List of associated Subjects</h4>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div class="table-responsive" data-role="table">
+
+ <table class="table table-striped table-hover" ng-table="list.table">
+
+ <thead>
+
+ <tr>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('description', 'asc'), 'sort-desc': list.table.isSortBy('description', 'desc') }"
+ ng-click="list.table.sorting('description', list.table.isSortBy('description', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.policy.rules.list.table.metaRule">Meta Rule</div>
+ </th>
+
+ <th class="customTables sortable">
+ <div data-translate="moon.policy.rules.list.table.rule">Rule</div>
+ </th>
+
+ <th class="customTables sortable">
+ <div data-translate="moon.policy.rules.list.table.instructions">Instruction</div>
+ </th>
+
+ <th class="customTables sortable">
+ <div data-translate="moon.policy.rules.list.table.action.title">Actions</div>
+ </th>
+ </tr>
+
+ </thead>
+
+ <moon-loader ng-if="list.loadingRules"></moon-loader>
+
+ <tbody ng-if="!list.loadingRules && !list.hasRules()">
+ <tr>
+ <td colspan="4"><span data-translate="moon.policy.rules.list.table.notFound">There is no Rules</span></td>
+ </tr>
+ </tbody>
+
+ <tbody ng-if="!list.loadingRules && list.hasRules()">
+
+ <tr ng-repeat="aRule in $data | filter:list.search.find | orderBy:sort:reverse">
+ <td>
+ <span ng-if="!list.getMetaRuleFromRule(aRule)">
+ <moon-loader ng-if="!list.getMetaRuleFromRule(aRule)" ></moon-loader>
+ <em data-translate="moon.policy.rules.list.table.loading.metaRule">Loading </em>
+ </span>
+
+ <span ng-if="list.getMetaRuleFromRule(aRule)">
+ <span ng-bind="aRule.meta_rule.name"></span>
+ </span>
+ </td>
+
+ <td>
+
+ <span ng-if="!list.getMetaRuleFromRule(aRule)">
+ <moon-loader ng-if="!list.getMetaRuleFromRule(aRule)" ></moon-loader>
+ <em data-translate="moon.policy.rules.list.table.loading.metaRule">Loading </em>
+ </span>
+
+ <span ng-if="list.getMetaRuleFromRule(aRule)" ng-repeat="(key, value) in aRule.rule">
+
+ <span ng-if="!list.getCategoryFromRuleIndex(key, aRule)">
+ <moon-loader ng-if="!list.getCategoryFromRuleIndex(key, aRule)" ></moon-loader>
+ </span>
+
+ <span ng-if="list.getCategoryFromRuleIndex(key, aRule)">
+ <span ng-if="aRule.rule_value[key].category.name" ng-bind="aRule.rule_value[key].category.name"></span>
+ <span ng-if="aRule.rule_value[key].category.value.name" ng-bind="aRule.rule_value[key].category.value.name"></span>
+ <span ng-if="key < aRule.rule.length-1">,</span>
+ </span>
+
+ </span>
+
+ </td>
+
+ <td>
+ <pre ng-bind="aRule.instructions | json "></pre>
+ </td>
+
+ <td>
+
+ <a href="" ng-if="!aRule.loader" ng-click="list.deleteRules(aRule)" >
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span class="control-label" data-translate="moon.policy.rules.list.table.action.delete">Delete</span>
+ </a>
+
+ <div ng-if="aRule.loader">
+
+ <moon-loader></moon-loader>
+
+ </div>
+
+ </td>
+
+ </tr>
+
+ </tbody>
+
+ </table>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div ng-if="list.editMode" class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <h4 data-translate="moon.policy.rules.edit.action.add.title">Add a Rule</h4>
+
+ </div>
+
+ <div class="panel-body">.
+
+ <moon-rules-edit policy="list.policy"></moon-rules-edit>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/parameter/rules/rules.edit.dir.js b/old/moon_gui/static/app/policy/edit/parameter/rules/rules.edit.dir.js
new file mode 100755
index 00000000..b7bb7614
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/rules/rules.edit.dir.js
@@ -0,0 +1,537 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonRulesEdit', moonRulesEdit);
+
+ moonRulesEdit.$inject = [];
+
+ function moonRulesEdit() {
+
+ return {
+ templateUrl : 'html/policy/edit/parameter/rules/rules-edit.tpl.html',
+ bindToController : true,
+ controller : moonRulesEditController,
+ controllerAs : 'edit',
+ scope : {
+ policy : '='
+ },
+ restrict : 'E',
+ replace : true
+ };
+
+ }
+
+ angular
+ .module('moon')
+ .controller('moonRulesEditController', moonRulesEditController);
+
+ moonRulesEditController.$inject = ['$scope', 'rulesService', 'alertService', '$translate',
+ 'formService', 'policyService', 'utilService', 'metaRuleService', 'metaDataService', 'modelService', 'dataService', 'DATA_CST'];
+
+ function moonRulesEditController($scope, rulesService, alertService, $translate,
+ formService, policyService, utilService, metaRuleService, metaDataService, modelService, dataService, DATA_CST) {
+
+ var edit = this;
+
+ edit.policy = $scope.edit.policy;
+ edit.editMode = true;
+
+ edit.fromList = false;
+
+ edit.loading = false;
+
+ edit.form = {};
+ edit.showDetailselectedMetaRules = false;
+
+ edit.list = [];
+ edit.policyList = [];
+
+ edit.categories = {
+ subject : [],
+ loadingSubjects: true,
+ object : [],
+ loadingObjects: true,
+ action : [],
+ loadingActions : true
+ };
+
+ edit.data = {}; // this object is filled in declareDataObject():
+
+ edit.create = createRules;
+ edit.addDataToRules = addDataToRules;
+ edit.removeSelectedDataFromRules = removeSelectedDataFromRules;
+ edit.isNumberSelectedDataAtMaximum = isNumberSelectedDataAtMaximum;
+
+ //this variable is related to checks on Instruction field which is in JSON
+ edit.instructionsValid = true;
+ edit.numberOfSelectedSubjectValid = true;
+ edit.numberOfSelectedObjecttValid = true;
+ edit.numberOfSelectedActionsValid = true;
+
+ activate();
+
+ /*
+ *
+ */
+ function activate(){
+
+ edit.rules = {meta_rule_id: null, rule: [], policy_id: null, instructions: '[{"decision": "grant"}]', enabled: true};
+ declareDataObject();
+ loadAllPolicies();
+ clearSelectedMetaRules();
+
+ }
+
+ function loadAllPolicies() {
+
+ edit.policyList = [];
+
+ policyService.findAllWithCallback( function(data) {
+
+ _.each(data, function(element){
+
+ if(element.id === edit.policy.id){
+ edit.selectedPolicy = element;
+ }
+
+ });
+
+ edit.policyList = data;
+
+ });
+ }
+
+ $scope.$watch('edit.selectedPolicy', function(newValue){
+
+ clearSelectedMetaRules();
+
+ if(!_.isUndefined(newValue)){
+
+ loadRelatedMetaRules();
+
+ }
+
+ });
+
+ $scope.$watch('edit.selectedMetaRules', function(newValue){
+
+ clearSelectedData();
+
+ edit.categories = {
+ subject : [],
+ loadingSubjects: true,
+ object : [],
+ loadingObjects: true,
+ action : [],
+ loadingActions : true
+ };
+
+ declareDataObject();
+
+ if(!_.isUndefined(newValue)){
+
+ loadRelatedCategoriesAndData(newValue.subject_categories, newValue.object_categories, newValue.action_categories);
+
+ }
+
+ });
+
+ /**
+ * To get the related MetaRules, it is required to :
+ * - Get the model related to the policy
+ * - Get the metaRules associated to the model
+ * - Get the MetaData associated to the metaRules
+ */
+ function loadRelatedMetaRules() {
+
+ edit.selectedPolicy.meta_rules_values = undefined;
+
+ modelService.findOneWithCallback(edit.selectedPolicy.model_id, function(model){
+
+ metaRuleService.findSomeWithCallback(model.meta_rules, function(metaRules){
+
+ edit.selectedPolicy.meta_rules_values = metaRules;
+
+ });
+
+ });
+
+ }
+
+ /**
+ * Load categories from arrays of id in args
+ * @param subjectsCategories, list of subject id related to the metaRule
+ * @param objectCategories, list of object id related to the metaRule
+ * @param actionsCategories, list of action id related to the metaRule
+ */
+ function loadRelatedCategoriesAndData(subjectsCategories, objectCategories, actionsCategories){
+
+ metaDataService.subject.findSomeWithCallback(subjectsCategories, function(list){
+
+ edit.categories.subject = list;
+ edit.categories.loadingSubjects = false;
+
+ _.each(edit.categories.subject, function(aSubject){
+
+ dataService.subject.findAllFromCategoriesWithCallback(edit.selectedPolicy.id, aSubject.id, function(subjects){
+
+ edit.data.subject = subjects;
+ edit.data.loadingSubjects = false;
+ edit.data.subjectsToBeSelected = angular.copy(edit.data.subject);
+
+ });
+
+ });
+
+ });
+
+ metaDataService.object.findSomeWithCallback(objectCategories, function(list){
+
+ edit.categories.object = list;
+ edit.categories.loadingObjects = false;
+
+ _.each(edit.categories.object, function(aObject){
+
+ dataService.object.findAllFromCategoriesWithCallback(edit.selectedPolicy.id, aObject.id, function(objects){
+
+ edit.data.object = objects;
+ edit.data.loadingObjects = false;
+ edit.data.objectsToBeSelected = angular.copy(edit.data.object);
+
+ });
+
+ });
+
+ });
+
+ metaDataService.action.findSomeWithCallback(actionsCategories, function(list){
+
+ edit.categories.action = list;
+ edit.categories.loadingActions = false;
+
+ _.each(edit.categories.action, function(aAction){
+
+ dataService.action.findAllFromCategoriesWithCallback(edit.selectedPolicy.id, aAction.id, function(actions){
+
+ edit.data.action = actions;
+ edit.data.loadingActions = false;
+ edit.data.actionsToBeSelected = angular.copy(edit.data.action);
+
+ });
+
+ });
+
+ });
+
+ }
+
+ /**
+ * createRules, create Rules depending of what has been filled in the view
+ */
+ function createRules() {
+
+ edit.instructionsValid = true;
+ edit.numberOfSelectedSubjectValid = true;
+ edit.numberOfSelectedObjecttValid = true;
+ edit.numberOfSelectedActionsValid = true;
+
+ manageInstructionContent();
+ // bellow function is called here in order to display errors into the view
+ manageNumberOfSelectedData();
+
+ if(formService.isInvalid(edit.form)) {
+
+ formService.checkFieldsValidity(edit.form);
+
+ //manageNumberOfSelectedData is call again in order to check if errors have been display into the view
+ }else if(edit.instructionsValid && manageNumberOfSelectedData()){
+
+ startLoading();
+ buildRulesArray();
+
+ edit.rules.meta_rule_id = edit.selectedMetaRules.id;
+ edit.rules.policy_id = edit.selectedPolicy.id;
+
+ var rulesToSend = angular.copy(edit.rules);
+ rulesToSend.instructions = JSON.parse(edit.rules.instructions);
+
+ rulesService.add(rulesToSend, edit.policy.id, createSuccess, createError);
+ }
+
+
+ function createSuccess(data) {
+
+ var created = utilService.transformOne(data, 'rules');
+
+ $translate('moon.policy.rules.edit.action.add.create.success').then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ $scope.$emit('event:createRulesFromDataRulesSuccess', created);
+
+ activate();
+
+ stopLoading();
+
+ }
+
+ function createError(reason) {
+
+ $translate('moon.policy.rules.edit.action.add.create.error').then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ stopLoading();
+
+ }
+
+ }
+
+ /**
+ * if instructions attribute is not good then edit.instructionsValid is set to false
+ * it will allow the view to display an error
+ */
+ function manageInstructionContent(){
+
+ if (!isInstructionValid(edit.rules.instructions)){
+
+ edit.instructionsValid = false;
+
+ }else{
+
+ edit.instructionsValid = true;
+
+ }
+ }
+
+ /**
+ * return true if the user has selected the number required of Selected Data (subject, object or action)
+ * if one is missing then return false
+ * it will also set numberOfSelected(Subject/Object/Action)Valid to true or false in order to display errors form in the view
+ * @returns {boolean}
+ */
+ function manageNumberOfSelectedData(){
+
+ isNumberSelectedDataAtMaximum(DATA_CST.TYPE.SUBJECT) ?
+ edit.numberOfSelectedSubjectValid = true: edit.numberOfSelectedSubjectValid = false;
+ isNumberSelectedDataAtMaximum(DATA_CST.TYPE.OBJECT) ?
+ edit.numberOfSelectedObjecttValid = true: edit.numberOfSelectedObjecttValid = false;
+ isNumberSelectedDataAtMaximum(DATA_CST.TYPE.ACTION) ?
+ edit.numberOfSelectedActionsValid = true: edit.numberOfSelectedActionsValid = false;
+
+ return edit.numberOfSelectedSubjectValid && edit.numberOfSelectedObjecttValid && edit.numberOfSelectedActionsValid;
+ }
+
+ /**
+ * Check if the variables in param is not undefined and if it is a JSON
+ * It is used for instructions attribute of a Rules object
+ * @param str
+ * @returns {boolean|*}
+ */
+ function isInstructionValid(str){
+
+ return !_.isUndefined(str) && isJsonString(str);
+
+ }
+
+ function isJsonString(str) {
+
+ var item = null;
+
+ try {
+ item = JSON.parse(str);
+ } catch (e) {
+
+ return false;
+ }
+
+ if (typeof item === 'object' && item !== null) {
+
+ return true;
+ }
+
+ return false;
+ }
+
+ function startLoading(){
+
+ edit.loading = true;
+
+ }
+
+ function stopLoading(){
+
+ edit.loading = false;
+
+ }
+
+ /**
+ * allow to clear selected values in the form
+ */
+ function clearSelectedMetaRules(){
+
+ edit.selectedMetaRules = undefined;
+
+ clearSelectedData();
+
+ }
+
+ function clearSelectedData(){
+
+ edit.selectedSubject = undefined;
+ edit.selectedObject = undefined;
+ edit.selectedAction = undefined;
+
+ }
+
+ /**
+ * check if the number of Selected Data is equal to the number of categories associated to the metaRule
+ * @param typeCST : 'SUBJECT', 'OBJECT', 'ACTION'
+ * @returns {boolean}
+ */
+ function isNumberSelectedDataAtMaximum(typeCST){
+
+ if(!edit.selectedMetaRules){
+ return false;
+ }
+
+ switch (typeCST) {
+
+ case DATA_CST.TYPE.SUBJECT:
+
+ return edit.data.selectedSubjectsList.length === edit.selectedMetaRules.subject_categories.length;
+
+ case DATA_CST.TYPE.OBJECT:
+
+ return edit.data.selectedObjectsList.length === edit.selectedMetaRules.object_categories.length;
+
+ case DATA_CST.TYPE.ACTION:
+
+ return edit.data.selectedActionsList.length === edit.selectedMetaRules.action_categories.length;
+ }
+ }
+
+ /**
+ * Add a data to an array of selected value (SUBJECT/OBJECT/ACTION)
+ * those arrays will used in the create function in order to filled the rule attribute of a rules object
+ * it will remove the selected value from the possible value to be selected once the data is added
+ * @param typeCST
+ */
+ function addDataToRules(typeCST){
+
+ switch (typeCST) {
+ case DATA_CST.TYPE.SUBJECT:
+
+ if (!edit.selectedSubject || isNumberSelectedDataAtMaximum(typeCST)
+ || _.contains(edit.data.selectedSubjectsList, edit.selectedSubject)) {
+ return;
+ }
+
+ edit.data.selectedSubjectsList.push(edit.selectedSubject);
+ edit.data.subjectsToBeSelected = _.without(edit.data.subjectsToBeSelected, edit.selectedSubject);
+
+ break;
+ case DATA_CST.TYPE.OBJECT:
+
+ if (!edit.selectedObject || isNumberSelectedDataAtMaximum(typeCST)
+ || _.contains(edit.data.selectedObjectsList, edit.selectedObject)) {
+ return;
+ }
+
+ edit.data.selectedObjectsList.push(edit.selectedObject);
+ edit.data.objectsToBeSelected = _.without(edit.data.objectsToBeSelected, edit.selectedObject);
+
+ break;
+
+ case DATA_CST.TYPE.ACTION:
+ if (!edit.selectedAction || isNumberSelectedDataAtMaximum(typeCST)
+ || _.contains(edit.data.selectedActionsList, edit.selectedAction)) {
+ return;
+ }
+
+ edit.data.selectedActionsList.push(edit.selectedAction);
+ edit.data.actionsToBeSelected = _.without(edit.data.actionsToBeSelected, edit.selectedAction);
+
+ break;
+ }
+
+ }
+
+ /**
+ * Remove a selected value,
+ * refresh the list of possible value to be selected with the removed selected value
+ * @param data
+ * @param typeCST
+ */
+ function removeSelectedDataFromRules(data, typeCST) {
+
+ switch (typeCST) {
+
+ case DATA_CST.TYPE.SUBJECT:
+
+ edit.data.subjectsToBeSelected.push(data);
+ edit.data.selectedSubjectsList = _.without(edit.data.selectedSubjectsList, data);
+ break;
+
+ case DATA_CST.TYPE.OBJECT:
+
+ edit.data.objectsToBeSelected.push(data);
+ edit.data.selectedObjectsList = _.without(edit.data.selectedObjectsList, data);
+ break;
+
+ case DATA_CST.TYPE.ACTION:
+
+ edit.data.actionsToBeSelected.push(data);
+ edit.data.selectedActionsList = _.without(edit.data.selectedActionsList, data);
+ break;
+ }
+
+ }
+
+ /**
+ * fill edit.rules.rule array with the selected data
+ * it will first add subject list, object list and then action list
+ */
+ function buildRulesArray(){
+
+ _.each(edit.data.selectedSubjectsList, pushInRulesTab);
+ _.each(edit.data.selectedObjectsList, pushInRulesTab);
+ _.each(edit.data.selectedActionsList, pushInRulesTab);
+
+ function pushInRulesTab(elem){
+ edit.rules.rule.push(elem.id);
+ }
+ }
+
+ /**
+ * Declare the data object which contains attributes related to data,
+ * values to be selected, values selected, loader...
+ */
+ function declareDataObject(){
+
+ edit.data = {
+ subject : [], // List of subjects related to the policy
+ loadingSubjects: true, // allow to know if a call to the API is in progress
+ subjectsToBeSelected : [], // List of subjects the user can select
+ selectedSubjectsList: [], // List of subjects selected by the user from subjectsToBeSelected
+ subjectCST : DATA_CST.TYPE.SUBJECT,
+ object : [],
+ loadingObjects: true,
+ objectsToBeSelected: [],
+ selectedObjectsList: [],
+ objectCST : DATA_CST.TYPE.OBJECT,
+ action : [],
+ loadingActions : true,
+ actionsToBeSelected : [],
+ selectedActionsList: [],
+ actionCST : DATA_CST.TYPE.ACTION
+ }
+
+ }
+
+ }
+
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/parameter/rules/rules.list.dir.js b/old/moon_gui/static/app/policy/edit/parameter/rules/rules.list.dir.js
new file mode 100755
index 00000000..5c3e7457
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/parameter/rules/rules.list.dir.js
@@ -0,0 +1,302 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonRulesList', moonRulesList);
+
+ moonRulesList.$inject = [];
+
+ function moonRulesList() {
+
+ return {
+ templateUrl : 'html/policy/edit/parameter/rules/rules-list.tpl.html',
+ bindToController : true,
+ controller : moonRulesListController,
+ controllerAs : 'list',
+ scope : {
+ policy: '=',
+ editMode : '='
+ },
+ restrict : 'E',
+ replace : true
+ };
+ }
+
+ angular
+ .module('moon')
+ .controller('moonRulesListController', moonRulesListController);
+
+ moonRulesListController.$inject = [ '$scope', '$rootScope', 'NgTableParams', '$filter', 'metaRuleService', 'rulesService', 'dataService', '$translate', 'alertService' ];
+
+ function moonRulesListController( $scope, $rootScope, NgTableParams, $filter, metaRuleService, rulesService, dataService, $translate, alertService ) {
+
+ var list = this;
+
+ list.rules = [];
+ list.editMode = $scope.list.editMode;
+
+ list.loadingRules = true;
+
+ list.table = {};
+
+ list.getRules = getRules;
+ list.hasRules = hasRules;
+ list.refreshRules = refreshRules;
+ list.deleteRules = deleteRules;
+
+ list.getMetaRuleFromRule = getMetaRuleFromRule;
+ list.getCategoryFromRuleIndex = getCategoryFromRuleIndex;
+
+ list.isRuleIndexSubjectCategory = isRuleIndexSubjectCategory;
+ list.isRuleIndexObjectCategory = isRuleIndexObjectCategory;
+ list.isRuleIndexActionCategory = isRuleIndexActionCategory;
+
+ activate();
+
+ function activate(){
+
+ newRulesTable();
+
+ manageRules();
+
+ }
+
+ var rootListeners = {
+
+ 'event:createRulesFromDataRulesSuccess': $rootScope.$on('event:createRulesFromDataRulesSuccess', addRulesToList)
+
+ };
+
+ _.each(rootListeners, function(unbind){
+ $scope.$on('$destroy', rootListeners[unbind]);
+ });
+
+ function manageRules(){
+
+ rulesService.findAllFromPolicyWithCallback(list.policy.id, function(data){
+
+ list.rules = data;
+ list.loadingRules = false;
+
+ refreshRules();
+
+ });
+ }
+
+ function newRulesTable() {
+
+ list.table = new NgTableParams({
+
+ page: 1, // show first page
+ count: 10 // count per page
+
+ }, {
+
+ total: function () { return list.getRules().length; }, // length of data
+ getData: function($defer, params) {
+
+ var orderedData = params.sorting() ? $filter('orderBy')(list.getRules(), params.orderBy()) : list.getRules();
+ $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
+
+ },
+ $scope: { $data: {} }
+
+ });
+
+ return list.table;
+
+ }
+
+ function getMetaRuleFromRule(rule) {
+
+ if(_.has(rule, 'meta_rule')){
+ return rule.meta_rule;
+ }
+
+ // if the call has not been made
+ if(!_.has(rule, 'callMetaRuleInProgress')){
+
+ rule.callMetaRuleInProgress = true;
+
+ metaRuleService.findOneWithCallback(rule.meta_rule_id, function(meta_rule){
+
+ rule.callMetaRuleInProgress = false;
+ rule.meta_rule = meta_rule;
+
+ });
+
+ }
+
+ // if the call is in progress return false
+ return false;
+ }
+
+
+ /**
+ * Prerequisite : meta Rule must be completely loader
+ * Depending on the meta_rule, the rule array will be filled by subject(s), object(s) or an action(s)
+ * the only way to know if rule[i] contains a subject/object/action is to check
+ * how many subject/object/action are associated to a MetaRule
+ * For example if the associated MetaRule contains 2 subjects, 1 object and 2 actions
+ * then the 2 first elements of rule array are 2 subject, the third one will be an object, and the 2 last will be action
+ * @param index
+ * @param rule
+ */
+ function getCategoryFromRuleIndex(index, rule){
+
+ if(!_.has(rule, 'rule_value')){
+ // setting an array which will contains every value of the category
+ rule.rule_value = Array.apply(null, new Array(rule.rule.length)).map(function(){
+ return {
+ category: {}
+ };
+ });
+ }
+
+ if(_.has(rule.rule_value[index], 'callCategoryInProgress') && !rule.rule_value[index].callCategoryInProgress ){
+ return rule.rule_value[index].category;
+ }
+
+ // if the call has not been made
+ if(!_.has(rule.rule_value[index], 'callCategoryInProgress')){
+
+ rule.rule_value[index].callCategoryInProgress = true;
+
+ var categoryId = 0;
+
+ if(list.isRuleIndexSubjectCategory(index, rule)){
+
+ categoryId = rule.meta_rule.subject_categories[index];
+
+ dataService.subject.data.findOne(list.policy.id, categoryId, rule.rule[index], function(category){
+
+ rule.rule_value[index].callCategoryInProgress = false;
+ rule.rule_value[index].category = category;
+
+ });
+
+ }else if(list.isRuleIndexObjectCategory(index, rule)){
+
+
+ categoryId = rule.meta_rule.object_categories[index - rule.meta_rule.subject_categories.length ];
+
+ dataService.object.data.findOne(list.policy.id, categoryId, rule.rule[index], function(category){
+
+ rule.rule_value[index].callCategoryInProgress = false;
+ rule.rule_value[index].category = category;
+
+ });
+
+
+ }else if(list.isRuleIndexActionCategory(index, rule)){
+
+ categoryId = rule.meta_rule.action_categories[index - rule.meta_rule.subject_categories.length - rule.meta_rule.object_categories.length ];
+
+ dataService.action.data.findOne(list.policy.id, categoryId, rule.rule[index], function(category){
+
+ rule.rule_value[index].callCategoryInProgress = false;
+ rule.rule_value[index].category = category;
+
+ });
+
+ }else{
+
+ rule.rule_value[index].callCategoryInProgress = false;
+ rule.rule_value[index].category = {
+ name : 'ERROR'
+ };
+ }
+
+ }
+
+ // if the call is in progress return false
+ return false;
+ }
+
+ function isRuleIndexSubjectCategory(index, rule){
+
+ var ind = index + 1;
+
+ return ind <= rule.meta_rule.subject_categories.length;
+
+ }
+
+ function isRuleIndexObjectCategory(index, rule){
+
+ var ind = index + 1;
+
+ return rule.meta_rule.subject_categories.length < ind && ind <= ( rule.meta_rule.object_categories.length + rule.meta_rule.subject_categories.length );
+
+ }
+
+ function isRuleIndexActionCategory(index, rule){
+
+ var ind = index + 1;
+
+ return ( rule.meta_rule.object_categories.length + rule.meta_rule.subject_categories.length ) < ind && ind <= ( rule.meta_rule.object_categories.length + rule.meta_rule.subject_categories.length + rule.meta_rule.action_categories.length);
+
+ }
+
+ function getRules() {
+ return (list.rules) ? list.rules : [];
+ }
+
+ function hasRules() {
+ return list.getRules().length > 0;
+ }
+
+ /**
+ * Refresh the table
+ */
+ function refreshRules(){
+ list.table.total(list.rules.length);
+ list.table.reload();
+ }
+
+ function addRulesToList(event, rules){
+ list.rules.push(rules);
+ refreshRules();
+ }
+
+ /**
+ * Delete
+ */
+ function deleteRules(rules){
+
+ rules.loader = true;
+
+ rulesService.delete(rules.id, list.policy.id, deleteRulesSuccess, deleteRulesError );
+
+ function deleteRulesSuccess(){
+
+ $translate('moon.policy.rules.edit.action.add.delete.success').then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ removeRulesFromList(rules);
+ refreshRules();
+
+ rules.loader = false;
+
+ }
+
+ function deleteRulesError(reason){
+
+ $translate('moon.policy.rules.edit.action.add.delete.success', {reason: reason.message}).then( function(translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ rules.loader = false;
+
+ }
+
+ }
+
+ function removeRulesFromList(rules){
+ list.rules = _.without(list.rules, rules);
+ }
+ }
+
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/policy-edit-basic.tpl.html b/old/moon_gui/static/app/policy/edit/policy-edit-basic.tpl.html
new file mode 100755
index 00000000..f55c1d05
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/policy-edit-basic.tpl.html
@@ -0,0 +1,89 @@
+<div class="row">
+
+ <form class="form-horizontal" role="form" name="edit.form">
+
+ <div class="form-group">
+
+ <label for="id" class="col-sm-3 control-label" data-translate="moon.policy.edit.basic.form.id">Id</label>
+
+ <div class="col-sm-6">
+
+ <input name="id" id="id" disabled class="form-control" type="text" data-ng-model="edit.policyToEdit.id" required />
+
+ </div>
+
+ </div>
+
+ <div class="form-group" ng-class="{'has-error': edit.form.name.$invalid && edit.form.name.$dirty}">
+
+ <label for="name" class="col-sm-3 control-label" data-translate="moon.policy.edit.basic.form.name">Name</label>
+
+ <div class="col-sm-6">
+
+ <input name="name" id="name" class="form-control" type="text" data-ng-model="edit.policyToEdit.name" required />
+
+ <div class="help-block" ng-show="edit.form.name.$dirty && edit.form.name.$invalid">
+ <small class="error" ng-show="edit.form.name.$error.required" data-translate="moon.policy.edit.basic.check.name.required">Name is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+
+ <div class="form-group" ng-class="{'has-error': edit.form.model.$dirty && (edit.form.model.$invalid || !edit.selectedModel)}">
+
+ <label class="col-sm-3 control-label" data-translate="moon.policy.edit.basic.form.model">Models</label>
+
+ <div class="col-sm-6">
+
+ <ui-select ng-model="edit.selectedModel" name="model" required>
+ <ui-select-match placeholder="(None)">{{$select.selected.name}}</ui-select-match>
+ <ui-select-choices repeat="model in edit.models">
+ <div ng-value="model">{{model.name}}</div>
+ </ui-select-choices>
+ </ui-select>
+
+ <moon-loader ng-if="edit.modelsLoading"></moon-loader>
+
+ <div class="help-block" ng-show="edit.form.model.$dirty && (edit.form.model.$invalid || !edit.selectedModel)">
+ <small class="error" ng-show="edit.form.model.$error.required" data-translate="moon.policy.edit.basic.check.model.required">Model is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <label for="description" class="col-sm-3 control-label" data-translate="moon.policy.edit.basic.form.description">Description</label>
+ <div class="col-sm-6">
+ <textarea id="description" name="description" class="form-control" data-ng-model="edit.policyToEdit.description"></textarea>
+ </div>
+
+ </div>
+
+ <div class="form-group">
+
+ <div class="col-sm-2 col-sm-offset-3">
+
+ <a href="" ng-disabled="edit.loading" ng-click="edit.init()" class="btn btn-default">
+ <span data-translate="moon.policy.edit.basic.action.init">Init</span>
+ </a>
+ </div>
+
+ <div class="col-sm-4 col-sm-offset-2">
+
+ <a href="" ng-disabled="edit.loading" ng-click="edit.editPolicy()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-save"></span>
+ <span data-translate="moon.policy.edit.basic.action.update">Update</span>
+ </a>
+
+ <moon-loader ng-if="edit.loading"></moon-loader>
+ </div>
+
+ </div>
+
+ </form>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/edit/policy-edit.tpl.html b/old/moon_gui/static/app/policy/edit/policy-edit.tpl.html
new file mode 100755
index 00000000..60841168
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/policy-edit.tpl.html
@@ -0,0 +1,202 @@
+<div class="container">
+
+ <div class="row">
+ <h3 class="pull-left" data-translate="moon.policy.edit.title" data-translate-values="{ policyName: edit.policy.name }">Edit</h3>
+ </div>
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <span data-translate="moon.policy.edit.basic.title" >Basic Information</span>
+ <a href="" ng-click="edit.editBasic = !edit.editBasic">
+ <span data-translate="moon.policy.edit.update">Update</span>
+ <span class="glyphicon glyphicon-cog"></span>
+ </a>
+
+ </div>
+
+ <div class="panel-body">
+
+ <div ng-if="edit.editBasic">
+ <moon-policy-edit-basic policy="edit.policy"></moon-policy-edit-basic>
+ </div>
+
+ <div ng-if="!edit.editBasic">
+
+ <dl class="dl-horizontal">
+
+ <dt data-translate="moon.policy.edit.basic.form.id">Id</dt>
+ <dd ng-bind="edit.policy.id"></dd>
+
+ <dt data-translate="moon.policy.edit.basic.form.name">Name</dt>
+ <dd ng-bind="edit.policy.name"></dd>
+
+ <dt data-translate="moon.policy.edit.basic.form.genre">Genre</dt>
+ <dd ng-bind="edit.policy.genre"></dd>
+
+ <dt data-translate="moon.policy.edit.basic.form.model">Model</dt>
+ <dd>
+
+ <span ng-if="edit.loadingModel">
+ <moon-loader ng-if="edit.loadingModel"></moon-loader>
+ </span>
+ <span ng-if="!edit.loadingModel">
+ <span ng-bind="edit.policy.model.name" ></span>
+ </span>
+
+ </dd>
+
+ <dt data-translate="moon.policy.edit.basic.form.description">Description</dt>
+ <dd ng-bind="edit.policy.description"></dd>
+
+ </dl>
+
+ </div>
+
+ </div>
+
+ </div>
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <span data-translate="moon.policy.edit.perimeter.title" >Perimeters</span>
+
+ <a href="" ng-click="edit.showPart('showPerimeters')">
+
+ <span ng-if="!edit.showPerimeters">
+ <span data-translate="moon.policy.edit.show.open">Show</span>
+ <span class="glyphicon glyphicon-eye-open"></span>
+ </span>
+
+ <span ng-if="edit.showPerimeters">
+ <span data-translate="moon.policy.edit.show.close">Show</span>
+ <span class="glyphicon glyphicon-eye-close"></span>
+ </span>
+
+ </a>
+
+ <!--<a href="" ng-if="edit.showPerimeters">
+ <span data-translate="moon.policy.edit.update">Update</span>
+ <span class="glyphicon glyphicon-cog"></span>
+ </a>-->
+
+ </div>
+
+ <div class="panel-body" ng-if="edit.showPerimeters">
+
+ <moon-perimeter-list edit-mode="true" policy="edit.policy" ></moon-perimeter-list>
+
+ </div>
+
+ </div>
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <span data-translate="moon.policy.edit.data.title" >Data</span>
+
+ <a href="" ng-click="edit.showPart('showData')">
+
+ <span ng-if="!edit.showData">
+ <span data-translate="moon.policy.edit.show.open">Show</span>
+ <span class="glyphicon glyphicon-eye-open"></span>
+ </span>
+
+ <span ng-if="edit.showData">
+ <span data-translate="moon.policy.edit.show.close">Show</span>
+ <span class="glyphicon glyphicon-eye-close"></span>
+ </span>
+
+ </a>
+
+ <!--<a href="" ng-if="edit.showData">
+ <span data-translate="moon.policy.edit.update">Update</span>
+ <span class="glyphicon glyphicon-cog"></span>
+ </a>-->
+
+ </div>
+
+ <div class="panel-body" ng-if="edit.showData" > <!-- -->
+
+ <moon-data-list edit-mode="true" policy="edit.policy" ></moon-data-list>
+
+ </div>
+
+ </div>
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <span data-translate="moon.policy.edit.rules.title" >Rules</span>
+
+ <a href="" ng-click="edit.showPart('showRules')">
+
+ <span ng-if="!edit.showRules">
+ <span data-translate="moon.policy.edit.show.open">Show</span>
+ <span class="glyphicon glyphicon-eye-open"></span>
+ </span>
+
+ <span ng-if="edit.showRules">
+ <span data-showRules="moon.policy.edit.show.close">Close</span>
+ <span class="glyphicon glyphicon-eye-close"></span>
+ </span>
+
+ </a>
+
+ <!--<a href="" ng-if="edit.showRules">
+ <span data-translate="moon.policy.edit.update">Update</span>
+ <span class="glyphicon glyphicon-cog"></span>
+ </a>-->
+
+ </div>
+
+ <div class="panel-body" ng-if="edit.showRules">
+
+ <moon-rules-list edit-mode="true" policy="edit.policy" ></moon-rules-list>
+
+ </div>
+
+ </div>
+
+
+ <div class="panel panel-default">
+
+ <div class="panel-heading">
+
+ <span data-translate="moon.policy.edit.assignments.title" >Assignments</span>
+
+ <a href="" ng-click="edit.showPart('showAssignments')">
+
+ <span ng-if="!edit.showAssignments">
+ <span data-translate="moon.policy.edit.show.open">Show</span>
+ <span class="glyphicon glyphicon-eye-open"></span>
+ </span>
+
+ <span ng-if="edit.showAssignments">
+ <span data-showRules="moon.policy.edit.show.close">Close</span>
+ <span class="glyphicon glyphicon-eye-close"></span>
+ </span>
+
+ </a>
+
+ <!--<a href="" ng-if="edit.showRules">
+ <span data-translate="moon.policy.edit.update">Update</span>
+ <span class="glyphicon glyphicon-cog"></span>
+ </a>-->
+
+ </div>
+
+ <div class="panel-body" ng-if="edit.showAssignments">
+
+ <moon-assignments-list edit-mode="true" policy="edit.policy" ></moon-assignments-list>
+
+ </div>
+
+ </div>
+
+</div>
diff --git a/old/moon_gui/static/app/policy/edit/policy.controller.edit.js b/old/moon_gui/static/app/policy/edit/policy.controller.edit.js
new file mode 100755
index 00000000..cd6e429b
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/policy.controller.edit.js
@@ -0,0 +1,88 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('PolicyEditController', PolicyEditController);
+
+ PolicyEditController.$inject = ['$scope', '$rootScope', 'policy', 'modelService'];
+
+ function PolicyEditController($scope, $rootScope, policy, modelService) {
+
+ var edit = this;
+
+ edit.policy = policy;
+
+ edit.editBasic = false;
+
+ edit.showPerimeters = false;
+ edit.showData = false;
+ edit.showRules = false;
+ edit.showAssignments = false;
+
+ edit.showPart = showPart;
+
+
+ activate();
+
+ function showPart(partName) {
+ var state = edit[partName];
+
+ edit.showPerimeters = false;
+ edit.showData = false;
+ edit.showRules = false;
+ edit.showAssignments = false;
+
+ edit[partName] = !state;
+ }
+
+
+ function activate(){
+
+ manageModel();
+
+ }
+
+ function manageModel(){
+
+ edit.loadingModel = true;
+
+ modelService.findOneWithCallback( edit.policy.model_id, function(model){
+
+ edit.loadingModel = false;
+ edit.policy.model = model;
+
+ });
+
+ }
+
+ /*
+ * ---- events
+ */
+ var rootListeners = {
+
+ 'event:policyUpdatedSuccess': $rootScope.$on('event:policyUpdatedSuccess', policyUpdatedSuccess)
+
+ };
+
+ for (var unbind in rootListeners) {
+ $scope.$on('$destroy', rootListeners[unbind]);
+ }
+
+ /**
+ * When the model is updated, this function refresh the current model with the new changes
+ * @param event
+ * @param policy
+ */
+ function policyUpdatedSuccess(event, policy){
+
+ edit.policy = policy;
+
+ manageModel();
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/policy/edit/policy.edit.basic.dir.js b/old/moon_gui/static/app/policy/edit/policy.edit.basic.dir.js
new file mode 100755
index 00000000..c32d9e69
--- /dev/null
+++ b/old/moon_gui/static/app/policy/edit/policy.edit.basic.dir.js
@@ -0,0 +1,134 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonPolicyEditBasic', moonPolicyEditBasic);
+
+ moonPolicyEditBasic.$inject = [];
+
+ function moonPolicyEditBasic() {
+
+ return {
+ templateUrl : 'html/policy/edit/policy-edit-basic.tpl.html',
+ bindToController : true,
+ controller : moonPolicyEditBasicController,
+ controllerAs : 'edit',
+ scope : {
+ policy : '='
+ },
+ restrict : 'E',
+ replace : true
+ };
+ }
+
+ angular
+ .module('moon')
+ .controller('moonPolicyEditBasicController', moonPolicyEditBasicController);
+
+ moonPolicyEditBasicController.$inject = ['$scope', 'policyService', 'formService', 'alertService', '$translate', 'utilService', 'modelService'];
+
+ function moonPolicyEditBasicController($scope, policyService, formService, alertService, $translate, utilService, modelService){
+
+ var edit = this;
+
+ edit.editPolicy = editPolicy;
+ edit.init = init;
+
+ edit.form = {};
+ edit.modelsLoading = true;
+
+
+ activate();
+
+ function activate(){
+
+ edit.policy = $scope.edit.policy;
+
+ edit.policyToEdit = angular.copy(edit.policy);
+
+ console.log(edit.policyToEdit);
+
+ resolveModels();
+
+ }
+
+ /*
+ *
+ */
+
+ function resolveModels() {
+
+ modelService.findAllWithCallBack(resolveModelsCallback);
+
+ }
+
+ function resolveModelsCallback(models) {
+
+ edit.models = models;
+
+ _.each(models, function(model){
+
+ if(model.id === edit.policy.model_id){
+ edit.selectedModel = model;
+ }
+
+ });
+
+ edit.modelsLoading = false;
+
+ }
+
+
+ function editPolicy(){
+
+ if(formService.isInvalid(edit.form)) {
+
+ formService.checkFieldsValidity(edit.form);
+
+ }else{
+
+ edit.loading = true;
+
+ delete edit.policyToEdit.model;
+
+ edit.policyToEdit.model_id = edit.selectedModel.id;
+
+ policyService.update(edit.policyToEdit, updateSuccess, updateError);
+
+ }
+
+ function updateSuccess(data) {
+
+ var updatedPolicy = utilService.transformOne(data, 'policies');
+
+ $translate('moon.policy.edit.basic.success', { policyName: updatedPolicy.name }).then( function(translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ edit.loading = false;
+
+ $scope.$emit('event:policyUpdatedSuccess', updatedPolicy);
+
+ }
+
+ function updateError(reason) {
+
+ $translate('moon.policy.edit.basic.error', { policyName: edit.policy.name }).then( function(translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ edit.loading = false;
+
+ }
+ }
+
+ function init(){
+
+ edit.policyToEdit = angular.copy(edit.policy);
+
+ }
+ }
+
+})();
diff --git a/old/moon_gui/static/app/policy/policy-list.tpl.html b/old/moon_gui/static/app/policy/policy-list.tpl.html
new file mode 100755
index 00000000..aeb90f0b
--- /dev/null
+++ b/old/moon_gui/static/app/policy/policy-list.tpl.html
@@ -0,0 +1,131 @@
+<div class="container">
+
+ <div>
+ <form class="form-inline pull-right">
+ <div class="form-group">
+ <div>
+ <input id="searcPolicy" data-ng-model="list.search.query" type="text" class="form-control" placeholder="{{'moon.policy.list.search.placeholder' | translate}}" />
+ </div>
+ </div>
+ <div class="form-group">
+ <div>
+ <button type="submit" class="btn btn-danger" data-ng-click="list.search.reset()" data-translate="moon.policy.list.search.reset">Reset</button>
+ </div>
+ </div>
+ </form>
+ </div>
+
+ <div>&nbsp;</div>
+ <div>&nbsp;</div>
+ <div>&nbsp;</div>
+
+
+ <div class="row" >
+
+ <div class="table-responsive" data-role="table">
+
+ <table class="table table-striped table-hover" ng-table="list.table">
+
+ <colgroup>
+ <col class="col-md-4" />
+ <col class="col-md-2" />
+ <col class="col-md-2" />
+ <col class="col-md-1" />
+ </colgroup>
+
+ <thead>
+
+ <tr>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('name', 'asc'), 'sort-desc': list.table.isSortBy('name', 'desc') }"
+ ng-click="list.table.sorting('name', list.table.isSortBy('name', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.policy.list.table.name">Name</div>
+ </th>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('genre', 'asc'), 'sort-desc': list.table.isSortBy('genre', 'desc') }"
+ ng-click="list.table.sorting('genre', list.table.isSortBy('genre', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.policy.list.table.genre">Genre</div>
+ </th>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('description', 'asc'), 'sort-desc': list.table.isSortBy('description', 'desc') }"
+ ng-click="list.table.sorting('description', list.table.isSortBy('description', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.policy.list.table.description">Description</div>
+ </th>
+
+ <th class="customTables sortable">
+ <div data-translate="moon.policy.list.action.title">Actions</div>
+ </th>
+
+ </tr>
+
+ </thead>
+
+ <tbody ng-if="!list.hasPolicies()">
+ <tr>
+ <td colspan="12"><span data-translate="moon.policy.list.table.notFound">There is no policy</span></td>
+ </tr>
+ </tbody>
+
+ <tbody ng-if="list.hasPolicies()">
+
+ <tr ng-repeat="policy in $data | filter:list.search.find | orderBy:sort:reverse">
+
+ <td ng-bind="policy.name"></td>
+
+ <td ng-bind="policy.genre"></td>
+
+ <td ng-bind="policy.description"></td>
+
+ <td>
+ <div class="dropdown">
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.policy.list.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu">
+
+ <li>
+ <a href="" ui-sref="moon.policy.edit({id: policy.id})">
+ <span class="glyphicon glyphicon-cog"></span>
+ <span class="control-label" data-translate="moon.policy.list.action.edit">Edit</span>
+ </a>
+ </li>
+
+ <li class="divider"></li>
+
+ <li>
+ <a href="" ng-click="list.del.showModal(policy)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.policy.list.action.delete">Delete</span>
+ </a>
+ </li>
+
+ </ul>
+ </div>
+ </td>
+
+ </tr>
+
+ </tbody>
+
+ </table>
+
+ </div>
+
+ <div class="container">
+
+ <div class="form-inline form-group">
+ <a href="" ng-click="list.add.showModal()" class="btn btn-default">
+ <span class="glyphicon glyphicon-plus-sign"></span>
+ <span data-translate="moon.policy.list.action.add">Add Model</span>
+ </a>
+ </div>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/policy-mapped-list.tpl.html b/old/moon_gui/static/app/policy/policy-mapped-list.tpl.html
new file mode 100755
index 00000000..127dae3b
--- /dev/null
+++ b/old/moon_gui/static/app/policy/policy-mapped-list.tpl.html
@@ -0,0 +1,88 @@
+<div class="container">
+
+ <div class="row" ng-if="list.loadingPolicies">
+ <moon-loader ng-if="list.loadingPolicies"></moon-loader>
+ </div>
+
+ <div class="row" ng-if="!list.loadingPolicies" >
+
+ <div class="table-responsive" data-role="table">
+
+ <table class="table table-striped table-hover" ng-table="list.table">
+
+ <colgroup>
+ <col class="col-md-4" />
+ <col class="col-md-2" />
+ <col class="col-md-2" />
+ <col class="col-md-1" />
+ </colgroup>
+
+ <thead>
+
+ <tr>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('name', 'asc'), 'sort-desc': list.table.isSortBy('name', 'desc') }"
+ ng-click="list.table.sorting('name', list.table.isSortBy('name', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.policy.list.table.name">Name</div>
+ </th>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('genre', 'asc'), 'sort-desc': list.table.isSortBy('genre', 'desc') }"
+ ng-click="list.table.sorting('genre', list.table.isSortBy('genre', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.policy.list.table.genre">Genre</div>
+ </th>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('description', 'asc'), 'sort-desc': list.table.isSortBy('description', 'desc') }"
+ ng-click="list.table.sorting('description', list.table.isSortBy('description', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.policy.list.table.description">Description</div>
+ </th>
+
+ <th class="customTables sortable">
+ <div data-translate="moon.policy.list.action.title">Actions</div>
+ </th>
+ </tr>
+
+ </thead>
+
+ <tbody ng-if="!list.hasPolicies()">
+ <tr>
+ <td colspan="12"><span data-translate="moon.policy.list.table.notFound">There is no policy</span></td>
+ </tr>
+ </tbody>
+
+ <tbody ng-if="list.hasPolicies()">
+
+ <tr ng-repeat="policy in $data | filter:list.search.find | orderBy:sort:reverse">
+ <td ng-bind="policy.name"></td>
+ <td ng-bind="policy.genre"></td>
+ <td ng-bind="policy.description"></td>
+ <td>
+ <a href="" ng-click="list.unmap.showModal(policy)">
+ <span class="glyphicon glyphicon-transfer"></span>
+ <em data-translate="moon.policy.list.action.unmap">Unmap</em>
+ </a>
+ </td>
+ </tr>
+
+ </tbody>
+
+ </table>
+
+ </div>
+
+ <div class="container">
+
+ <div class="form-inline form-group">
+ <a href="" ng-click="list.map.showModal()" class="btn btn-default">
+ <span class="glyphicon glyphicon-link"></span>
+ <em data-translate="moon.policy.list.action.map">Map a Policy to PDP</em>
+ </a>
+ </div>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/policy/policy.controller.list.js b/old/moon_gui/static/app/policy/policy.controller.list.js
new file mode 100755
index 00000000..fc2c6503
--- /dev/null
+++ b/old/moon_gui/static/app/policy/policy.controller.list.js
@@ -0,0 +1,175 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('PolicyListController', PolicyListController);
+
+ PolicyListController.$inject = ['$scope', 'policies', 'NgTableParams', '$filter', '$modal', '$rootScope'];
+
+ function PolicyListController($scope, policies, NgTableParams, $filter, $modal, $rootScope) {
+
+ var list = this;
+
+ list.policies = policies;
+
+ list.getPolicies = getPolicies;
+ list.hasPolicies = hasPolicies;
+ list.addPolicy = addPolicy;
+ list.refreshPolicies = refreshPolicies;
+ list.deletePolicy = deletePolicy;
+
+ list.table = {};
+
+ list.search = { query: '',
+ find: searchPolicy,
+ reset: searchReset };
+
+ list.add = { modal: $modal({ template: 'html/policy/action/policy-add.tpl.html', show: false }),
+ showModal: showAddModal };
+
+ list.del = { modal: $modal({ template: 'html/policy/action/policy-delete.tpl.html', show: false }),
+ showModal: showDeleteModal };
+
+ activate();
+
+ function activate(){
+
+ newPoliciesTable();
+
+ }
+
+
+ /*
+ * ---- events
+ */
+
+ var rootListeners = {
+
+ 'event:policyCreatedSuccess': $rootScope.$on('event:policyCreatedSuccess', policyCreatedSuccess),
+ 'event:policyCreatedError': $rootScope.$on('event:policyCreatedError', policyCreatedError),
+
+ 'event:policyDeletedSuccess': $rootScope.$on('event:policyDeletedSuccess', policyDeletedSuccess),
+ 'event:policyDeletedError': $rootScope.$on('event:policyDeletedError', policyDeletedError)
+
+ };
+
+ for (var unbind in rootListeners) {
+ $scope.$on('$destroy', rootListeners[unbind]);
+ }
+
+ function getPolicies() {
+ return (list.policies) ? list.policies : [];
+ }
+
+ function hasPolicies() {
+ return list.getPolicies().length > 0;
+ }
+
+ function newPoliciesTable() {
+
+ list.table = new NgTableParams({
+
+ page: 1, // show first page
+ count: 10, // count per page
+ sorting: {
+ name: 'asc',
+ genre: 'asc'
+ }
+
+ }, {
+
+ total: function () { return list.getPolicies().length; }, // length of data
+ getData: function($defer, params) {
+
+ var orderedData = params.sorting() ? $filter('orderBy')(list.getPolicies(), params.orderBy()) : list.getPolicies();
+ $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
+
+ },
+ $scope: { $data: {} }
+
+ });
+
+ return list.table;
+
+ }
+
+
+ /*
+ * ---- search
+ */
+
+ function searchPolicy(policy){
+ return (policy.name.indexOf(list.search.query) !== -1 || policy.genre.indexOf(list.search.query) !== -1 || policy.description.indexOf(list.search.query) !== -1);
+ }
+
+ function searchReset() {
+ list.search.query = '';
+ }
+
+ /*
+ * ---- add
+ */
+ function showAddModal() {
+ list.add.modal.$promise.then(list.add.modal.show);
+ }
+
+ function policyCreatedSuccess(event, pdp) {
+
+ list.addPolicy(pdp);
+ list.refreshPolicies();
+
+ list.add.modal.hide();
+
+ }
+
+ function policyCreatedError(event, pdp) {
+ list.add.modal.hide();
+ }
+
+ function addPolicy(policy) {
+ list.policies.push(policy);
+ }
+
+ function refreshPolicies() {
+
+ list.table.total(list.policies.length);
+ list.table.reload();
+
+ }
+
+ /*
+ * ---- delete
+ */
+
+ function showDeleteModal(policy) {
+
+ list.del.modal.$scope.policy = policy;
+ list.del.modal.$promise.then(list.del.modal.show);
+
+ }
+
+ function deletePolicy(policy) {
+
+ list.policies = _.chain(list.policies).reject({id: policy.id}).value();
+
+ }
+
+ function policyDeletedSuccess(event, policy) {
+
+ list.deletePolicy(policy);
+ list.refreshPolicies();
+
+ list.del.modal.hide();
+
+ }
+
+ function policyDeletedError(event, policy) {
+ list.del.modal.hide();
+ }
+
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/policy/policy.mapped.list.dir.js b/old/moon_gui/static/app/policy/policy.mapped.list.dir.js
new file mode 100755
index 00000000..78bb3b8d
--- /dev/null
+++ b/old/moon_gui/static/app/policy/policy.mapped.list.dir.js
@@ -0,0 +1,202 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .directive('moonPolicyMappedList', moonPolicyMappedList);
+
+ moonPolicyMappedList.$inject = [];
+
+ function moonPolicyMappedList() {
+
+ return {
+ templateUrl : 'html/policy/policy-mapped-list.tpl.html',
+ bindToController : true,
+ controller : moonPolicyMappedListController,
+ controllerAs : 'list',
+ scope : {
+ pdp : '='
+ },
+ restrict : 'E',
+ replace : true
+ };
+ }
+
+ angular
+ .module('moon')
+ .controller('moonPolicyMappedListController', moonPolicyMappedListController);
+
+ moonPolicyMappedListController.$inject = ['$scope', '$rootScope', 'NgTableParams', '$modal', '$filter', 'policyService'];
+
+ function moonPolicyMappedListController($scope, $rootScope, NgTableParams, $modal, $filter, policyService){
+
+ var list = this;
+
+ list.table = {};
+
+
+ list.pdp = $scope.list.pdp;
+
+ list.getPolicies = getPolicies;
+ list.hasPolicies = hasPolicies;
+ list.refreshPolicies = refreshPolicies;
+
+ list.loadingPolicies = true;
+
+ list.policies = [];
+
+
+ activate();
+
+ function activate() {
+
+ loadPolicices(false);
+
+ }
+
+ /**
+ *
+ * @param refresh boolean, if !refresh then newPolicYtable will be called, if refresh, then refreshPolicies is called
+ */
+ function loadPolicices(refresh){
+
+ if(_.isUndefined( list.pdp.security_pipeline)){
+ return;
+ }
+ list.policiesId = list.pdp.security_pipeline;
+
+ policyService.findSomeWithCallback(list.policiesId, function(policies){
+
+ list.policies = policies;
+
+ list.loadingPolicies = false;
+
+ if(refresh){
+
+ refreshPolicies();
+
+ }else{
+
+ newMPolicyTable();
+
+ }
+
+ });
+
+ }
+
+ list.map = { modal: $modal({ template: 'html/policy/action/mapping/policy-map.tpl.html', show: false }),
+ showModal: showMapModal };
+
+ list.unmap = { modal: $modal({ template: 'html/policy/action/mapping/policy-unmap.tpl.html', show: false }),
+ showModal: showUnmapModal };
+
+ /*
+ * ---- events
+ */
+ var rootListeners = {
+
+ 'event:policyMapToPdpSuccess': $rootScope.$on('event:policyMapToPdpSuccess', policyMapToPdpSuccess),
+ 'event:policyMapToPdpError': $rootScope.$on('event:policyMapToPdpError', policyMapToPdpError),
+
+ 'event:policyUnMappedToPdpSuccess': $rootScope.$on('event:policyUnMappedToPdpSuccess', policyUnmappedSuccess),
+ 'event:policyUnMappedToPdpError': $rootScope.$on('event:policyUnMappedToPdpError', policyUnmappedError)
+
+ };
+
+ for (var unbind in rootListeners) {
+ $scope.$on('$destroy', rootListeners[unbind]);
+ }
+
+
+
+ function newMPolicyTable() {
+
+ list.table = new NgTableParams({
+
+ page: 1, // show first page
+ count: 10 // count per page
+
+ }, {
+
+ total: function () { return list.getPolicies().length; }, // length of data
+ getData: function($defer, params) {
+
+ var orderedData = params.sorting() ? $filter('orderBy')(list.getPolicies(), params.orderBy()) : list.getPolicies();
+ $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
+
+ },
+ $scope: { $data: {} }
+
+ });
+
+ return list.table;
+
+ }
+
+
+ function getPolicies() {
+ return (list.policies) ? list.policies : [];
+ }
+
+ function hasPolicies() {
+ return list.getPolicies().length > 0;
+ }
+
+ function refreshPolicies(){
+
+ list.table.total(list.getPolicies().length);
+ list.table.reload();
+
+ }
+
+ function showMapModal(){
+ list.map.modal.$scope.pdp = list.pdp;
+ list.map.modal.$promise.then(list.map.modal.show);
+ }
+
+ function showUnmapModal(policy){
+
+ list.unmap.modal.$scope.pdp = list.pdp;
+ list.unmap.modal.$scope.policy = policy;
+
+ list.unmap.modal.$promise.then(list.unmap.modal.show);
+
+ }
+
+ function policyMapToPdpSuccess(event, pdp){
+
+ list.pdp = pdp;
+
+ loadPolicices(true);
+
+ list.map.modal.hide();
+
+ }
+
+
+ function policyMapToPdpError(event) {
+
+ list.map.modal.hide();
+
+ }
+
+ function policyUnmappedSuccess(event, pdp) {
+
+ list.pdp = pdp;
+
+ loadPolicices(true);
+
+ list.unmap.modal.hide();
+
+ }
+
+ function policyUnmappedError(event) {
+ list.unmap.modal.hide();
+ }
+
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/project/action/mapping/project-map.tpl.html b/old/moon_gui/static/app/project/action/mapping/project-map.tpl.html
new file mode 100755
index 00000000..5ffd98e2
--- /dev/null
+++ b/old/moon_gui/static/app/project/action/mapping/project-map.tpl.html
@@ -0,0 +1,62 @@
+<div ng-controller="ProjectMapController as map" class="modal" tabindex="-1" data-role="modalMappingProject">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.project.map.title" data-translate-values="{projectName: map.project.name}"></h4>
+ </div>
+
+ <div class="modal-body">
+
+ <form class="form-horizontal" role="form" name="map.form">
+
+ <div class="form-group" ng-class="{'has-error': map.form.pdp.$dirty && (map.form.pdp.$invalid || !map.selectedPDP)}">
+
+ <label class="col-sm-3 control-label" data-translate="moon.project.map.form.pdp">PDP</label>
+
+ <div class="col-sm-6">
+
+ <ui-select ng-model="map.selectedPDP" name="pdp" required>
+ <ui-select-match placeholder="(None)" ng-bind="$select.selected.name"></ui-select-match>
+ <ui-select-choices repeat="pdp in map.pdps">
+ <div ng-bind="pdp.name" ng-value="pdp"></div>
+ </ui-select-choices>
+ </ui-select>
+
+ <img ng-if="map.pdpsLoading" src="assets/img/ajax-loader.gif" />
+
+ <div class="help-block" ng-show="map.form.pdp.$dirty && (map.form.pdp.$invalid || !map.selectedPDP)">
+ <small class="error" ng-show="map.form.pdp.$error.required" data-translate="moon.project.map.check.pdp.required">PDP is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+ </form>
+
+ </div>
+
+ <div class="modal-footer">
+ <div class="btn-toolbar" style="float: right;">
+ <a href="" ng-click="$hide()" class="btn btn-default">
+ <span data-translate="moon.project.map.action.cancel">Cancel</span>
+ </a>
+ <a href="" ng-disabled="map.mappingLoading" ng-click="map.map()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-link"></span>
+ <span data-translate="moon.project.map.action.map">Map</span>
+ </a>
+
+ <img ng-if="map.mappingLoading" src="assets/img/ajax-loader.gif" />
+
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+
+</div>
diff --git a/old/moon_gui/static/app/project/action/mapping/project-unmap.tpl.html b/old/moon_gui/static/app/project/action/mapping/project-unmap.tpl.html
new file mode 100755
index 00000000..5cc5c6dd
--- /dev/null
+++ b/old/moon_gui/static/app/project/action/mapping/project-unmap.tpl.html
@@ -0,0 +1,33 @@
+<div ng-controller="ProjectUnMapController as unmap" class="modal" tabindex="-1" data-role="modalUnmapProject">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.project.unmap.title"></h4>
+ </div>
+
+ <div class="modal-body">
+ <span data-translate="moon.project.unmap.content" data-translate-values="{ projectName: unmap.project.name, pdpName: unmap.project.mapping.authz.pdp.name }"></span>
+ </div>
+
+ <div class="modal-footer">
+ <div class="btn-toolbar" style="float: right;">
+ <a href="" ng-click="$hide()" class="btn btn-default">
+ <span data-translate="moon.project.unmap.action.cancel">Cancel</span>
+ </a>
+ <a href="" ng-disabled="unmap.unMappingLoading" ng-click="unmap.unmap()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-transfer"></span>
+ <span data-translate="moon.project.unmap.action.unmap">Unmap</span>
+ </a>
+ <img ng-if="unmap.unMappingLoading" src="assets/img/ajax-loader.gif" />
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/project/action/mapping/project.controller.map.js b/old/moon_gui/static/app/project/action/mapping/project.controller.map.js
new file mode 100755
index 00000000..afa2bfc0
--- /dev/null
+++ b/old/moon_gui/static/app/project/action/mapping/project.controller.map.js
@@ -0,0 +1,107 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('ProjectMapController', ProjectMapController);
+
+ ProjectMapController.$inject = ['$scope', '$translate', 'alertService', 'formService', 'pdpService'];
+
+ function ProjectMapController($scope, $translate, alertService, formService, pdpService) {
+
+ var map = this;
+
+ /*
+ *
+ */
+
+ map.form = {};
+
+ map.project = $scope.project;
+
+ map.pdps = [];
+
+ map.pdpsLoading = true;
+
+ map.selectedPDP = null;
+
+ map.map = mapProject;
+
+ activate();
+
+ function activate(){
+
+ resolvePDPs();
+
+ }
+
+ /*
+ *
+ */
+
+ function resolvePDPs() {
+
+ pdpService.findAllWithCallBack(resolveMappedProjects);
+
+ }
+
+ function resolveMappedProjects(pdps) {
+
+ map.pdps = _.filter(pdps, function(pdp){
+ return _.isNull(pdp.keystone_project_id);
+ });
+
+ map.pdpsLoading = false;
+
+ }
+
+ function mapProject() {
+
+ if(formService.isInvalid(map.form)) {
+
+ formService.checkFieldsValidity(map.form);
+
+ } else {
+
+ map.mappingLoading = true;
+
+ pdpService.map( map.selectedPDP, map.project.id, mapSuccess, mapError);
+
+ }
+
+ function mapSuccess(data) {
+
+ map.project.pdp = map.selectedPDP;
+
+ $translate('moon.project.map.success', { projectName: map.project.name, pdpName: map.selectedPDP.name }).then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ map.mappingLoading = false;
+
+ $scope.$emit('event:projectMappedSuccess', map.project);
+
+ }
+
+ function mapError(response) {
+
+ $translate('moon.project.map.error', { projectName: map.project.name, pdpName: map.selectedPDP.name }).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ map.mappingLoading = false;
+
+ $scope.$emit('event:projectMappedError', map.project);
+
+ }
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/project/action/mapping/project.controller.unmap.js b/old/moon_gui/static/app/project/action/mapping/project.controller.unmap.js
new file mode 100755
index 00000000..911b30ff
--- /dev/null
+++ b/old/moon_gui/static/app/project/action/mapping/project.controller.unmap.js
@@ -0,0 +1,74 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('ProjectUnMapController', ProjectUnMapController);
+
+ ProjectUnMapController.$inject = ['$scope', '$translate', 'alertService', 'pdpService'];
+
+ function ProjectUnMapController($scope, $translate, alertService, pdpService) {
+
+ var unmap = this;
+
+ /*
+ *
+ */
+
+ unmap.project = $scope.project;
+ unmap.unMappingLoading = false;
+
+ unmap.unmap = unMapProject;
+
+ /*
+ *
+ */
+
+ function unMapProject() {
+
+
+ unmap.unMappingLoading = true;
+
+ var pdpName = unmap.project.pdp.name;
+
+ pdpService.unMap(unmap.project.pdp, unMapSuccess, unMapError);
+
+ function unMapSuccess(data) {
+
+ $translate('moon.project.unmap.success', { projectName: unmap.project.name, pdpName: pdpName })
+ .then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ unmap.unMappingLoading = false;
+
+ delete unmap.project.mapping;
+ delete unmap.project.pdp;
+
+ $scope.$emit('event:projectUnmappedSuccess', unmap.project);
+
+ }
+
+ function unMapError(reason) {
+
+ $translate('moon.project.unmap.error', { projectName: unmap.project.name, pdpName: pdpName })
+ .then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ unmap.unMappingLoading = false;
+
+ $scope.$emit('event:projectUnmappedError', unmap.project);
+
+ }
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/project/action/project-add.tpl.html b/old/moon_gui/static/app/project/action/project-add.tpl.html
new file mode 100755
index 00000000..a90dcfa1
--- /dev/null
+++ b/old/moon_gui/static/app/project/action/project-add.tpl.html
@@ -0,0 +1,89 @@
+<div ng-controller="ProjectAddController as add" class="modal" tabindex="-1" data-role="modalAddProject">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.project.add.title"></h4>
+ </div>
+
+ <div class="modal-body">
+
+ <form class="form-horizontal" role="form" name="add.form">
+
+ <div class="form-group" ng-class="{'has-error': add.form.name.$invalid && add.form.name.$dirty}">
+
+ <label for="name" class="col-sm-3 control-label" data-translate="moon.project.add.form.name">Name</label>
+
+ <div class="col-sm-6">
+
+ <input name="name" id="name" class="form-control" type="text" data-ng-model="add.project.project.name" required />
+
+ <div class="help-block" ng-show="add.form.name.$dirty && add.form.name.$invalid">
+ <small class="error" ng-show="add.form.name.$error.required" data-translate="moon.project.add.check.name.required">Name is required</small>
+ </div>
+
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="description" class="col-sm-3 control-label" data-translate="moon.project.add.form.description">Description</label>
+ <div class="col-sm-6">
+ <textarea id="description" name="description" class="form-control" data-ng-model="add.project.project.description"></textarea>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="enabled" class="col-sm-3 control-label" data-translate="moon.project.add.form.enabled">Enabled</label>
+ <div class="col-sm-6">
+ <div class="radio">
+ <input type="checkbox" id="enabled" name="enabled" class="js-switch" data-ng-model="add.project.project.enabled" ui-switch />
+ </div>
+ </div>
+ </div>
+
+ <div class="form-group" ng-class="{'has-error': add.form.domain.$invalid && add.form.domain.$dirty}">
+
+ <label for="domain" class="col-sm-3 control-label" data-translate="moon.project.add.form.domain">Domain</label>
+
+ <div class="col-sm-6">
+
+ <input name="domain" id="domain" type="text" class="form-control" data-ng-model="add.project.project.domain" required />
+
+ <div class="help-block" ng-show="add.form.domain.$dirty && add.form.domain.$invalid">
+ <small class="error" ng-show="add.form.domain.$error.required" data-translate="moon.project.add.check.domain.required">Domain is required</small>
+ </div>
+
+ </div>
+
+ </div>
+
+ </form>
+
+ </div>
+
+ <div class="modal-footer">
+
+ <div class="btn-toolbar" style="float: right;">
+
+ <a href="" ng-click="$hide()" class="btn btn-default">
+ <span data-translate="moon.project.add.action.cancel">Cancel</span>
+ </a>
+
+ <a href="" ng-disabled="add.loading" ng-click="add.create()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-save"></span>
+ <span data-translate="moon.project.add.action.create">Create</span>
+ </a>
+ <img ng-if="add.loading" src="assets/img/ajax-loader.gif" />
+
+ </div>
+
+ </div>
+
+ </div>
+
+ </div>
+
+</div>
diff --git a/old/moon_gui/static/app/project/action/project-delete.tpl.html b/old/moon_gui/static/app/project/action/project-delete.tpl.html
new file mode 100755
index 00000000..96b4f2e3
--- /dev/null
+++ b/old/moon_gui/static/app/project/action/project-delete.tpl.html
@@ -0,0 +1,45 @@
+<div ng-controller="ProjectDeleteController as del" class="modal" tabindex="-1" data-role="modalDeleteProject">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.project.remove.title"></h4>
+ </div>
+
+ <div class="modal-body">
+ <p><span data-translate="moon.project.remove.content.query" data-translate-values="{ projectName: del.project.name }"></span></p>
+
+ <p ng-if="del.loadingPDP"><img src="assets/img/ajax-loader.gif" /></p>
+
+ <div ng-if="!del.loadingPDP">
+ <p ng-if="!del.isProjectMapped()"><span data-translate="moon.project.remove.content.isNotMapped">This Project is not map with any PDP</span></p>
+ <p ng-if="del.isProjectMapped()">
+ <span data-translate="moon.project.remove.content.isMapped" data-translate-values="{ pdpName: del.project.pdp.name }"></span>
+ </p>
+ </div>
+
+ </div>
+
+ <div class="modal-footer">
+ <div class="btn-toolbar" style="float: right;">
+
+ <a href="" ng-click="$hide()" class="btn btn-default">
+ <span data-translate="moon.project.remove.action.cancel">Cancel</span>
+ </a>
+ <a href="" ng-disabled="del.loading || del.loadingPDP" ng-click="del.remove()" class="btn btn-warning">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span data-translate="moon.project.remove.action.delete">Delete</span>
+ </a>
+ <img ng-if="del.loading" src="assets/img/ajax-loader.gif" />
+
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/project/action/project-view.tpl.html b/old/moon_gui/static/app/project/action/project-view.tpl.html
new file mode 100755
index 00000000..3228c915
--- /dev/null
+++ b/old/moon_gui/static/app/project/action/project-view.tpl.html
@@ -0,0 +1,194 @@
+<div ng-controller="ProjectViewController as view" class="modal" tabindex="-1" data-role="modalViewProject">
+
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+
+ <div class="modal-header">
+ <button type="button" class="close" ng-click="$hide()">&times;</button>
+ <h4 class="modal-title" data-translate="moon.project.view.title" data-translate-values="{projectName: view.project.name}"></h4>
+ </div>
+ <div class="modal-body">
+ <dl class="dl-horizontal">
+ <dt>Id</dt>
+ <dd ng-bind="view.project.id"></dd>
+ <dt>Name</dt>
+ <dd ng-bind="view.project.name"></dd>
+ <dt>Is_domain</dt>
+ <dd ng-bind="view.project.is_domain"></dd>
+ <dt>Link</dt>
+ <dd ng-bind="view.project.links.self"></dd>
+ <dt>enabled</dt>
+ <dd ng-bind="view.project.enabled"></dd>
+ <dt>Parent id</dt>
+ <dd ng-bind="view.project.parent_id"></dd>
+ <dt>Domain id</dt>
+ <dd ng-bind="view.project.domain_id"></dd>
+ <dt>Description</dt>
+ <dd ng-bind="view.project.description"></dd>
+ </dl>
+ </div>
+
+ <!--<div class="modal-body">-->
+ <!---->
+ <!--&lt;!&ndash; objects &ndash;&gt;-->
+ <!---->
+ <!--<div class="row">-->
+ <!--<div class="col-md-12">-->
+ <!--<h1 class="pull-left" data-translate="moon.project.view.object.title">Objects</h1>-->
+ <!--</div>-->
+ <!--</div>-->
+ <!---->
+ <!--<div class="row top05">-->
+ <!--<div class="col-md-3"><label data-translate="moon.project.view.object.name">Name</label></div>-->
+ <!--<div class="col-md-7"><label data-translate="moon.project.view.object.description">Description</label></div>-->
+ <!--<div class="col-md-2"><label data-translate="moon.project.view.object.enabled">Enabled</label></div>-->
+ <!--</div>-->
+ <!---->
+ <!--<div class="row" ng-if="view.objectsLoading">-->
+ <!--<div class="col-md-12"><img src="assets/img/ajax-loader.gif" /> <em data-translate="moon.project.view.object.loading">Loading Objects</em></div>-->
+ <!--</div>-->
+ <!---->
+ <!--<div class="row" ng-if="!view.objectsLoading && !view.hasObjects()">-->
+ <!--<div class="col-md-12" data-translate="moon.project.view.object.notFound">Objects not found</div>-->
+ <!--</div>-->
+ <!---->
+ <!--<div class="row" ng-if="!view.objectsLoading && view.hasObjects()" ng-repeat="object in view.objects">-->
+ <!--<div class="col-md-3">{{object.name}}</div> -->
+ <!--<div class="col-md-7">{{object.description}}</div>-->
+ <!--<div class="col-md-2">-->
+ <!--<span ng-if="object.enabled" class="glyphicon glyphicon-ok"></span>-->
+ <!--</div>-->
+ <!--</div>-->
+ <!---->
+ <!--&lt;!&ndash; subjects &ndash;&gt;-->
+ <!---->
+ <!--<div class="row top10">-->
+ <!--<div class="col-md-12">-->
+ <!--<h1 class="pull-left" data-translate="moon.project.view.subject.title">Subjects</h1>-->
+ <!--</div>-->
+ <!--</div>-->
+ <!---->
+ <!--<div class="row top05">-->
+ <!--<div class="col-md-3"><label data-translate="moon.project.view.subject.name">Name</label></div>-->
+ <!--<div class="col-md-3"><label data-translate="moon.project.view.subject.domain">Domain</label></div>-->
+ <!--<div class="col-md-4"><label data-translate="moon.project.view.subject.mail">Mail</label></div>-->
+ <!--<div class="col-md-2"><label data-translate="moon.project.view.subject.enabled">Enabled</label></div>-->
+ <!--</div>-->
+ <!---->
+ <!--<div class="row">-->
+ <!--<div class="col-md-3">-->
+ <!--<ui-select ng-model="view.selectedSubject" on-select="view.resolveRoles($item); view.resolveGroups($item)">-->
+ <!--<ui-select-match placeholder="(None)">{{$select.selected.name}}</ui-select-match>-->
+ <!--<ui-select-choices repeat="subject in view.subjects">-->
+ <!--<div ng-value="subject">{{subject.name}}</div>-->
+ <!--</ui-select-choices>-->
+ <!--</ui-select>-->
+ <!--<img ng-if="view.subjectsLoading" src="assets/img/ajax-loader.gif" />-->
+ <!--</div> -->
+ <!--<div class="col-md-3">{{view.selectedSubject.domain}}</div>-->
+ <!--<div class="col-md-4">{{view.selectedSubject.mail}}</div>-->
+ <!--<div class="col-md-2">-->
+ <!--<div ng-if="view.selectedSubject != null">-->
+ <!--<span ng-if="view.selectedSubject.enabled" class="glyphicon glyphicon-ok"></span>-->
+ <!--</div>-->
+ <!--</div>-->
+ <!--</div>-->
+ <!---->
+ <!--&lt;!&ndash; roles &ndash;&gt;-->
+ <!---->
+ <!--<div ng-if="view.hasSelectedSubject()">-->
+ <!---->
+ <!--<div class="row top10">-->
+ <!--<div class="col-md-12">-->
+ <!--<h1 class="pull-left" data-translate="moon.project.view.role.title">Roles</h1>-->
+ <!--</div>-->
+ <!--</div>-->
+ <!---->
+ <!--<div class="row top05">-->
+ <!---->
+ <!--<div class="col-md-3"><label data-translate="moon.project.view.role.value">Value</label></div>-->
+ <!--<div class="col-md-5"><label data-translate="moon.project.view.role.description">Description</label></div>-->
+ <!--<div class="col-md-2"><label data-translate="moon.project.view.role.assigned">Assigned</label></div>-->
+ <!--<div class="col-md-2"><label data-translate="moon.project.view.role.enabled">Enabled</label></div>-->
+ <!---->
+ <!--</div>-->
+ <!---->
+ <!--<div class="row" ng-if="view.rolesLoading">-->
+ <!--<div class="col-md-12"><img src="assets/img/ajax-loader.gif" /> <em data-translate="moon.project.view.role.loading">Loading Roles</em></div>-->
+ <!--</div>-->
+ <!---->
+ <!--<div class="row" ng-if="!view.rolesLoading && !view.hasRoles()">-->
+ <!--<div class="col-md-12" data-translate="moon.project.view.role.notFound">Roles not found</div>-->
+ <!--</div>-->
+ <!---->
+ <!--<div class="row" ng-if="!view.rolesLoading && view.hasRoles()" ng-repeat="role in view.roles">-->
+ <!---->
+ <!--<div class="col-md-3" ng-bind="role.value"></div>-->
+ <!--<div class="col-md-5" ng-bind="role.description"></div>-->
+ <!--<div class="col-md-2">-->
+ <!--<span ng-if="view.isRoleAssigned(role)" class="glyphicon glyphicon-ok"></span>-->
+ <!--</div>-->
+ <!--<div class="col-md-2">-->
+ <!--<span ng-if="role.enabled" class="glyphicon glyphicon-ok"></span>-->
+ <!--</div>-->
+ <!---->
+ <!--</div>-->
+ <!---->
+ <!--</div>-->
+ <!---->
+ <!--&lt;!&ndash; groups &ndash;&gt;-->
+ <!---->
+ <!--<div ng-if="view.hasSelectedSubject()">-->
+ <!---->
+ <!--<div class="row top10">-->
+ <!--<div class="col-md-12">-->
+ <!--<h1 class="pull-left" data-translate="moon.project.view.group.title">Groups</h1>-->
+ <!--</div>-->
+ <!--</div>-->
+ <!---->
+ <!--<div class="row top05">-->
+ <!---->
+ <!--<div class="col-md-3"><label data-translate="moon.project.view.group.value">Value</label></div>-->
+ <!--<div class="col-md-5"><label data-translate="moon.project.view.group.description">Description</label></div>-->
+ <!--<div class="col-md-2"><label data-translate="moon.project.view.group.assigned">Assigned</label></div>-->
+ <!--<div class="col-md-2"><label data-translate="moon.project.view.group.enabled">Enabled</label></div>-->
+ <!---->
+ <!--</div>-->
+ <!---->
+ <!--<div class="row" ng-if="view.groupsLoading">-->
+ <!--<div class="col-md-12"><img src="assets/img/ajax-loader.gif" /> <em data-translate="moon.project.view.group.loading">Loading Groups</em></div>-->
+ <!--</div>-->
+ <!---->
+ <!--<div class="row" ng-if="!view.groupsLoading && !view.hasGroups()">-->
+ <!--<div class="col-md-12" data-translate="moon.project.view.group.notFound">Groups not found</div>-->
+ <!--</div>-->
+ <!---->
+ <!--<div class="row" ng-if="!view.groupsLoading && view.hasGroups()" ng-repeat="group in view.groups">-->
+ <!---->
+ <!--<div class="col-md-3">{{group.value}}</div>-->
+ <!--<div class="col-md-5">{{group.description}}</div>-->
+ <!--<div class="col-md-2">-->
+ <!--<span ng-if="view.isGroupAssigned(group)" class="glyphicon glyphicon-ok"></span>-->
+ <!--</div>-->
+ <!--<div class="col-md-2">-->
+ <!--<span ng-if="group.enabled" class="glyphicon glyphicon-ok"></span>-->
+ <!--</div>-->
+ <!---->
+ <!--</div>-->
+ <!---->
+ <!--</div>-->
+ <!---->
+ <!--</div>-->
+ <!---->
+ <div class="modal-footer top10">
+ <div class="btn-toolbar" style="float: right;">
+ <button ng-click="$hide()" class="btn btn-default" data-translate="moon.project.view.action.close">Close</button>
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+
+</div>
diff --git a/old/moon_gui/static/app/project/action/project.controller.add.js b/old/moon_gui/static/app/project/action/project.controller.add.js
new file mode 100755
index 00000000..4d12b75d
--- /dev/null
+++ b/old/moon_gui/static/app/project/action/project.controller.add.js
@@ -0,0 +1,78 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('ProjectAddController', ProjectAddController);
+
+ ProjectAddController.$inject = ['$scope', '$translate', 'alertService', 'formService', 'projectService', 'DEFAULT_CST'];
+
+ function ProjectAddController($scope, $translate, alertService, formService, projectService, DEFAULT_CST) {
+
+ var add = this;
+
+ /*
+ *
+ */
+
+ add.form = {};
+
+ add.loading = false;
+
+ //@todo: verify if enable argument is understood serrver-side
+ add.project = { project: {name: null, description: null, enabled: true, domain: DEFAULT_CST.DOMAIN.DEFAULT} };
+ add.create= createProject;
+
+ /*
+ * ---- create
+ */
+
+ function createProject() {
+
+ if(formService.isInvalid(add.form)) {
+
+ formService.checkFieldsValidity(add.form);
+
+ } else {
+
+ add.loading = true;
+
+ projectService.data.projects.create({}, add.project, createSuccess, createError);
+
+ }
+
+ function createSuccess(data) {
+
+ var created = data.project;
+ $translate('moon.project.add.success', { projectName: created.name }).then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ add.loading = false;
+
+ $scope.$emit('event:projectCreatedSuccess', created);
+
+ }
+
+ function createError(reason) {
+
+ $translate('moon.project.add.error', { projectName: add.project.project.name }).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ add.loading = false;
+
+ $scope.$emit('event:projectCreatedError', add.project);
+
+ }
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/project/action/project.controller.delete.js b/old/moon_gui/static/app/project/action/project.controller.delete.js
new file mode 100755
index 00000000..4f18f8e6
--- /dev/null
+++ b/old/moon_gui/static/app/project/action/project.controller.delete.js
@@ -0,0 +1,134 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('ProjectDeleteController', ProjectDeleteController);
+
+ ProjectDeleteController.$inject = ['$scope', '$translate', 'alertService', 'projectService', 'pdpService'];
+
+ function ProjectDeleteController($scope, $translate, alertService, projectService, pdpService) {
+
+ var del = this;
+
+ /*
+ *
+ */
+
+ del.project = $scope.project;
+ del.loading = false;
+ del.loadingPDP = true;
+ del.remove = deleteProjectAndMapping;
+ del.isProjectMapped = isProjectMapped;
+ del.pdps = [];
+
+ activate();
+
+ /**
+ *
+ */
+
+ function activate(){
+
+ resolvePDPs();
+
+ }
+
+ function resolvePDPs() {
+
+ pdpService.findAllWithCallBack(function(data){
+
+ del.pdps = data;
+
+ pdpService.mapPdpsToProject(del.project, del.pdps);
+
+ del.loadingPDP = false;
+
+ });
+
+ }
+
+ function isProjectMapped(){
+ return _.has(del.project, 'pdp');
+ }
+
+ /*
+ * ---- delete
+ */
+
+
+ function deleteProjectAndMapping() {
+
+ del.loading = true;
+
+
+ if(isProjectMapped() ) {
+
+ removeMapping(deleteProject);
+
+ }else{
+ deleteProject();
+ }
+
+ }
+
+ function removeMapping(callbackSuccess){
+
+
+ var pdpName = unmap.project.pdp.name;
+
+ pdpService.unMap(unmap.project, callbackSuccess, deleteMappingError);
+
+
+ function deleteMappingError(reason) {
+
+ $translate('moon.project.remove.mapping.remove.error', { pdpName: pdpName} ).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ del.loading = false;
+
+ $scope.$emit('event:projectDeletedError', del.project);
+
+ }
+
+
+ }
+
+ function deleteProject(){
+
+ projectService.data.projects.remove({project_id: del.project.id}, deleteSuccess, deleteError);
+
+ function deleteSuccess(data) {
+
+ $translate('moon.project.remove.success', { projectName: del.project.name }).then(function (translatedValue) {
+ alertService.alertSuccess(translatedValue);
+ });
+
+ del.loading = false;
+
+ $scope.$emit('event:projectDeletedSuccess', del.project);
+
+ }
+
+ function deleteError(reason) {
+
+ $translate('moon.project.remove.error', { projectName: del.project.name, errorCode: reason.data.error.code, message : reason.data.error.message } ).then(function (translatedValue) {
+ alertService.alertError(translatedValue);
+ });
+
+ del.loading = false;
+
+ $scope.$emit('event:projectDeletedError', del.project);
+
+ }
+
+ }
+ }
+
+})();
diff --git a/old/moon_gui/static/app/project/action/project.controller.view.js b/old/moon_gui/static/app/project/action/project.controller.view.js
new file mode 100755
index 00000000..fe98a507
--- /dev/null
+++ b/old/moon_gui/static/app/project/action/project.controller.view.js
@@ -0,0 +1,216 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('ProjectViewController', ProjectViewController);
+
+ ProjectViewController.$inject = ['$q', '$scope', '$translate', 'alertService', 'projectService'];
+
+ function ProjectViewController($q, $scope, $translate, alertService, projectService) {
+
+ var view = this;
+
+ /*
+ *
+ */
+
+ view.project = $scope.project;
+
+ // view.subjects = [];
+ // view.subjectsLoading = true;
+ // view.selectedSubject = null;
+ // view.hasSubjects = hasSubjects;
+ // view.hasSelectedSubject = hasSelectedSubject;
+ //
+ // view.objects = [];
+ // view.objectsLoading = true;
+ // view.hasObjects = hasObjects;
+ //
+ // view.roles = [];
+ // view.groups = [];
+ // view.roleAssignments = [];
+ // view.groupAssignments = [];
+ //
+ // view.hasRoles = hasRoles;
+ // view.hasGroups = hasGroups;
+ //
+ // view.isRoleAssigned = isRoleAssigned;
+ // view.isGroupAssigned = isGroupAssigned;
+ //
+ // view.resolveRoles = resolveRoles;
+ // view.resolveGroups = resolveGroups;
+ //
+ // //resolveObjects();
+ // //resolveSubjects();
+ //
+ // /*
+ // * ---- objects
+ // */
+ //
+ // function resolveObjects() {
+ //
+ // projectService.data.object.query({project_uuid: view.project.id}).$promise.then(resolveSuccess, resolveError);
+ //
+ // function resolveSuccess(data) {
+ //
+ // view.objectsLoading = false;
+ // view.objects = data.objects;
+ //
+ // }
+ //
+ // function resolveError(reason) {
+ //
+ // view.objectsLoading = false;
+ //
+ // $translate('moon.project.view.object.error').then(function (translatedValue) {
+ // alertService.alertError(translatedValue);
+ // });
+ //
+ // }
+ //
+ // }
+ //
+ // function hasObjects() {
+ // return view.objects.length > 0;
+ // }
+ //
+ // /*
+ // * ---- subjects
+ // */
+ //
+ // function resolveSubjects() {
+ //
+ // projectService.data.subject.query({project_uuid: view.project.uuid}).$promise.then(resolveSuccess, resolveError);
+ //
+ // function resolveSuccess(data) {
+ //
+ // view.subjectsLoading = false;
+ // view.subjects = data.users;
+ //
+ // }
+ //
+ // function resolveError(reason) {
+ //
+ // view.subjectsLoading = false;
+ //
+ // $translate('moon.project.view.subject.error').then(function (translatedValue) {
+ // alertService.alertError(translatedValue);
+ // });
+ //
+ // }
+ //
+ // }
+ //
+ // function hasSubjects() {
+ // return view.subjects.lenght > 0;
+ // }
+ //
+ // function hasSelectedSubject() {
+ // return view.selectedSubject != null;
+ // }
+ //
+ // /*
+ // * ---- role
+ // */
+ //
+ // function isRoleAssigned(role) {
+ //
+ // return _(view.roleAssignment.attributes).find(function(role_uuid) {
+ // return role.uuid === role_uuid;
+ // }).length !== 0;
+ //
+ // }
+ //
+ // function hasRoles() {
+ // return view.roles.length > 0;
+ // }
+ //
+ // function resolveRoles(subject) {
+ //
+ // view.rolesLoading = true;
+ //
+ // view.roles = [];
+ // view.roleAssignment = null;
+ //
+ // var promises = { roles: projectService.data.subjectRole.get({project_uuid: view.project.uuid, user_uuid: subject.uuid}).$promise,
+ // roleAssigment: projectService.data.roleAssigment.get({project_uuid: view.project.uuid, user_uuid: subject.uuid}).$promise };
+ //
+ // $q.all(promises).then(resolveSuccess, resolveError);
+ //
+ // function resolveSuccess(data) {
+ //
+ // view.rolesLoading = false;
+ // view.roles = data.roles.roles;
+ // view.roleAssignment = _.first(data.roleAssigment.role_assignments);
+ //
+ // }
+ //
+ // function resolveError(reason) {
+ //
+ // view.rolesLoading = false;
+ //
+ // $translate('moon.project.view.role.error').then(function (translatedValue) {
+ // alertService.alertError(translatedValue);
+ // });
+ //
+ // }
+ //
+ // }
+ //
+ // /*
+ // * ---- group
+ // */
+ //
+ // function isGroupAssigned(group) {
+ //
+ // return _($scope.view.groupAssignment.attributes).find(function(group_uuid) {
+ // return group.uuid === group_uuid;
+ // }).length !== 0;
+ //
+ // }
+ //
+ // function hasGroups() {
+ // return view.groups.length > 0;
+ // }
+ //
+ // function resolveGroups(subject) {
+ //
+ // view.groupsLoading = true;
+ //
+ // view.groups = [];
+ // view.groupAssignment = null;
+ //
+ // var promises = { groups: projectService.data.subjectGroup.get({project_uuid: view.project.uuid, user_uuid: subject.uuid}).$promise,
+ // groupAssignment: projectService.data.groupAssigment.get({project_uuid: view.project.uuid, user_uuid: subject.uuid}).$promise };
+ //
+ // $q.all(promises).then(resolveSuccess, resolveError);
+ //
+ // function resolveSuccess(data) {
+ //
+ // view.groupsLoading = false;
+ // view.groups = data.groups.groups;
+ // view.groupAssignment = _.first(data.groupAssignment.group_assignments);
+ //
+ // }
+ //
+ // function resolveError(reason) {
+ //
+ // view.groupsLoading = false;
+ //
+ // $translate('moon.project.view.group.error').then(function (translatedValue) {
+ // alertService.alertError(translatedValue);
+ // });
+ //
+ // }
+ //
+ // }
+ //
+ }
+
+})();
diff --git a/old/moon_gui/static/app/project/project-list.tpl.html b/old/moon_gui/static/app/project/project-list.tpl.html
new file mode 100755
index 00000000..82a3745e
--- /dev/null
+++ b/old/moon_gui/static/app/project/project-list.tpl.html
@@ -0,0 +1,157 @@
+
+<div class="container">
+
+ <div>
+ <form class="form-inline pull-right">
+ <div class="form-group">
+ <div>
+ <input id="searchProject" data-ng-model="list.search.query" type="text" class="form-control" placeholder="{{'moon.project.list.search.placeholder' | translate}}" />
+ </div>
+ </div>
+ <div class="form-group">
+ <div>
+ <button type="submit" class="btn btn-danger" data-ng-click="list.search.reset()" data-translate="moon.project.list.search.reset">Reset</button>
+ </div>
+ </div>
+ </form>
+ </div>
+
+ <div>&nbsp;</div>
+ <div>&nbsp;</div>
+ <div>&nbsp;</div>
+
+ <div class="row">
+
+ <div class="table-responsive" data-role="table">
+
+ <table class="table table-striped table-hover" ng-table="list.table">
+
+ <colgroup>
+ <col class="col-md-2" />
+ <col class="col-md-2" />
+ <col class="col-md-1" />
+ <col class="col-md-1" />
+ <col class="col-md-2" />
+ <col class="col-md-1" />
+ </colgroup>
+
+ <thead>
+
+ <tr>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('name', 'asc'), 'sort-desc': list.table.isSortBy('name', 'desc') }"
+ ng-click="list.table.sorting('name', list.table.isSortBy('name', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.project.list.table.name">Name</div>
+ </th>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('domain', 'asc'), 'sort-desc': list.table.isSortBy('domain', 'desc') }"
+ ng-click="list.table.sorting('domain', list.table.isSortBy('domain', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.project.list.table.domain">Domain</div>
+ </th>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('enabled', 'asc'), 'sort-desc': list.table.isSortBy('enabled', 'desc') }"
+ ng-click="list.table.sorting('enabled', list.table.isSortBy('enabled', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.project.list.table.enabled">Enabled</div>
+ </th>
+
+ <th class="customTables sortable"
+ ng-class="{ 'sort-asc': list.table.isSortBy('description', 'asc'), 'sort-desc': list.table.isSortBy('description', 'desc') }"
+ ng-click="list.table.sorting('description', list.table.isSortBy('description', 'asc') ? 'desc' : 'asc')">
+ <div data-translate="moon.project.list.table.description">Description</div>
+ </th>
+
+ <th class="customTables">
+ <div data-translate="moon.project.list.table.mapping">Mapping</div>
+ </th>
+
+ <th class="customTables">
+ <div data-translate="moon.project.list.action.title">Actions</div>
+ </th>
+
+ </tr>
+
+ </thead>
+
+ <tbody ng-if="!list.hasProjects()">
+ <tr>
+ <td colspan="2"><span data-translate="moon.project.list.table.notFound">There is no Projects</span></td>
+ </tr>
+ </tbody>
+
+ <tbody ng-if="list.hasProjects()">
+
+ <tr ng-repeat="aProject in $data | filter:list.search.find | orderBy:sort:reverse">
+ <td ng-bind="aProject.name"></td>
+ <td ng-bind="aProject.domain_id"></td>
+ <td>
+ <span ng-if="aProject.enabled" class="glyphicon glyphicon-ok"></span>
+ </td>
+ <td ng-bind="aProject.description"></td>
+ <td>
+
+ <div ng-if="list.loadingPDPs">
+ <img src="assets/img/ajax-loader.gif" /> <em data-translate="moon.project.list.table.loading.pdp">Loading PDP</em>
+ </div>
+
+ <div ng-if="!list.loadingPDPs">
+ <a href="" ng-if="!list.isProjectMapped(aProject)" ng-click="list.map.showModal(aProject)">
+ <span class="glyphicon glyphicon-link"></span> <em data-translate="moon.project.list.action.map">Map to a PDP</em>
+ </a>
+
+ <div ng-if="list.isProjectMapped(aProject)">
+
+ <span ng-bind="list.getMappedPDPName(aProject)"></span>
+ (<a href="" ng-click="list.unmap.showModal(aProject)">
+ <span class="glyphicon glyphicon-transfer"></span> <em data-translate="moon.project.list.action.unmap">Unmap to a PDP</em>
+ </a>)
+
+ </div>
+ </div>
+
+ </td>
+ <td>
+ <div class="dropdown">
+ <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
+ <span data-translate="moon.project.list.action.title">Actions</span>
+ <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu">
+ <li>
+ <a href="" ng-click="list.view.showModal(aProject)">
+ <span class="glyphicon glyphicon-eye-open"></span>
+ <span class="control-label" data-translate="moon.project.list.action.detail">Detail</span>
+ </a>
+ </li>
+ <li>
+ <a href="" ng-click="list.del.showModal(aProject)">
+ <span class="glyphicon glyphicon-trash"></span>
+ <span class="control-label" data-translate="moon.project.list.action.delete">Delete</span>
+ </a>
+ </li>
+ </ul>
+ </div>
+ </td>
+
+ </tr>
+
+ </tbody>
+
+ </table>
+
+ </div>
+
+ <div class="container">
+ <div class="form-inline form-group">
+ <a href="" ng-click="list.add.showModal()" class="btn btn-default">
+ <span class="glyphicon glyphicon-plus-sign"></span>
+ <span data-translate="moon.project.list.action.add">Add Project</span>
+ </a>
+ </div>
+ </div>
+
+ </div>
+
+</div> \ No newline at end of file
diff --git a/old/moon_gui/static/app/project/project.controller.list.js b/old/moon_gui/static/app/project/project.controller.list.js
new file mode 100755
index 00000000..b1cb2056
--- /dev/null
+++ b/old/moon_gui/static/app/project/project.controller.list.js
@@ -0,0 +1,310 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .controller('ProjectListController', ProjectListController);
+
+ ProjectListController.$inject = ['$rootScope', '$scope', '$filter', '$modal', 'ngTableParams', 'pdpService', 'projects'];
+
+ function ProjectListController($rootScope, $scope, $filter, $modal, ngTableParams, pdpService, projects) {
+
+ var list = this;
+
+ /*
+ *
+ */
+
+ list.projects = projects;
+ list.pdps = [];
+
+ list.getProjects = getProjects;
+ list.hasProjects = hasProjects;
+ list.isProjectMapped = isProjectMapped;
+
+ list.table = {};
+
+ list.addProject = addProject;
+ list.deleteProject = deleteProject;
+ list.refreshProjects = refreshProjects;
+
+ list.getMappedPDPName = getMappedPDPName;
+ list.getPdpFromProject = getPdpFromProject;
+
+ list.search = { query: '',
+ find: searchProject,
+ reset: searchReset };
+
+ list.add = { modal: $modal({ template: 'html/project/action/project-add.tpl.html', show: false }),
+ showModal: showAddModal };
+
+ list.del = { modal: $modal({ template: 'html/project/action/project-delete.tpl.html', show: false }),
+ showModal: showDeleteModal };
+
+ list.map = { modal: $modal({ template: 'html/project/action/mapping/project-map.tpl.html', show: false }),
+ showModal: showMapModal };
+
+ list.unmap = { modal: $modal({ template: 'html/project/action/mapping/project-unmap.tpl.html', show: false }),
+ showModal: showUnmapModal };
+
+ list.view = { modal: $modal({ template: 'html/project/action/project-view.tpl.html', show: false }),
+ showModal: showViewModal };
+
+ activate();
+
+
+ function activate(){
+
+ list.loadingPDPs = true;
+
+ newProjectsTable();
+
+ pdpService.findAllWithCallBack(function(data){
+
+ list.pdps = data;
+
+ pdpService.mapPdpsToProjects(list.projects, list.pdps);
+
+ list.loadingPDPs = false;
+
+ });
+ }
+
+
+ /*
+ * ---- events
+ */
+
+ var rootListeners = {
+
+ 'event:projectCreatedSuccess': $rootScope.$on('event:projectCreatedSuccess', projectCreatedSuccess),
+ 'event:projectCreatedError': $rootScope.$on('event:projectCreatedError', projectCreatedError),
+
+ 'event:projectDeletedSuccess': $rootScope.$on('event:projectDeletedSuccess', projectDeletedSuccess),
+ 'event:projectDeletedError': $rootScope.$on('event:projectDeletedError', projectDeletedError),
+
+ 'event:projectMappedSuccess': $rootScope.$on('event:projectMappedSuccess', projectMappedSuccess),
+ 'event:projectMappedError': $rootScope.$on('event:projectMappedError', projectMappedError),
+
+ 'event:projectUnmappedSuccess': $rootScope.$on('event:projectUnmappedSuccess', projectUnmappedSuccess),
+ 'event:projectUnmappedError': $rootScope.$on('event:projectUnmappedError', projectUnmappedError)
+
+ };
+
+ for (var unbind in rootListeners) {
+ $scope.$on('$destroy', rootListeners[unbind]);
+ }
+
+ /*
+ * ---- table
+ */
+
+ /**
+ * Get projects array from the Keystone Moon.
+ * @return an array containing projects JSON
+ */
+ function getProjects() {
+ return (list.projects) ? list.projects : [];
+ }
+
+ function hasProjects() {
+ return list.getProjects().length > 0;
+ }
+
+ function isProjectMapped(project){
+ return _.has(project, 'pdp');
+ }
+
+ /**
+ * Prerequisite, isProjectMapped should return true
+ * @param project
+ * @returns {*}
+ */
+ function getPdpFromProject(project){
+ return project.pdp;
+ }
+
+ function addProject(project) {
+ list.projects.push(project);
+ }
+
+ function deleteProject(project) {
+ list.projects = _.chain(list.projects).reject({id: project.id}).value();
+ }
+
+ function refreshProjects() {
+
+ list.table.total(list.projects.length);
+ list.table.reload();
+
+ }
+
+ function newProjectsTable() {
+
+ list.table = new ngTableParams({
+
+ page: 1, // show first page
+ count: 10, // count per page
+ sorting: {
+ name: 'asc' // initial sorting
+ }
+
+ }, {
+
+ total: function () { return list.getProjects().length; }, // length of data
+ getData: function($defer, params) {
+
+ var orderedData = params.sorting() ? $filter('orderBy')(list.getProjects(), params.orderBy()) : list.getProjects();
+ $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
+
+ },
+ $scope: { $data: {} }
+
+ });
+
+ return list.table;
+
+ }
+
+ /**
+ *
+ * @param project should have project.mapping.authz.pdp.name attribute
+ */
+ function getMappedPDPName(project) {
+ return _.has(project, 'pdp') ? project.pdp.name : 'error';
+ }
+
+ /*
+ * ---- search
+ */
+
+ function searchProject(project){
+ return (project.name.indexOf(list.search.query) !== -1 || project.description.indexOf(list.search.query) !== -1);
+ }
+
+ function searchReset() {
+ list.search.query = '';
+ }
+
+ /*
+ * ---- add
+ */
+
+ function showAddModal() {
+ list.add.modal.$promise.then(list.add.modal.show);
+ }
+
+ function projectCreatedSuccess(event, project) {
+
+ list.addProject(project);
+ list.refreshProjects();
+
+ list.add.modal.hide();
+
+ }
+
+ function projectCreatedError(event, project) {
+ list.add.modal.hide();
+ }
+
+ /*
+ * ---- delete
+ */
+
+ function showDeleteModal(project) {
+
+ list.del.modal.$scope.project = project;
+ list.del.modal.$promise.then(list.del.modal.show);
+
+ }
+
+ function projectDeletedSuccess(event, project) {
+
+ list.deleteProject(project);
+ list.refreshProjects();
+
+ list.del.modal.hide();
+
+ }
+
+ function projectDeletedError(event, project) {
+ list.del.modal.hide();
+ }
+
+ /*
+ * ---- map
+ */
+
+ function showMapModal(project) {
+
+ list.map.modal.$scope.project = project;
+ list.map.modal.$promise.then(list.map.modal.show);
+
+ }
+
+ function projectMappedSuccess(event, project) {
+
+ activate();
+ list.map.modal.hide();
+
+ }
+
+ function projectMappedError(event, project) {
+ list.map.modal.hide();
+ }
+
+ /*
+ * ---- unmap
+ */
+
+ function showUnmapModal(project) {
+
+ list.unmap.modal.$scope.project = project;
+ list.unmap.modal.$promise.then(list.unmap.modal.show);
+
+ }
+
+ function projectUnmappedSuccess(event, project) {
+
+
+ var index = _.findIndex(list.projects, function(aProject){
+ return project.id === aProject.id;
+ });
+
+ if(index === -1){
+ list.unmap.modal.hide();
+ return false;
+ }
+
+ list.projects[index] = project;
+
+ list.refreshProjects();
+
+ list.unmap.modal.hide();
+
+ }
+
+ function projectUnmappedError(event, project) {
+ list.unmap.modal.hide();
+ }
+
+
+ /*
+ * ---- view
+ */
+
+ function showViewModal(project) {
+
+ list.view.modal.$scope.project = project;
+ list.view.modal.$promise.then(list.view.modal.show);
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/services/gui/alert.service.js b/old/moon_gui/static/app/services/gui/alert.service.js
new file mode 100755
index 00000000..8435eab1
--- /dev/null
+++ b/old/moon_gui/static/app/services/gui/alert.service.js
@@ -0,0 +1,39 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('alertService', alertService);
+
+ alertService.$inject = [ 'toaster'];
+
+ function alertService( toaster) {
+
+ var service = {};
+
+ service.alertError = alertError;
+ service.alertSuccess = alertSuccess;
+ service.alertInfo = alertInfo;
+
+ return service;
+
+ function alertError(msg){
+ toaster.pop('error', null, msg, 5000);
+ }
+
+ function alertSuccess(msg){
+ toaster.pop('success', null, msg, 5000);
+ }
+
+ function alertInfo(msg){
+ toaster.pop('note', null, msg, 5000);
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/services/gui/browser.service.js b/old/moon_gui/static/app/services/gui/browser.service.js
new file mode 100755
index 00000000..88c693a8
--- /dev/null
+++ b/old/moon_gui/static/app/services/gui/browser.service.js
@@ -0,0 +1,47 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('browserService', browserService);
+
+ function browserService() {
+
+ var service = {};
+
+ service.sayWho = sayWho;
+
+ return service;
+
+ function sayWho() {
+
+ var ua= navigator.userAgent, tem,
+
+ M= ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
+
+ if(/trident/i.test(M[1])){
+ tem= /\brv[ :]+(\d+)/g.exec(ua) || [];
+ return 'IE '+(tem[1] || '');
+ }
+
+ if(M[1]=== 'Chrome'){
+ tem= ua.match(/\bOPR\/(\d+)/);
+ if(tem!= null){ return 'Opera '+tem[1];}
+ }
+
+ M= M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
+
+ if((tem= ua.match(/version\/(\d+)/i))!= null) M.splice(1, 1, tem[1]);
+
+ return M.join(' ');
+
+ };
+
+ };
+
+})();
diff --git a/old/moon_gui/static/app/services/gui/form.service.js b/old/moon_gui/static/app/services/gui/form.service.js
new file mode 100755
index 00000000..e436593c
--- /dev/null
+++ b/old/moon_gui/static/app/services/gui/form.service.js
@@ -0,0 +1,47 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('formService', formService);
+
+ function formService() {
+
+ var service = {};
+
+ service.isInvalid = isInvalid;
+ service.checkFieldsValidity = checkFieldsValidity;
+
+ return service;
+
+ function isInvalid(form) {
+ return form.$invalid;
+ }
+
+ function checkFieldsValidity(form) {
+
+ var validationErrorKeys = _.keys(form.$error);
+
+ _(validationErrorKeys).each(function(anErrorKey) {
+
+ var formFields = _.values(form.$error[anErrorKey]);
+
+ _(formFields).each(function(aFormField) {
+
+ aFormField.$dirty = true;
+ aFormField.$setValidity(anErrorKey, false);
+
+ });
+
+ });
+
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/services/gui/menu.service.js b/old/moon_gui/static/app/services/gui/menu.service.js
new file mode 100755
index 00000000..fd90a2fa
--- /dev/null
+++ b/old/moon_gui/static/app/services/gui/menu.service.js
@@ -0,0 +1,49 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('menuService', menuService);
+
+ menuService.$inject = ['$state'];
+
+ function menuService($state) {
+
+ var service = {};
+
+ service.isProjectTabActive = isProjectTabActive;
+ service.isPDPTabActive = isPDPTabActive;
+ service.isPolicyTabActive = isPolicyTabActive;
+ service.isLogsTabActive = isLogsTabActive;
+ service.isModelTabActive = isModelTabActive;
+
+ return service;
+
+ function isProjectTabActive() {
+ return $state.includes('moon.project');
+ }
+
+ function isPDPTabActive() {
+ return $state.includes('moon.pdp');
+ }
+
+ function isPolicyTabActive(){
+ return $state.includes('moon.policy');
+ }
+
+ function isLogsTabActive(){
+ return $state.includes('moon.logs');
+ }
+
+ function isModelTabActive(){
+ return $state.includes('moon.model');
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/services/gui/security.pipeline.service.js b/old/moon_gui/static/app/services/gui/security.pipeline.service.js
new file mode 100755
index 00000000..3831e487
--- /dev/null
+++ b/old/moon_gui/static/app/services/gui/security.pipeline.service.js
@@ -0,0 +1,29 @@
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('securityPipelineService', securityPipelineService);
+
+ securityPipelineService.$inject = ['SECURITY_PIPELINE_CST','policyService'];
+
+ function securityPipelineService(SECURITY_PIPELINE_CST, policyService) {
+ var service = {};
+
+ service.findAll = findAll;
+
+ return service;
+
+ function findAll(type){
+ switch(type){
+ case SECURITY_PIPELINE_CST.TYPE.POLICY :
+ return policyService.findAll();
+ default :
+ return policyService.findAll();
+ }
+
+ }
+ }
+
+})();
diff --git a/old/moon_gui/static/app/services/gui/util.service.js b/old/moon_gui/static/app/services/gui/util.service.js
new file mode 100755
index 00000000..7274244a
--- /dev/null
+++ b/old/moon_gui/static/app/services/gui/util.service.js
@@ -0,0 +1,66 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('utilService', utilService);
+
+ utilService.$inject = [];
+
+ function utilService() {
+
+ return {
+
+
+ /**
+ * Transforms an answer from server and return an array of objects instead the @param data
+
+ * @param data object : {
+ * 'typeOfTheRreturnedObject' : {
+ * 'idObject1' : {....},
+ * 'idObject2' : {....}
+ * }
+ * }
+ * @param typeOfObject
+ * @returns {Array}
+ */
+ transform : function(data, typeOfObject){
+
+ var result = [];
+
+ _.each(data[typeOfObject],function(item, key){
+ item.id = key;
+ result.push(item);
+ });
+
+ return result;
+ },
+
+ /**
+ * same as transform but with only one object
+ * @param data
+ * @param typeOfObject the first elem of the dictonnary
+ */
+ transformOne : function(data, typeOfObject){
+
+ var result = [];
+
+ _.each(data[typeOfObject], function (item, key) {
+ item.id = key;
+ result.push(item);
+ });
+
+ return result[0];
+
+ }
+
+ };
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/services/gui/version.service.js b/old/moon_gui/static/app/services/gui/version.service.js
new file mode 100755
index 00000000..5f9f2786
--- /dev/null
+++ b/old/moon_gui/static/app/services/gui/version.service.js
@@ -0,0 +1,27 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('versionService', versionService);
+
+ versionService.$inject = ['$resource'];
+
+ function versionService($resource) {
+
+ return {
+
+ version: $resource('version.json', {}, {
+ get: {method: 'GET', isArray: false}
+ })
+
+ };
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/services/moon/model/model.service.js b/old/moon_gui/static/app/services/moon/model/model.service.js
new file mode 100755
index 00000000..a676fc1a
--- /dev/null
+++ b/old/moon_gui/static/app/services/moon/model/model.service.js
@@ -0,0 +1,105 @@
+/**
+ * @author Samy Abdallah
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('modelService', modelService);
+
+ modelService.$inject = ['$resource', 'REST_URI', 'metaRuleService', 'utilService'];
+
+ function modelService($resource, REST_URI, metaRuleService, utilService) {
+
+ return {
+
+ data: $resource(REST_URI.MODELS + ':model_id', {}, {
+ get: {method: 'GET'},
+ query: {method: 'GET'},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'},
+ update: {method: 'PATCH'}
+ }),
+
+ findAll: function () {
+
+ return this.data.query().$promise.then(function (data) {
+
+ return utilService.transform(data, 'models');
+
+ });
+
+ },
+
+
+ findAllWithCallBack : function (callback){
+
+ return this.data.query().$promise.then(function (data) {
+
+ callback( utilService.transform(data, 'models'));
+
+ });
+
+ },
+
+ findOneWithCallback : function(modelId, callback){
+
+ return this.data.get({model_id: modelId}).$promise.then(function (data) {
+
+ callback(utilService.transformOne(data, 'models'));
+
+ });
+
+ },
+
+ findOneWithMetaRules: function (modelId) {
+
+ return this.data.get({model_id: modelId}).$promise.then(function (data) {
+
+ var res = utilService.transformOne(data, 'models');
+
+ if(res.meta_rules.length > 0){
+
+ metaRuleService.findSomeWithMetaData(res.meta_rules).then(function(metaRules){
+
+ res.meta_rules_values = metaRules;
+ res.id = modelId;
+
+ return res;
+
+ });
+
+ }else{
+
+ res.meta_rules_values = [];
+ res.id = modelId;
+
+ }
+
+ return res;
+
+ });
+
+ },
+
+ delete: function (model, callbackSuccess, callbackError ) {
+
+ delete model.meta_rules_values;
+
+ this.data.remove({model_id: model.id}, model, callbackSuccess, callbackError);
+
+ },
+
+ update: function (model, callbackSuccess, callbackError) {
+
+ delete model.meta_rules_values;
+ this.data.update({model_id: model.id}, model, callbackSuccess, callbackError);
+
+ }
+
+ }
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/services/moon/pdp.service.js b/old/moon_gui/static/app/services/moon/pdp.service.js
new file mode 100755
index 00000000..822f7414
--- /dev/null
+++ b/old/moon_gui/static/app/services/moon/pdp.service.js
@@ -0,0 +1,128 @@
+/**
+ * service allowing the client to interact with pdp
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('pdpService', pdpService);
+
+ pdpService.$inject = ['$q', '$resource','REST_URI', 'utilService'];
+
+ function pdpService($q, $resource, REST_URI, utilService) {
+
+ return {
+
+ data: {
+
+ pdp: $resource(REST_URI.PDP + ':pdp_id', {}, {
+ query: { method: 'GET', isArray: false },
+ get: { method: 'GET', isArray: false },
+ create: { method: 'POST' },
+ update: { method:'PATCH'},
+ remove: { method: 'DELETE' }
+ })
+
+ },
+
+ findAll: function() {
+
+ return this.data.pdp.query().$promise.then(function (data) {
+
+ return utilService.transform(data, 'pdps');
+
+ });
+
+ },
+
+ findAllWithCallBack : function (callback){
+
+ return this.data.pdp.query().$promise.then(function (data) {
+
+ callback( utilService.transform(data, 'pdps'));
+
+ });
+
+ },
+
+ findOne: function(id) {
+
+ return this.data.pdp.get({pdp_id: id}).$promise.then(function (data) {
+
+ return utilService.transformOne(data, 'pdps');
+
+ });
+
+ },
+
+ unMap: function(pdp, callbackSuccess, callbackError){
+
+ pdp.keystone_project_id = null;
+
+ if(_.has(pdp, 'project')){
+ delete pdp.project;
+ }
+
+ this.data.pdp.update({pdp_id: pdp.id}, pdp, callbackSuccess, callbackError);
+
+ },
+
+ map: function(pdp, projectId, callbackSuccess, callbackError){
+
+ pdp.keystone_project_id = projectId;
+
+ this.data.pdp.update({pdp_id: pdp.id}, pdp, callbackSuccess, callbackError);
+ },
+
+ update: function (pdp, callbackSuccess, callbackError) {
+
+ this.data.pdp.update({pdp_id: pdp.id}, pdp, callbackSuccess, callbackError);
+
+ },
+
+ mapPdpsToProjects : mapPdpsToProjects,
+
+ mapPdpsToProject : mapPdpsToProject
+
+ };
+
+ /**
+ * Will assign each project to it related pdp
+ * @param projects a list of Project, a new attribute pdp will be add, if the related pdp is existing in @param pdps
+ * @param pdps a list of Pdp
+ */
+ function mapPdpsToProjects(projects, pdps){
+
+ _.each(projects, function(project){
+
+ return mapPdpsToProject(project, pdps);
+
+ });
+ }
+
+ function mapPdpsToProject(project, pdps){
+
+ if (_.isNull(project.keystone_project_id)){
+ return false;
+ }
+
+ var index = _.findIndex(pdps, function(pdp){
+ return project.id === pdp.keystone_project_id;
+ });
+
+ if(index === -1){
+ return false;
+ }
+
+ project.pdp = pdps[index];
+
+ return true;
+ }
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/services/moon/policy/parameters/assignements.service.js b/old/moon_gui/static/app/services/moon/policy/parameters/assignements.service.js
new file mode 100755
index 00000000..ca138b45
--- /dev/null
+++ b/old/moon_gui/static/app/services/moon/policy/parameters/assignements.service.js
@@ -0,0 +1,133 @@
+/**
+ * @author Samy Abdallah
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('assignmentsService', assignmentsService);
+
+ assignmentsService.$inject = ['$resource', 'REST_URI', 'utilService'];
+
+ function assignmentsService($resource, REST_URI, utilService) {
+
+ var data = {
+
+ subject: {
+
+ policy: $resource(REST_URI.POLICIES + ':policy_id/subject_assignments/:perimeter_id/:category_id/:data_id', {}, {
+ get: {method: 'GET'},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'}
+ })
+
+ },
+
+
+ object: {
+
+ policy: $resource(REST_URI.POLICIES + ':policy_id/object_assignments/:perimeter_id/:category_id/:data_id', {}, {
+ get: {method: 'GET'},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'}
+ })
+
+ },
+
+ action: {
+
+ policy: $resource(REST_URI.POLICIES + ':policy_id/action_assignments/:perimeter_id/:category_id/:data_id', {}, {
+ get: {method: 'GET'},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'}
+ })
+
+ }
+
+ };
+
+ return {
+
+ subject : {
+
+ delete: function (policyId, perimeterId, categoryId, dataId, callbackSuccess, callbackError ) {
+
+ data.subject.policy.remove({policy_id: policyId, perimeter_id: perimeterId, category_id: categoryId, data_id: dataId}, {}, callbackSuccess, callbackError);
+
+ },
+
+ add:function (subject, policyId, callbackSuccess, callbackError ) {
+
+ data.subject.policy.create({policy_id: policyId}, subject, callbackSuccess, callbackError);
+
+ },
+
+ findAllFromPolicyWithCallback: function(policyId, callback){
+
+ data.subject.policy.get({policy_id: policyId}).$promise.then(function(data) {
+
+ callback(utilService.transform(data, 'subject_assignments'));
+
+ });
+
+ }
+ },
+
+ object : {
+
+
+ delete: function (policyId, perimeterId, categoryId, dataId, callbackSuccess, callbackError ) {
+
+ data.object.policy.remove({policy_id: policyId, perimeter_id: perimeterId, category_id: categoryId, data_id: dataId}, {}, callbackSuccess, callbackError);
+
+ },
+
+ add:function (object, policyId, callbackSuccess, callbackError ) {
+
+ data.object.policy.create({policy_id: policyId}, object, callbackSuccess, callbackError);
+
+ },
+
+ findAllFromPolicyWithCallback: function(policyId, callback){
+
+ data.object.policy.get({policy_id: policyId}).$promise.then(function(data) {
+
+ callback(utilService.transform(data, 'object_assignments'));
+
+ });
+
+ }
+ },
+
+ action : {
+
+ delete: function (policyId, perimeterId, categoryId, dataId, callbackSuccess, callbackError ) {
+
+ data.action.policy.remove({policy_id: policyId, perimeter_id: perimeterId, category_id: categoryId, data_id: dataId}, {}, callbackSuccess, callbackError);
+
+ },
+
+ add:function (action, policyId, callbackSuccess, callbackError ) {
+
+ data.action.policy.create({policy_id: policyId}, action, callbackSuccess, callbackError);
+
+ },
+
+ findAllFromPolicyWithCallback: function(policyId, callback){
+
+ data.action.policy.get({policy_id: policyId}).$promise.then(function(data) {
+
+ callback(utilService.transform(data, 'action_assignments'));
+
+ });
+
+ }
+ }
+
+ };
+
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/services/moon/policy/parameters/data.service.js b/old/moon_gui/static/app/services/moon/policy/parameters/data.service.js
new file mode 100755
index 00000000..1bbd3b24
--- /dev/null
+++ b/old/moon_gui/static/app/services/moon/policy/parameters/data.service.js
@@ -0,0 +1,249 @@
+/**
+ * @author Samy Abdallah
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('dataService', dataService);
+
+ dataService.$inject = ['$resource', 'REST_URI', 'utilService'];
+
+ function dataService($resource, REST_URI, utilService) {
+
+ var data = {
+
+ subject: {
+
+ policy: $resource(REST_URI.POLICIES + ':policy_id/subject_data/:subject_id/:category_id/:data_id', {}, {
+ get: {method: 'GET'},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'}
+ })
+
+ },
+
+ object: {
+
+ policy: $resource(REST_URI.POLICIES + ':policy_id/object_data/:object_id/:category_id/:data_id', {}, {
+ get: {method: 'GET', isArray: false},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'}
+ })
+
+ },
+
+ action: {
+
+ policy: $resource(REST_URI.POLICIES + ':policy_id/action_data/:action_id/:category_id/:data_id', {}, {
+ get: {method: 'GET', isArray: false},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'}
+ })
+
+ }
+
+ };
+
+ return {
+
+ subject : {
+
+ findAllFromPolicyWithCallback: function(policyId, callback){
+
+ data.subject.policy.get({policy_id: policyId}).$promise.then(function(data) {
+
+ callback(utilService.transform(data['subject_data'][0], 'data'));
+
+ });
+
+ },
+
+ findAllFromCategoriesWithCallback: function(policyId, categoryId, callback){
+
+ data.subject.policy.get({policy_id: policyId, category_id: categoryId}).$promise.then(function(data) {
+
+ if(data['subject_data'][0]) {
+
+ callback(utilService.transform(data['subject_data'][0], 'data'));
+
+ }else{
+
+ callback([])
+
+ }
+
+ });
+
+ },
+
+ delete: function (subject, policyId, categoryId, callbackSuccess, callbackError ) {
+
+ data.subject.policy.remove({policy_id: policyId, category_id: categoryId, data_id: subject.id}, subject, callbackSuccess, callbackError);
+
+ },
+
+ add: function (subject, policyId, categoryId, callbackSuccess, callbackError ) {
+
+ data.subject.policy.create({policy_id: policyId, category_id: categoryId}, subject, callbackSuccess, callbackError);
+
+ },
+
+ data: {
+
+ findOne: function(policyId, subjectId, dataId, callback){
+
+ data.subject.policy.get({policy_id: policyId, subject_id: subjectId, data_id : dataId}).$promise.then(function(data) {
+
+ if(data['subject_data'][0]){
+
+ callback(utilService.transformOne(data['subject_data'][0], 'data'));
+
+ }else{
+
+ callback({ });
+
+ }
+
+ });
+
+ }
+ }
+ },
+
+ object : {
+
+ findAllFromPolicyWithCallback: function(policyId, callback){
+
+ data.object.policy.get({policy_id: policyId}).$promise.then(function(data) {
+
+ callback(utilService.transform(data['object_data'][0], 'data'));
+
+ });
+
+ },
+
+ findAllFromCategoriesWithCallback: function(policyId, categoryId, callback){
+
+ data.object.policy.get({policy_id: policyId, category_id: categoryId}).$promise.then(function(data) {
+
+ if(data['object_data'][0]) {
+
+ callback(utilService.transform(data['object_data'][0], 'data'));
+
+ }else{
+
+ callback([])
+
+ }
+
+ });
+
+ },
+
+ delete: function (object, policyId, categoryId, callbackSuccess, callbackError ) {
+
+ data.object.policy.remove({policy_id: policyId, category_id: categoryId, data_id: object.id}, object, callbackSuccess, callbackError);
+
+ },
+
+ add:function (object, policyId, categoryId, callbackSuccess, callbackError ) {
+
+ data.object.policy.create({policy_id: policyId, category_id: categoryId}, object, callbackSuccess, callbackError);
+
+ },
+
+ data: {
+
+ findOne: function(policyId, objectId, dataId, callback){
+
+ data.object.policy.get({policy_id: policyId, object_id: objectId, data_id : dataId}).$promise.then(function(data) {
+
+ if(data['object_data'][0]){
+
+ callback(utilService.transformOne(data['object_data'][0], 'data'));
+
+ }else{
+
+ callback({ });
+
+ }
+
+ });
+
+ }
+ }
+ },
+
+ action : {
+
+ findAllFromPolicyWithCallback: function(policyId, callback){
+
+ data.action.policy.get({policy_id: policyId}).$promise.then(function(data) {
+
+ callback(utilService.transform(data['action_data'][0], 'data'));
+
+ });
+
+ },
+
+ findAllFromCategoriesWithCallback: function(policyId, categoryId, callback){
+
+ data.action.policy.get({policy_id: policyId, category_id: categoryId}).$promise.then(function(data) {
+
+ if(data['action_data'][0]) {
+
+ callback(utilService.transform(data['action_data'][0], 'data'));
+
+ }else{
+
+ callback([])
+
+ }
+
+ });
+
+ },
+
+ delete: function (action, policyId, categoryId, callbackSuccess, callbackError ) {
+
+ data.action.policy.remove({policy_id: policyId, category_id: categoryId, data_id: action.id}, action, callbackSuccess, callbackError);
+
+ },
+
+ add:function (action, policyId, categoryId, callbackSuccess, callbackError ) {
+
+ data.action.policy.create({policy_id: policyId, category_id: categoryId}, action, callbackSuccess, callbackError);
+
+ },
+
+
+ data: {
+
+ findOne: function(policyId, actionId, dataId, callback){
+
+ data.action.policy.get({policy_id: policyId, action_id: actionId, data_id : dataId}).$promise.then(function(data) {
+
+ if(data['action_data'][0]){
+
+ callback(utilService.transformOne(data['action_data'][0], 'data'));
+
+ }else{
+
+ callback({ });
+
+ }
+
+ });
+
+ }
+ }
+ }
+
+ };
+
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/services/moon/policy/parameters/perimeter.service.js b/old/moon_gui/static/app/services/moon/policy/parameters/perimeter.service.js
new file mode 100755
index 00000000..42e7288a
--- /dev/null
+++ b/old/moon_gui/static/app/services/moon/policy/parameters/perimeter.service.js
@@ -0,0 +1,460 @@
+/**
+ * @author Samy Abdallah
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('perimeterService', perimeterService);
+
+ perimeterService.$inject = ['$resource', 'REST_URI', '$q', 'utilService'];
+
+ function perimeterService($resource, REST_URI, $q, utilService) {
+
+ var data = {
+
+ subject: {
+
+ perimeter: $resource(REST_URI.PERIMETERS.subject + ':subject_id', {}, {
+ get: {method: 'GET', isArray: false},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'},
+ update: { method: 'PATCH' }
+ }),
+
+ policy: $resource(REST_URI.POLICIES + ':policy_id/subjects/:subject_id', {}, {
+ get: {method: 'GET'},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'},
+ update: { method: 'PATCH' }
+ })
+
+ },
+
+ object: {
+
+ perimeter: $resource(REST_URI.PERIMETERS.object + ':object_id', {}, {
+ get: {method: 'GET', isArray: false},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'},
+ update: { method: 'PATCH' }
+ }),
+
+ policy: $resource(REST_URI.POLICIES + ':policy_id/objects/:object_id', {}, {
+ get: {method: 'GET', isArray: false},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'},
+ update: { method: 'PATCH' }
+ })
+
+ },
+
+ action: {
+
+ perimeter: $resource(REST_URI.PERIMETERS.action + ':action_id', {}, {
+ get: {method: 'GET', isArray: false},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'},
+ update: { method: 'PATCH' }
+ }),
+
+ policy: $resource(REST_URI.POLICIES + ':policy_id/actions/:action_id', {}, {
+ get: {method: 'GET', isArray: false},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'},
+ update: { method: 'PATCH' }
+ })
+
+ }
+
+ };
+
+ return {
+
+ subject : {
+
+ findOne: function(subjectId, callback){
+
+ data.subject.perimeter.get({subject_id: subjectId}).$promise.then(function(data) {
+
+ callback(utilService.transformOne(data, 'subjects'));
+
+ });
+
+ },
+
+ findOneReturningPromise: function (subjectId){
+
+ return data.subject.perimeter.get({subject_id: subjectId}).$promise;
+
+ },
+
+ findSome: function(subjectListId) {
+
+ var _self = this;
+
+ if(subjectListId.length === 0){
+ return [];
+ }
+
+ var promises = _(subjectListId).map( function(subjectId) {
+
+ return _self.findOneReturningPromise(subjectId);
+
+ });
+
+ return $q.all(promises).then( function(result) {
+
+ return _(result).map( function(resource) {
+
+ return utilService.transformOne(resource, 'subjects');
+
+ });
+
+ });
+
+ },
+
+ unMapPerimeterFromPolicy: function(policyId, subjectId, callbackSuccess, callbackError ){
+
+ data.subject.policy.remove({policy_id: policyId, subject_id: subjectId}, {}, callbackSuccess, callbackError);
+
+ },
+
+ findAllFromPolicyWithCallback: function(policyId, callback){
+
+ data.subject.policy.get({policy_id: policyId}).$promise.then(function(data) {
+
+ callback(utilService.transform(data, 'subjects'));
+
+ });
+
+ },
+
+ findOneFromPolicyWithCallback: function(policyId, subjectId, callback){
+
+ data.subject.policy.get({policy_id: policyId, subject_id: subjectId}).$promise.then(function(data) {
+
+ callback(utilService.transformOne(data, 'subjects'));
+
+ });
+
+ },
+
+ findAll: function(){
+
+ return data.subject.perimeter.get().$promise.then(function(data) {
+
+ return utilService.transform(data, 'subjects');
+
+ });
+ },
+
+ findAllWithCallback: function(callback){
+
+ return data.subject.perimeter.get().$promise.then(function(data) {
+
+ callback(utilService.transform(data, 'subjects'));
+
+ });
+
+ },
+
+ delete: function (subject, callbackSuccess, callbackError ) {
+
+ data.subject.perimeter.remove({subject_id: subject.id}, subject, callbackSuccess, callbackError);
+
+ },
+
+ add: function (subject, callbackSuccess, callbackError ) {
+
+ data.subject.perimeter.create({}, subject, callbackSuccess, callbackError);
+
+ },
+
+ update: function(subject, callbackSuccess, callbackError){
+
+ data.subject.perimeter.update({subject_id: subject.id}, subject, callbackSuccess, callbackError);
+
+ }
+ },
+
+ object : {
+
+ findOne: function(objectId, callback){
+
+ data.object.perimeter.get({object_id: objectId}).$promise.then(function(data) {
+
+ callback(utilService.transformOne(data, 'objects'));
+
+ });
+
+ },
+
+ findOneReturningPromise: function(objectId){
+
+ return data.object.perimeter.get({object_id: objectId}).$promise;
+
+ },
+
+ findSome: function(objectListId) {
+
+
+ var _self = this;
+
+ if(objectListId.length === 0){
+ return [];
+ }
+
+ var promises = _(objectListId).map( function(objectId) {
+
+ return _self.findOneReturningPromise(objectId);
+
+ });
+
+ return $q.all(promises).then( function(result) {
+
+ return _(result).map( function(resource) {
+
+ return utilService.transformOne(resource, 'objects');
+
+ });
+
+ });
+
+ },
+
+ unMapPerimeterFromPolicy: function(policyId, objectId, callbackSuccess, callbackError ){
+
+ data.object.policy.remove({policy_id: policyId, object_id: objectId}, {}, callbackSuccess, callbackError);
+
+ },
+
+ findSomeWithCallback: function(objectListId, callback){
+
+ var _self = this;
+
+ if(objectListId.length === 0){
+ callback([]);
+ }
+
+ var promises = _(objectListId).map( function(subjectId) {
+
+ return _self.findOneReturningPromise(subjectId);
+
+ });
+
+ $q.all(promises).then( function(result) {
+
+ callback( _(result).map( function(resource) {
+
+ return utilService.transformOne(resource, 'objects');
+
+ }));
+
+ });
+
+ },
+
+ findAll : function(){
+
+ return data.object.perimeter.get().$promise.then(function(data) {
+
+ return utilService.transform(data, 'objects');
+
+ });
+
+ },
+
+ findAllFromPolicyWithCallback: function(policyId, callback){
+
+ data.object.policy.get({policy_id: policyId}).$promise.then(function(data) {
+
+ callback(utilService.transform(data, 'objects'));
+
+ });
+
+ },
+
+ findOneFromPolicyWithCallback: function(policyId, objectId, callback){
+
+
+ data.object.policy.get({policy_id: policyId, object_id: objectId}).$promise.then(function(data) {
+
+ callback(utilService.transformOne(data, 'objects'));
+
+ });
+
+ },
+
+ findAllWithCallback: function(callback){
+
+ return data.object.perimeter.get().$promise.then(function(data) {
+
+ callback(utilService.transform(data, 'objects'));
+
+ });
+
+ },
+
+ delete: function (object, callbackSuccess, callbackError ) {
+
+ data.object.perimeter.remove({object_id: object.id}, object, callbackSuccess, callbackError);
+
+ },
+
+ add:function (object, callbackSuccess, callbackError ) {
+
+ data.object.perimeter.create({}, object, callbackSuccess, callbackError);
+
+ },
+
+ update: function(object, callbackSuccess, callbackError){
+
+ data.object.perimeter.update({object_id: object.id}, object, callbackSuccess, callbackError);
+
+ }
+ },
+
+ action : {
+
+ findOne: function(actionId, callback){
+
+ data.action.perimeter.get({actionId: actionId}).$promise.then(function(data) {
+
+ callback(utilService.transformOne(data, 'actions'));
+
+ });
+
+ },
+
+ findOneReturningPromise: function(actionId){
+
+ return data.action.perimeter.get({actionId: actionId}).$promise;
+
+ },
+
+ findSome: function(actionListId) {
+
+ var _self = this;
+
+ if(actionListId.length === 0){
+ return [];
+ }
+
+ var promises = _(actionListId).map( function(actionId) {
+
+ return _self.findOneReturningPromise(actionId);
+
+ });
+
+ return $q.all(promises).then( function(result) {
+
+ return _(result).map( function(resource) {
+
+ return utilService.transformOne(resource, 'actions');
+
+ });
+
+ });
+
+ },
+
+ unMapPerimeterFromPolicy: function(policyId, actionId, callbackSuccess, callbackError){
+
+ data.action.policy.remove({policy_id: policyId, action_id: actionId}, {}, callbackSuccess, callbackError);
+
+ },
+
+ findSomeWithCallback: function(actionListId, callback){
+
+ var _self = this;
+
+ if(actionListId.length === 0){
+ callback([]);
+ }
+
+ var promises = _(actionListId).map( function(subjectId) {
+
+ return _self.findOneReturningPromise(subjectId);
+
+ });
+
+ $q.all(promises).then( function(result) {
+
+ callback( _(result).map( function(resource) {
+
+ return utilService.transformOne(resource, 'actions');
+
+ }));
+
+ });
+
+ },
+
+ findAll : function(){
+
+ return data.action.perimeter.get().$promise.then(function(data) {
+
+ return utilService.transform(data, 'actions');
+
+ });
+
+ },
+
+ findAllFromPolicyWithCallback: function(policyId, callback){
+
+ data.action.policy.get({policy_id: policyId}).$promise.then(function(data) {
+
+ callback(utilService.transform(data, 'actions'));
+
+ });
+
+ },
+
+ findOneFromPolicyWithCallback: function(policyId, actionId, callback){
+
+ data.action.policy.get({policy_id: policyId, action_id: actionId}).$promise.then(function(data) {
+
+ callback(utilService.transformOne(data, 'actions'));
+
+ });
+
+ },
+
+ findAllWithCallback: function(callback){
+
+ return data.action.perimeter.get().$promise.then(function(data) {
+
+ callback(utilService.transform(data, 'actions'));
+
+ });
+
+ },
+
+ delete: function (action, callbackSuccess, callbackError ) {
+
+ data.action.perimeter.remove({action_id: action.id}, action, callbackSuccess, callbackError);
+
+ },
+
+ add:function (action, callbackSuccess, callbackError ) {
+
+ data.action.perimeter.create({}, action, callbackSuccess, callbackError);
+
+ },
+
+ update: function(action, callbackSuccess, callbackError){
+
+ data.action.perimeter.update({action_id: action.id}, action, callbackSuccess, callbackError);
+
+ }
+ }
+
+ };
+
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/services/moon/policy/parameters/rule.service.js b/old/moon_gui/static/app/services/moon/policy/parameters/rule.service.js
new file mode 100644
index 00000000..b1a350ae
--- /dev/null
+++ b/old/moon_gui/static/app/services/moon/policy/parameters/rule.service.js
@@ -0,0 +1,49 @@
+/**
+ * @author Samy Abdallah
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('ruleService', ruleService);
+
+ ruleService.$inject = ['$resource', 'REST_URI', 'utilService'];
+
+ function ruleService($resource, REST_URI, utilService) {
+
+ return {
+
+ data: {
+
+ policy: $resource(REST_URI.POLICIES + ':policy_id/rules/:rule_id', {}, {
+ get: {method: 'GET'},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'}
+ })
+
+ },
+
+ findAllFromPolicyWithCallback: function(policyId, callback){
+
+ this.data.policy.get({policy_id: policyId}).$promise.then(function(data) {
+
+ console.log('ruleService - findAllFromPolicyWithCallback()');
+ console.log(data);
+
+ var array = data['rules'];
+
+ console.log(JSON.stringify(array));
+ callback(utilService.transform(array, 'rules'));
+
+ });
+
+ }
+
+
+ }
+
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/services/moon/policy/parameters/rules.service.js b/old/moon_gui/static/app/services/moon/policy/parameters/rules.service.js
new file mode 100755
index 00000000..76b24011
--- /dev/null
+++ b/old/moon_gui/static/app/services/moon/policy/parameters/rules.service.js
@@ -0,0 +1,56 @@
+/**
+ * @author Samy Abdallah
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('rulesService', rulesService);
+
+ rulesService.$inject = ['$resource', 'REST_URI', 'utilService'];
+
+ function rulesService($resource, REST_URI, utilService) {
+
+ return {
+
+ data: {
+
+ policy: $resource(REST_URI.POLICIES + ':policy_id/rules/:rule_id', {}, {
+ get: {method: 'GET'},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'}
+ })
+
+ },
+
+ add: function (rules, policyId, callbackSuccess, callbackError ) {
+
+ this.data.policy.create({policy_id: policyId}, rules, callbackSuccess, callbackError);
+
+ },
+
+ delete: function (ruleId, policyId, callbackSuccess, callbackError ) {
+
+ this.data.policy.remove({policy_id: policyId, rule_id: ruleId}, {}, callbackSuccess, callbackError);
+
+ },
+
+ findAllFromPolicyWithCallback: function(policyId, callback){
+
+ this.data.policy.get({policy_id: policyId}).$promise.then(function(data) {
+
+ callback(data.rules.rules);
+ //callback(utilService.transform(data['rules'], 'rules'));
+
+ });
+
+ }
+
+
+ }
+
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/services/moon/policy/policy.service.js b/old/moon_gui/static/app/services/moon/policy/policy.service.js
new file mode 100755
index 00000000..5ad31421
--- /dev/null
+++ b/old/moon_gui/static/app/services/moon/policy/policy.service.js
@@ -0,0 +1,108 @@
+/**
+ * Service providing access to the tenants
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('policyService', policyService);
+
+ policyService.$inject = ['$resource', 'REST_URI', 'utilService', '$q'];
+
+ function policyService($resource, REST_URI, utilService, $q) {
+
+ return {
+
+ data: {
+
+ policy: $resource(REST_URI.POLICIES + ':policy_id', {}, {
+ query: {method: 'GET'},
+ create: { method: 'POST' },
+ update: { method: 'PATCH' },
+ remove: { method: 'DELETE' }
+ })
+
+ },
+
+ findAll: function () {
+
+ return this.data.policy.query().$promise.then(function (data) {
+
+ return utilService.transform(data, 'policies');
+
+ });
+
+ },
+
+ findAllWithCallback: function (callback) {
+
+ return this.data.policy.query().$promise.then(function (data) {
+
+ callback(utilService.transform(data, 'policies'));
+
+ });
+
+ },
+
+ findOneReturningPromise: function(policyId){
+
+ return this.data.policy.get({policy_id: policyId}).$promise;
+
+ },
+
+ findSomeWithCallback: function(policyListId, callback){
+
+ var _self = this;
+
+ if(policyListId.length === 0){
+ callback([]);
+ }
+
+ var promises = _(policyListId).map( function(policyId) {
+
+ return _self.findOneReturningPromise(policyId);
+
+ });
+
+ $q.all(promises).then( function(result) {
+
+ callback( _(result).map( function(resource) {
+
+ return utilService.transformOne(resource, 'policies');
+
+ }));
+
+ });
+
+ },
+
+ findOne: function (policyId) {
+
+ return this.data.policy.get({policy_id: policyId}).$promise.then(function (data) {
+
+ return utilService.transformOne(data, 'policies');
+
+ });
+
+ },
+
+ update: function (policy, callbackSuccess, callbackError) {
+
+ this.data.policy.update({policy_id: policy.id}, policy, callbackSuccess, callbackError);
+
+ },
+
+ delete: function (policy, callbackSuccess, callbackError ) {
+
+ this.data.policy.remove({policy_id: policy.id}, policy, callbackSuccess, callbackError);
+
+ }
+
+ }
+ }
+
+})();
diff --git a/old/moon_gui/static/app/services/moon/rule/metadata.service.js b/old/moon_gui/static/app/services/moon/rule/metadata.service.js
new file mode 100755
index 00000000..8c68b2ef
--- /dev/null
+++ b/old/moon_gui/static/app/services/moon/rule/metadata.service.js
@@ -0,0 +1,354 @@
+/**
+ * @author Samy Abdallah
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('metaDataService', metaDataService);
+
+ metaDataService.$inject = ['$resource', 'REST_URI', '$q', 'utilService'];
+
+ function metaDataService($resource, REST_URI, $q, utilService) {
+
+ var data = {
+
+ subject: $resource(REST_URI.METADATA.subject + ':subject_id', {}, {
+ get: {method: 'GET', isArray: false},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'}
+ }),
+
+
+ object: $resource(REST_URI.METADATA.object + ':object_id', {}, {
+ get: {method: 'GET', isArray: false},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'}
+ }),
+
+ action: $resource(REST_URI.METADATA.action + ':action_id', {}, {
+ get: {method: 'GET', isArray: false},
+ create: {method: 'POST'},
+ remove: {method: 'DELETE'}
+ })
+
+ };
+
+ return {
+
+ subject : {
+
+ findOne: function(subjectId, callback){
+
+ data.subject.get({subject_id: subjectId}).$promise.then(function(data) {
+
+ callback(utilService.transformOne(data, 'subject_categories'));
+
+ });
+
+ },
+
+ findOneReturningPromise: function (subjectId){
+
+ return data.subject.get({subject_id: subjectId}).$promise;
+
+ },
+
+ findSome: function(subjectListId) {
+
+ var _self = this;
+
+ if(subjectListId.length === 0){
+ return [];
+ }
+
+ var promises = _(subjectListId).map( function(subjectId) {
+
+ return _self.findOneReturningPromise(subjectId);
+
+ });
+
+ return $q.all(promises).then( function(result) {
+
+ return _(result).map( function(resource) {
+
+ return utilService.transformOne(resource, 'subject_categories');
+
+ });
+
+ });
+
+ },
+
+ findSomeWithCallback: function(subjectListId, callback){
+
+ var _self = this;
+
+ if(subjectListId.length === 0){
+ callback([]);
+ }
+
+ var promises = _(subjectListId).map( function(subjectId) {
+
+ return _self.findOneReturningPromise(subjectId);
+
+ });
+
+ $q.all(promises).then( function(result) {
+
+ callback( _(result).map( function(resource) {
+
+ return utilService.transformOne(resource, 'subject_categories');
+
+ }));
+
+ });
+
+ },
+
+ findAll: function(){
+
+ return data.subject.get().$promise.then(function(data) {
+
+ return utilService.transform(data, 'subject_categories');
+
+ });
+ },
+
+ findAllWithCallback: function(callback){
+
+ return data.subject.get().$promise.then(function(data) {
+
+ callback(utilService.transform(data, 'subject_categories'));
+
+ });
+
+ },
+
+ delete: function (subject, callbackSuccess, callbackError ) {
+
+ data.subject.remove({subject_id: subject.id}, subject, callbackSuccess, callbackError);
+
+ },
+
+ add: function (subject, callbackSuccess, callbackError ) {
+
+ data.subject.create({}, subject, callbackSuccess, callbackError);
+
+ }
+ },
+
+ object : {
+
+ findOne: function(objectId, callback){
+
+ data.object.get({object_id: objectId}).$promise.then(function(data) {
+
+ callback(utilService.transformOne(data, 'object_categories'));
+
+ })
+
+ },
+
+ findOneReturningPromise: function(objectId){
+
+ return data.object.get({object_id: objectId}).$promise;
+
+ },
+
+ findSome: function(objectListId) {
+
+
+ var _self = this;
+
+ if(objectListId.length === 0){
+ return [];
+ }
+
+ var promises = _(objectListId).map( function(objectId) {
+
+ return _self.findOneReturningPromise(objectId);
+
+ });
+
+ return $q.all(promises).then( function(result) {
+
+ return _(result).map( function(resource) {
+
+ return utilService.transformOne(resource, 'object_categories');
+
+ });
+
+ });
+
+ },
+
+ findSomeWithCallback: function(objectListId, callback){
+
+ var _self = this;
+
+ if(objectListId.length === 0){
+ callback([]);
+ }
+
+ var promises = _(objectListId).map( function(objectId) {
+
+ return _self.findOneReturningPromise(objectId);
+
+ });
+
+ $q.all(promises).then( function(result) {
+
+ callback( _(result).map( function(resource) {
+
+ return utilService.transformOne(resource, 'object_categories');
+
+ }));
+
+ });
+
+ },
+
+ findAll : function(){
+
+ return data.object.get().$promise.then(function(data) {
+
+ return utilService.transform(data, 'object_categories');
+
+ });
+
+ },
+
+ findAllWithCallback: function(callback){
+
+ return data.object.get().$promise.then(function(data) {
+
+ callback(utilService.transform(data, 'object_categories'));
+
+ });
+
+ },
+
+ delete: function (object, callbackSuccess, callbackError ) {
+
+ data.object.remove({object_id: object.id}, object, callbackSuccess, callbackError);
+
+ },
+
+ add:function (object, callbackSuccess, callbackError ) {
+
+ data.object.create({}, object, callbackSuccess, callbackError);
+
+ }
+ },
+
+ action : {
+
+ findOne: function(actionId, callback){
+
+ data.action.get({action_id: actionId}).$promise.then(function(data) {
+
+ callback(utilService.transformOne(data, 'action_categories'));
+
+ })
+
+ },
+
+ findOneReturningPromise: function(actionId){
+
+ return data.action.get({action_id: actionId}).$promise;
+
+ },
+
+ findSome: function(actionListId) {
+
+ var _self = this;
+
+ if(actionListId.length === 0){
+ return [];
+ }
+
+ var promises = _(actionListId).map( function(actionId) {
+
+ return _self.findOneReturningPromise(actionId);
+
+ });
+
+ return $q.all(promises).then( function(result) {
+
+ return _(result).map( function(resource) {
+
+ return utilService.transformOne(resource, 'action_categories');
+
+ });
+
+ });
+
+ },
+
+ findSomeWithCallback: function(actionListId, callback){
+
+ var _self = this;
+
+ if(actionListId.length === 0){
+ callback([]);
+ }
+
+ var promises = _(actionListId).map( function(actionId) {
+
+ return _self.findOneReturningPromise(actionId);
+
+ });
+
+ $q.all(promises).then( function(result) {
+
+ callback( _(result).map( function(resource) {
+
+ return utilService.transformOne(resource, 'action_categories');
+
+ }));
+
+ });
+
+ },
+
+ findAll : function(){
+
+ return data.action.get().$promise.then(function(data) {
+
+ return utilService.transform(data, 'action_categories');
+
+ });
+
+ },
+
+ findAllWithCallback: function(callback){
+
+ return data.action.get().$promise.then(function(data) {
+
+ callback(utilService.transform(data, 'action_categories'));
+
+ });
+
+ },
+
+ delete: function (action, callbackSuccess, callbackError ) {
+
+ data.action.remove({action_id: action.id}, action, callbackSuccess, callbackError);
+
+ },
+
+ add:function (action, callbackSuccess, callbackError ) {
+
+ data.action.create({}, action, callbackSuccess, callbackError);
+
+ }
+ }
+
+ };
+
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/services/moon/rule/metarule.service.js b/old/moon_gui/static/app/services/moon/rule/metarule.service.js
new file mode 100755
index 00000000..05167849
--- /dev/null
+++ b/old/moon_gui/static/app/services/moon/rule/metarule.service.js
@@ -0,0 +1,208 @@
+/**
+ * @author Samy Abdallah
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('metaRuleService', metaRuleService);
+
+ metaRuleService.$inject = ['$resource', 'REST_URI', 'metaDataService', '$q', 'utilService'];
+
+ function metaRuleService($resource, REST_URI, metaDataService, $q, utilService) {
+
+ return {
+
+ data: $resource(REST_URI.METARULES + ':metarule_id', {}, {
+ query: {method: 'GET' },
+ get: {method: 'GET', isArray: false},
+ update: {method: 'PATCH'},
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ }),
+
+
+ findAll: function () {
+
+ return this.data.query().$promise.then(function (data) {
+
+ return utilService.transform(data, 'meta_rules');
+
+ });
+
+ },
+
+ findAllWithCallback : function (callback) {
+
+ this.data.query().$promise.then(function (data) {
+
+ callback(utilService.transform(data, 'meta_rules'));
+
+ });
+
+ },
+
+ findSomeWithMetaData : function(metaRuleListId){
+
+ var _self = this;
+
+ if(metaRuleListId.length === 0){
+ return [];
+ }
+
+ var promises = _(metaRuleListId).map(function(objectId) {
+
+ return _self.findOneReturningPromise(objectId);
+
+ });
+
+ return $q.all(promises).then(function(result) {
+
+ return _(result).map(function(resource) {
+
+ var metaRule = utilService.transformOne(resource, 'meta_rules');
+
+ metaRule = _self.findMetaDataFromMetaRule(metaRule);
+
+ return metaRule;
+
+ });
+
+ });
+
+
+ },
+
+ findSomeWithCallback : function(metaRuleListId, callback){
+
+ var _self = this;
+
+ if(metaRuleListId.length === 0){
+ return callback([]);
+ }
+
+ var promises = _(metaRuleListId).map(function(objectId) {
+
+ return _self.findOneReturningPromise(objectId);
+
+ });
+
+ return $q.all(promises).then(function(result) {
+
+ callback( _(result).map(function(resource) {
+
+ return utilService.transformOne(resource, 'meta_rules');
+
+ }));
+
+ });
+
+
+ },
+
+ findOneReturningPromise: function(metaRuleId){
+
+ return this.data.get({metarule_id: metaRuleId}).$promise;
+
+ },
+
+ findOne : function(metaRuleId){
+
+ return this.data.get({metarule_id: metaRuleId}).$promise.then(function(data) {
+
+ return utilService.transformOne(data, 'meta_rules');
+
+ });
+
+ },
+
+ findOneWithCallback: function(metaRuleId, callback){
+
+ this.data.get({metarule_id: metaRuleId}).$promise.then(function(data) {
+
+ callback(utilService.transformOne(data, 'meta_rules'));
+
+ });
+
+ },
+
+ findOneWithMetaData: function(metaRuleId){
+
+ var _self = this;
+
+ return this.data.get({metarule_id: metaRuleId}).$promise.then(function(data) {
+
+ var metaRule = utilService.transformOne(data, 'meta_rules');
+
+ metaRule = _self.findMetaDataFromMetaRule(metaRule);
+
+ return metaRule;
+
+ });
+
+ },
+
+ findMetaDataFromMetaRule : function (metaRule){
+
+ if(metaRule.subject_categories.length > 0){
+
+ metaDataService.subject.findSome(metaRule.subject_categories).then(function(categories){
+ metaRule.subject_categories_values = categories;
+ });
+
+ }else{
+
+ metaRule.subject_categories_values = [];
+
+ }
+
+ if(metaRule.object_categories.length > 0){
+
+ metaDataService.object.findSome(metaRule.object_categories).then(function(categories){
+ metaRule.object_categories_values = categories;
+ });
+
+ }else{
+
+ metaRule.object_categories_values = [];
+
+ }
+
+ if(metaRule.action_categories.length > 0){
+
+ metaDataService.action.findSome(metaRule.action_categories).then(function(categories){
+ metaRule.action_categories_values = categories;
+ });
+
+
+ }else{
+
+ metaRule.action_categories_values = [];
+
+ }
+
+ return metaRule;
+ },
+
+ delete: function (metaRule, callbackSuccess, callbackError ) {
+
+ this.data.remove({metarule_id: metaRule.id}, metaRule, callbackSuccess, callbackError);
+
+ },
+
+ update: function(metaRule, callbackSuccess, callbackError){
+
+ delete metaRule.subject_categories_values;
+ delete metaRule.object_categories_values;
+ delete metaRule.action_categories_values;
+
+ this.data.update({metarule_id: metaRule.id}, metaRule, callbackSuccess, callbackError);
+
+ }
+ };
+
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/services/partner/authentication.service.js b/old/moon_gui/static/app/services/partner/authentication.service.js
new file mode 100755
index 00000000..b6d3f36d
--- /dev/null
+++ b/old/moon_gui/static/app/services/partner/authentication.service.js
@@ -0,0 +1,106 @@
+/**
+ * @author Samy Abdallah
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('authenticationService', authenticationService);
+
+ authenticationService.$inject = ['$resource', 'REST_URI', '$sessionStorage', '$http', '$location'];
+
+ function authenticationService($resource, REST_URI, $sessionStorage, $http, $location) {
+
+ return {
+ data: $resource(REST_URI.KEYSTONE + 'auth/tokens', {}, {
+ login: { method: 'POST' ,
+ /**
+ * Transform Response is needed to add headers into the response object
+ * @param data
+ * @param headersGetter
+ * @returns {{}}
+ */
+ transformResponse : function (data, headersGetter) {
+ var response = {};
+ response.data = angular.fromJson(data) ;
+ response.headers = headersGetter();
+ return response;
+ }
+ },
+ logout: { method: 'DELETE' }
+ }),
+
+ /**
+ *
+ * @param credentials object : {username : '', password : ''}
+ * @param callbackSuccess
+ * @param callbackError
+ * @constructor
+ */
+ Login : function (credentials, callbackSuccess, callbackError){
+ var requestData = {
+ auth:{
+ identity:{
+ methods:[
+ 'password'
+ ],
+ password:{
+ user:{
+ name: credentials.username,
+ domain:{
+ name:'Default'
+ },
+ password: credentials.password
+ }
+ }
+ },
+ scope: {
+ project: {
+ name:'admin',
+ domain:{
+ name:'Default'
+ }
+ }
+ }
+ }
+ };
+ this.data.login({}, requestData, function (response){
+ $sessionStorage.currentUser = response.data;
+ $sessionStorage.currentUser.connectionToken = response.headers['x-subject-token'];
+ SetTokenHeader(response.headers['x-subject-token']);
+ callbackSuccess();
+ }, callbackError);
+ },
+ IsConnected : IsConnected,
+ SetTokenHeader : SetTokenHeader,
+ GetTokenHeader : GetTokenHeader,
+ GetUser : GetUser,
+ Logout : Logout
+ };
+
+ function IsConnected(){
+ return _.has($sessionStorage, 'currentUser');
+ }
+
+ function Logout(){
+ delete $sessionStorage.currentUser;
+ $http.defaults.headers.common['X-Auth-Token'] = '';
+ $location.path('/');
+ }
+
+ function GetUser(){
+ return $sessionStorage.currentUser;
+ }
+
+ function GetTokenHeader(){
+ return $sessionStorage.currentUser.connectionToken;
+ }
+
+ function SetTokenHeader(token){
+ $http.defaults.headers.common['X-Auth-Token'] = token;
+ }
+ }
+})(); \ No newline at end of file
diff --git a/old/moon_gui/static/app/services/partner/nova.service.js b/old/moon_gui/static/app/services/partner/nova.service.js
new file mode 100755
index 00000000..38e2a0fc
--- /dev/null
+++ b/old/moon_gui/static/app/services/partner/nova.service.js
@@ -0,0 +1,35 @@
+/**
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('novaService', novaService);
+
+ novaService.$inject = ['$resource'];
+
+ function novaService($resource) {
+
+ return {
+
+ data: {
+
+ image: $resource('./pip/nova/images', {}, {
+ query: {method: 'GET', isArray: false}
+ }),
+
+ flavor: $resource('./pip/nova/flavors', {}, {
+ query: {method: 'GET', isArray: false}
+ })
+
+ }
+
+ };
+
+ }
+
+})();
diff --git a/old/moon_gui/static/app/services/partner/project.service.js b/old/moon_gui/static/app/services/partner/project.service.js
new file mode 100755
index 00000000..4ec27f2e
--- /dev/null
+++ b/old/moon_gui/static/app/services/partner/project.service.js
@@ -0,0 +1,60 @@
+/**
+ * Service providing access to the tenants
+ * @author arnaud marhin<arnaud.marhin@orange.com>
+ */
+
+(function() {
+
+ 'use strict';
+
+ angular
+ .module('moon')
+ .factory('projectService', projectService);
+
+ projectService.$inject = [ '$resource' , 'REST_URI' ];
+
+ function projectService( $resource, REST_URI) {
+
+ return {
+
+ data: {
+
+ projects: $resource(REST_URI.KEYSTONE + 'projects/:project_id', {}, {
+ query: {method: 'GET', isArray: false},
+ get: { method: 'GET', isArray: false },
+ create: { method: 'POST' },
+ remove: { method: 'DELETE' }
+ })
+
+ },
+
+ findOne: function(project_id, callback){
+
+ return this.data.projects.get({project_id: project_id}).$promise.then(function(data) {
+
+ callback(data.project);
+
+ });
+
+ },
+
+ findAll: function() {
+
+ return this.data.projects.query().$promise.then(function(listProjects) {
+
+ var result = [];
+
+ _.each(listProjects['projects'], function(item){
+ result.push(item);
+ });
+
+ return result;
+ });
+
+ }
+
+ };
+
+ }
+
+})();
diff --git a/old/moon_gui/static/favicon.ico b/old/moon_gui/static/favicon.ico
new file mode 100755
index 00000000..a7910bf5
--- /dev/null
+++ b/old/moon_gui/static/favicon.ico
Binary files differ
diff --git a/old/moon_gui/static/i18n/en.json b/old/moon_gui/static/i18n/en.json
new file mode 100755
index 00000000..4dc7cea5
--- /dev/null
+++ b/old/moon_gui/static/i18n/en.json
@@ -0,0 +1,1357 @@
+{
+ "moon": {
+ "global": {
+ "applicationName": "Moon",
+ "404": "Page not found",
+ "error": "A global error occurs: {{stacktrace}}"
+ },
+ "compatibility": {
+ "label": "Browsers compatibility",
+ "title": "Existing browsers compatibility",
+ "content": "Moon is compliant with : <ul><li>Internet Explorer 9 or +</li><li><a href=\"http://www.mozilla.org/fr/firefox/\">Firefox</a> up-to-date</li><li><a href=\"http://chrome.google.com\">Chrome</a> up-to-date</li></ul>",
+ "close": "Close"
+ },
+ "menu": {
+ "project": "Project",
+ "pdp": "PDP",
+ "logs": "Log",
+ "policy": "Policy",
+ "model":"Model"
+ },
+ "login":{
+ "title" : "Login",
+ "titlePage" : "Login page",
+ "username" : "Username",
+ "password" : "Password",
+ "login": "Login",
+ "check": {
+ "username": {
+ "required": "Username is required"
+ },
+ "password": {
+ "required": "Password is required"
+ }
+ },
+ "error" :"Unable to login into Keystone, error code : {{errorCode}}",
+ "success" : "Connection established. Welcome to Moon GUI, \"Moon is uppon cloud\""
+ },
+ "logout": {
+ "title": "Logout",
+ "success" : "Successfully logout"
+ },
+ "dashboard":{
+ "content" : "Moon:Software-Defined Security Framework"
+ },
+ "policy":{
+ "title": "Policies",
+ "list" : {
+ "search": {
+ "placeholder": "Search Policies",
+ "reset": "Reset"
+ },
+ "table" : {
+ "name":"Name",
+ "genre" : "Genre",
+ "description": "Description",
+ "loading": {
+ "category" : "Loading Category"
+ },
+ "notFound": "There is no Policy"
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Add Policy",
+ "detail": "Consut",
+ "edit": "Edit",
+ "map" : "Map Policy to PDP",
+ "unmap" : "Unmap",
+ "delete": "Delete"
+ }
+ },
+ "unmap": {
+ "title": "Unmap Policy to PDP",
+ "content": "Are you sure you want to unmap PDP `{{pdpName}}` / Policy `{{policyName}}` ?",
+ "action": {
+ "unmap": "Unmap",
+ "cancel": "Cancel"
+ },
+ "error": "Unable to unmap PDP `{{pdpName}}` /Policy `{{policyName}}`",
+ "success": "PDP `{{pdpName}}` / Policy `{{policyName}}` successfully unmapped"
+ },
+ "map":{
+ "title": "Map a Policy to PDP `{{pdpName}}`",
+ "form" :{
+ "list": "List of Policies"
+ },
+ "action": {
+ "create": "Map Policy",
+ "cancel": "Cancel",
+ "new": "Create a Policy",
+ "list": "Map an existing Policy",
+ "map": "Map the selected Policy",
+ "delete" : "Delete the selected Policy"
+ },
+ "check": {
+ "policy":{
+ "required" : "Policy is required"
+ }
+ },
+ "error": "Unable to map Policy `{{policyName}}` to the PDP `{{pdpName}}`",
+ "success": "Policy `{{policyName}}` successfully mapped to the PDP `{{pdpName}}`"
+ },
+ "remove": {
+ "title": "Delete Policy",
+ "content": {
+ "query": "Are you sure you want to delete `{{policyName}}` Policy ?"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Policy `{{policyName}}`, error code : {{errorCode}}, message : \"{{message}}\"",
+ "success": "Model `{{policyName}}` successfully deleted"
+ },
+ "edit" : {
+ "title": "Policy `{{policyName}}` configuration",
+ "update" : "- update",
+ "show": {
+ "open": "( show )",
+ "close": "( close )"
+ },
+ "basic" : {
+ "title" : "Basic Information",
+ "form": {
+ "id": "Id",
+ "name": "Name",
+ "genre": "Genre",
+ "model": "Model",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Update"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ },
+ "genre": {
+ "required": "Genre is required"
+ }
+ },
+ "error": "Unable to update Policy `{{policyName}}`",
+ "success": "Policy `{{policyName}}` successfully updated"
+ },
+ "perimeter": {
+ "title" : "Perimeters"
+ },
+ "data": {
+ "title" : "Data"
+ },
+ "rules" : {
+ "title" : "Rules"
+ },
+ "assignments": {
+ "title" : "Assignments"
+ }
+ },
+ "add":{
+ "title": "Add new Policy",
+ "form": {
+ "name": "Name",
+ "genre": "Genre",
+ "model": "Models",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Create Policy",
+ "cancel": "Cancel"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ },
+ "genre": {
+ "required": "Genre is required"
+ },
+ "model": {
+ "required": "Model is required"
+ }
+ },
+ "error": "Unable to create Policy `{{policyName}}`",
+ "success": "Policy `{{policyName}}` successfully created"
+ },
+ "perimeter": {
+ "subject" : {
+ "title" : "List of associated Subjects",
+ "delete": {
+ "error" : "Unable to delete {{subjectName}} Subject, reason : {{reason}}",
+ "success": "Subject `{{subjectName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add a Subject"
+ },
+ "notFound": "There is no Subject"
+ },
+ "object" : {
+ "title" : "List of associated Objects",
+ "delete": {
+ "error" : "Unable to delete {{objectName}} Object, reason : {{reason}}",
+ "success": "Object `{{objectName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add an Object"
+ },
+ "notFound": "There is no Object"
+ },
+ "action" : {
+ "title" : "List of associated Actions",
+ "delete": {
+ "error" : "Unable to delete {{actionName}} Action, reason : {{reason}}",
+ "success": "Action `{{actionName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add an Action"
+ },
+ "notFound": "There is no Action"
+ },
+ "update":{
+ "error": "Unable to update Perimeter `{{perimeterName}}`",
+ "success": "Perimeter `{{perimeterName}}` successfully updated"
+ },
+ "table": {
+ "id" : "Id",
+ "name" : "Name",
+ "description" : "Description",
+ "email" : "Email",
+ "partner":{
+ "id" : "Partner Id"
+ },
+ "action": {
+ "title": "Actions",
+ "delete": "Delete",
+ "update": "Update",
+ "unmap": "Unmap"
+ }
+ },
+ "edit": {
+ "name" : "Name",
+ "description" : "Description",
+ "partnerId": "Partner Id",
+ "policies": "Policy list",
+ "email": "E-mail",
+ "selectedPolicies": "Selected Policies",
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "action": {
+ "list": "Add an existing Perimeter",
+ "new": "Add a new Perimeter",
+ "create": "Add Perimeter",
+ "add": "Add the selected Perimeter",
+ "delete" : "Delete the selected Perimeter"
+ },
+ "create":{
+ "error": "Unable to create `{{name}}`",
+ "success": "`{{name}}` successfully created"
+ },
+ "delete":{
+ "error": "Unable to delete `{{name}}`",
+ "success": "`{{name}}` successfully deleted"
+ }
+ }
+ },
+ "data": {
+ "subject" : {
+ "title" : "List of associated Data Subjects",
+ "delete": {
+ "error" : "Unable to delete {{subjectName}} Subject, reason : {{reason}}",
+ "success": "Subject `{{subjectName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add a Data Subject"
+ },
+ "notFound": "There is no Data Subject"
+ },
+ "object" : {
+ "title" : "List of associated Data Objects",
+ "delete": {
+ "error" : "Unable to delete {{objectName}} Object, reason : {{reason}}",
+ "success": "Object `{{objectName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add a Data Object"
+ },
+ "notFound": "There is no Data Object"
+ },
+ "action" : {
+ "title" : "List of associated Actions",
+ "delete": {
+ "error" : "Unable to delete {{actionName}} Action, reason : {{reason}}",
+ "success": "Action `{{actionName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add a Data Action"
+ },
+ "notFound": "There is no Data Action"
+ },
+ "table": {
+ "category" : {
+ "id" : "Category Id",
+ "name" : "Category Name"
+ },
+ "name" : "Name",
+ "description" : "Description",
+ "action": {
+ "title": "Actions",
+ "delete": "Delete",
+ "update": "Update"
+ },
+ "loading": {
+ "category" : "Loading Category"
+ }
+ },
+ "edit": {
+ "name" : "Name",
+ "description" : "Description",
+ "categories" : "Category List",
+ "policies": "Policy List",
+ "check": {
+ "name": {
+ "required": "Name is required"
+ },
+ "category":{
+ "required": "A Category is required"
+ },
+ "policy":{
+ "required": "A Policy is required"
+ }
+ },
+ "action": {
+ "list": "Add an existing Data",
+ "new": "Create a new Data",
+ "create": "Create Data",
+ "add": "Add the selected Data",
+ "delete": "Delete Data"
+ },
+ "create":{
+ "error": "Unable to create `{{name}}`",
+ "success": "`{{name}}` successfully created"
+ },
+ "delete":{
+ "error": "Unable to delete `{{name}}`",
+ "success": "`{{name}}` successfully deleted"
+ }
+ }
+ },
+ "rules": {
+ "title": "Rules",
+ "list": {
+ "search": {
+ "placeholder": "Search Rule",
+ "reset": "Reset"
+ },
+ "table": {
+ "id" : "Id",
+ "metaRule": "Meta Rule",
+ "description": "Description",
+ "enabled": "Enabled",
+ "rule": "Rule",
+ "instructions": "Instruction",
+ "notFound": "There is no Rule",
+ "loading": {
+ "metaRule" : "Loading Meta Rule"
+ },
+ "action":{
+ "title": "Actions",
+ "delete": "Delete"
+ }
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Add Rule",
+ "detail": "Consult",
+ "edit": "Edit",
+ "delete": "Delete"
+ },
+ "error": "Unable to retrieve Rule"
+ },
+ "edit": {
+ "title" : "List of associated Rules",
+ "action" : {
+ "create": "Create Rules",
+ "delete": {
+ "error" : "Unable to delete {{rulesName}} Action, reason : {{reason}}",
+ "success": "Rules `{{rulesName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add a Rule",
+ "policies": "Select a policy",
+ "instructions": "Instruction",
+ "metarules" : "Select one of the associated MetaRules",
+ "categories":{
+ "subject": "Select {{number}} Subject(s)",
+ "object": "Select {{number}} Object(s)",
+ "action": "Select {{number}} Action(s)"
+ },
+ "selectedSubjects": "Selected Subject(s)",
+ "selectedObjects": "Selected Object(s)",
+ "selectedActions": "Selected Action(s)",
+ "details":{
+ "show": "Details",
+ "close": "Close"
+ },
+ "check":{
+ "policy":{
+ "required": "A Policy is required"
+ },
+ "instructions":{
+ "required": "An Instruction in JSON format is required"
+ },
+ "metarules":{
+ "required": "A MetaRule is required"
+ },
+ "subject":{
+ "required": "{{number}} Subject(s) are required"
+ },
+ "object":{
+ "required": "{{number}} Object(s) are required"
+ },
+ "action":{
+ "required": "{{number}} Action(s) are required"
+ }
+ },
+ "create":{
+ "error": "Unable to create Rules",
+ "success": "Rules successfully created"
+ },
+ "delete":{
+ "error": "Unable to delete Rules, reason : `{{reason}}`",
+ "success": "Rules successfully deleted"
+ }
+ },
+ "notFound": "There is no Rules"
+ }
+ }
+ },
+ "assignments": {
+ "subject" : {
+ "title" : "List of associated Assignments Subjects",
+ "delete": {
+ "error" : "Unable to delete Assignments, reason : {{reason}}",
+ "success": "Assignments successfully deleted"
+ },
+ "add": {
+ "title": "Add a Assignments Subject"
+ },
+ "notFound": "There is no Assignments Subject"
+ },
+ "object" : {
+ "title" : "List of associated Assignments Objects",
+ "delete": {
+ "error" : "Unable to delete Assignments, reason : {{reason}}",
+ "success": "Assignments successfully deleted"
+ },
+ "add": {
+ "title": "Add a Assignments Object"
+ },
+ "notFound": "There is no Assignments Object"
+ },
+ "action" : {
+ "title" : "List of associated Assignments Actions",
+ "delete": {
+ "error" : "Unable to delete Assignments, reason : {{reason}}",
+ "success": "Assignments successfully deleted"
+ },
+ "add": {
+ "title": "Add a Assignments Action"
+ },
+ "notFound": "There is no Assignments Action"
+ },
+ "table": {
+ "action": {
+ "title": "Actions",
+ "delete": "Delete",
+ "update": "Update"
+ },
+ "perimeter": {
+ "name" : "Perimeter name"
+ },
+ "data": {
+ "name": "Data name"
+ },
+ "category": {
+ "name" : "Category name"
+ },
+ "loading": {
+ "category" : "Loading Category",
+ "perimeter": "Loading Perimeter",
+ "data": "Loading Data"
+ }
+ },
+ "edit": {
+ "policies": "Select a Policy",
+ "categories": "Select a Category",
+ "perimeters": "Select a Perimeter",
+ "data": "Select a Data",
+ "selectedData" : "Selected Data",
+ "check": {
+ "policy":{
+ "required": "A Policy is required"
+ },
+ "category":{
+ "required": "A Category is required"
+ },
+ "perimeter":{
+ "required": "A Perimeter is required"
+ },
+ "data":{
+ "required": "A Data is required"
+ }
+ },
+ "action": {
+ "list": "Add an existing Assignments",
+ "new": "Add a new Assignments",
+ "create": "Create Assignments",
+ "map": "Add the selected Assignments",
+ "delete": "Delete Assignments"
+ },
+ "create":{
+ "error": "Unable to create Assignments",
+ "success": "Assignments successfully created"
+ },
+ "delete":{
+ "error": "Unable to delete Assignments, reason : `{{reason}}`",
+ "success": "Assignments successfully deleted"
+ }
+ }
+ }
+ },
+ "model":{
+ "title": "Models",
+ "list": {
+ "search": {
+ "placeholder": "Search Model",
+ "reset": "Reset"
+ },
+ "table":{
+ "name":"Name",
+ "description": "Description",
+ "metaRules":{
+ "number" : "Number of Meta Rules"
+ },
+ "notFound": "There is no Models"
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Add Model",
+ "detail": "Consult",
+ "edit": "Edit",
+ "delete": "Delete"
+ },
+ "error": "Unable to retrieve Models"
+ },
+ "edit" : {
+ "title": "Model `{{modelName}}` configuration",
+ "update" : "- update",
+ "basic" : {
+ "title" : "Basic Information",
+ "form": {
+ "id": "Id",
+ "name": "Name",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Update"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "error": "Unable to update Model `{{modelName}}`",
+ "success": "Model `{{modelName}}` successfully updated"
+ },
+ "metarules": {
+ "title" : "Meta Rules"
+ }
+ },
+ "view": {
+ "title": "Model `{{modelName}}` details",
+ "name": "Name",
+ "id": "Id",
+ "description": "Description",
+ "action": {
+ "close": "Close"
+ }
+ },
+ "remove": {
+ "title": "Delete Model",
+ "content": {
+ "query": "Are you sure you want to delete `{{modelName}}` Model ?"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Model `{{modelName}}`, error code : {{errorCode}}, message : \"{{message}}\"",
+ "success": "Model `{{modelName}}` successfully deleted"
+ },
+ "metarules": {
+ "title": "List of Meta Rules",
+ "table": {
+ "name":"Name",
+ "description": "Description",
+ "metadata": {
+ "subject": {
+ "number": "Number of Subject Categories"
+ },
+ "object" : {
+ "number": "Number of Object Categories"
+ },
+ "action": {
+ "number": "Number of Action Categories"
+ }
+ },
+ "notFound": "There is no Meta Rules"
+ },
+ "edit" : {
+ "title" : "Meta Rule `{{metaRuleName}}` configuration",
+ "update": "- update",
+ "basic": {
+ "title": "Basic Information",
+ "form": {
+ "id": "Id",
+ "name": "Name",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Update"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "error": "Unable to update Meta Rule `{{metaRuleName}}`",
+ "success": "Meta Rule `{{metaRuleName}}` successfully updated"
+ }
+ },
+ "update":{
+ "error": "Unable to update Meta Rule `{{metaRuleName}}`",
+ "success": "Meta Rule `{{metaRuleName}}` successfully updated"
+ },
+ "action": {
+ "title": "Actions",
+ "edit": "Edit",
+ "remove": "Remove",
+ "settings" : "Settings",
+ "add": "Add",
+ "detail": {
+ "open": "Consult",
+ "close": "Close"
+ }
+ },
+ "add": {
+ "title": "Add new Meta Rule",
+ "form": {
+ "name": "Nom",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Add Meta Rule",
+ "cancel": "Cancel"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "error": "Unable to create Meta Rule `{{metaRuleName}}`",
+ "success": "Meta Rule `{{metaRuleName}}` successfully created"
+ },
+ "map":{
+ "title": "Add a Meta Rule",
+ "form" :{
+ "list": "List of Meta Rules"
+ },
+ "action": {
+ "create": "Add a new Meta Rule",
+ "cancel": "Cancel",
+ "new": "Add a Meta Rule",
+ "list": "Add an existing Meta Rule",
+ "add": "Add the selected Meta Rule",
+ "delete" : "Delete the selected Meta Rule"
+ },
+ "error": "Unable to map Model `{{modelName}}` to the Meta Rule `{{metaRuleName}}`",
+ "success": "Model `{{modelName}}` successfully mapped to the Meta Rule `{{metaRuleName}}`"
+ },
+ "unmap": {
+ "title": "Remove Meta Rule to Model",
+ "content": "Are you sure you want to remove Model `{{modelName}}` / Meta Rule `{{metaRuleName}}` ?",
+ "action": {
+ "unmap": "Remove",
+ "cancel": "Cancel"
+ },
+ "error": "Unable to remove Model `{{modelName}}` / Meta Rule `{{metaRuleName}}`",
+ "success": "Model `{{modelName}}` / Meta Rule `{{metaRuleName}}` successfully removed"
+ },
+ "delete":{
+ "error": "Unable to delete Meta Rule `{{metaRuleName}}`",
+ "success": "Meta Rule `{{metaRuleName}}` successfully deleted"
+ }
+ },
+ "metadata": {
+ "subject" : {
+ "title" : "List of associated Subject Categories",
+ "delete": {
+ "error" : "Unable to delete {{subjectName}} Subject, reason : {{reason}}",
+ "success": "Subject `{{subjectName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add a Subject Category"
+ },
+ "notFound": "There is no Subject"
+ },
+ "object" : {
+ "title" : "List of associated Object Categories",
+ "delete": {
+ "error" : "Unable to delete {{objectName}} Object, reason : {{reason}}",
+ "success": "Object `{{objectName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add an Object Category"
+ },
+ "notFound": "There is no Object"
+ },
+ "action" : {
+ "title" : "List of associated Action Categories",
+ "remove": "Remove",
+ "delete": {
+ "error" : "Unable to delete {{actionName}} Action, reason : {{reason}}",
+ "success": "Action `{{actionName}}` successfully deleted"
+ },
+ "add": {
+ "title": "Add an Action Category"
+ },
+ "notFound": "There is no Action"
+ },
+ "table": {
+ "id" : "Id",
+ "name" : "Name",
+ "description" : "Description",
+ "action": {
+ "title": "Actions",
+ "delete": "Delete",
+ "update": "Update"
+ }
+ },
+ "edit": {
+ "name" : "Name",
+ "description" : "Description",
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "action": {
+ "list": "Add an existing Category",
+ "new": "Add a new Category",
+ "create": "Add Category",
+ "add": "Add the selected Category",
+ "delete": "Delete"
+ },
+ "create":{
+ "error": "Unable to create Category `{{name}}`",
+ "success": "Category `{{name}}` successfully created"
+ },
+ "delete":{
+ "error": "Unable to delete Category `{{name}}`",
+ "success": "Category `{{name}}` successfully deleted"
+ }
+ }
+ },
+ "add":{
+ "title": "Add new Model",
+ "form": {
+ "name": "Name",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Create Model",
+ "cancel": "Cancel"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "error": "Unable to create Model `{{modelName}}`",
+ "success": "Model `{{modelName}}` successfully created"
+ }
+ },
+ "project": {
+ "title": "Projects",
+ "list": {
+ "search": {
+ "placeholder": "Search Projects",
+ "reset": "Reset"
+ },
+ "table": {
+ "name": "Name",
+ "domain": "Domain",
+ "managed": "Managed",
+ "enabled": "Enabled",
+ "description": "Description",
+ "mapping": "PDP",
+ "loading": {
+ "project": "Loading Projects",
+ "pdp": "Loading PDP"
+ },
+ "notFound": "There is no Projects"
+ },
+ "action": {
+ "title": "Actions",
+ "detail": "Consult",
+ "delete": "Delete",
+ "add": "Add Project",
+ "map": "Map to a PDP",
+ "unmap": "Unmap"
+ },
+ "error": "Unable to retrieve Projects"
+ },
+ "view": {
+ "title": "Project `{{projectName}}` details",
+ "action": {
+ "close": "Close"
+ },
+ "subject": {
+ "title": "Subjects",
+ "name": "Name",
+ "mail": "Email",
+ "domain": "Domain",
+ "enabled": "Enabled",
+ "error": "Unable to retrieve Subjects"
+ },
+ "object": {
+ "title": "Objects",
+ "category": "Category",
+ "description": "Description",
+ "enabled": "Enabled",
+ "name": "Name",
+ "error": "Unable to retrieve Objects",
+ "loading": "Loading Objects",
+ "notFound": "There is no Objects"
+ },
+ "role": {
+ "title": "Roles",
+ "category": "Category",
+ "value": "Value",
+ "description": "Description",
+ "assigned": "Assigned",
+ "enabled": "Enabled",
+ "error": "Unable to retrieve Roles",
+ "loading": "Loading Roles",
+ "notFound": "There is no Roles"
+ },
+ "roleAssignment": {
+ "title": "Role Assignments",
+ "category": "Category",
+ "attributes": "Attributes",
+ "description": "Description",
+ "error": "Unable to retrieve Role Assignments",
+ "loading": "Loading Role Assignments",
+ "notFound": "There is no Role Assignments"
+ },
+ "group": {
+ "title": "Groups",
+ "category": "Category",
+ "value": "Value",
+ "description": "Description",
+ "assigned": "Assigned",
+ "enabled": "Enabled",
+ "error": "Unable to retrieve Groups",
+ "loading": "Loading Groups",
+ "notFound": "There is no Groups"
+ },
+ "groupAssignment": {
+ "title": "Group Assignments",
+ "category": "Category",
+ "attributes": "Attributes",
+ "description": "Description",
+ "error": "Unable to retrieve Group Assignments",
+ "loading": "Loading Group Assignments",
+ "notFound": "There is no Group Assignments"
+ }
+ },
+ "add": {
+ "title": "Add new Project",
+ "form": {
+ "name": "Name",
+ "description": "Description",
+ "enabled": "Enabled",
+ "domain": "Domain"
+ },
+ "action": {
+ "create": "Create Project",
+ "cancel": "Cancel"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ },
+ "domain": {
+ "required": "Domain is required"
+ }
+ },
+ "error": "Unable to create Project `{{projectName}}`",
+ "success": "Project `{{projectName}}` successfully created"
+ },
+ "remove": {
+ "title": "Delete Project",
+ "content": {
+ "query": "Are you sure you want to delete `{{projectName}}` Project ?",
+ "isNotMapped": "This Project is not mapped to any PDP",
+ "isMapped": "This project is mapped to `{{pdpName}}` PDP, delete this Project, will remove the mapping."
+ },
+ "mapping":{
+ "remove":{
+ "error": "Unable to remove mapping with Pdp : `{{pdpName}}`"
+ }
+ },
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Project `{{projectName}}`, error code : {{errorCode}}, message : \"{{message}}\"",
+ "success": "Project `{{projectName}}` successfully deleted"
+ },
+ "map": {
+ "title": "Map Project `{{projectName}}` to a PDP",
+ "form": {
+ "pdp": "PDP"
+ },
+ "action": {
+ "map": "Map",
+ "cancel": "Cancel"
+ },
+ "check": {
+ "pdp": {
+ "required": "PDP is required"
+ }
+ },
+ "error": "Unable to map Project `{{projectName}}` to a PDP `{{pdpName}}`",
+ "success": "Project `{{projectName}}` successfully mapped to a PDP `{{pdpName}}`"
+ },
+ "unmap": {
+ "title": "Unmap Project and PDP",
+ "content": "Are you sure you want to unmap Project `{{projectName}}` / PDP `{{pdpName}}` ?",
+ "action": {
+ "unmap": "Unmap",
+ "cancel": "Cancel"
+ },
+ "error": "Unable to unmap Project `{{projectName}}` / PDP `{{pdpName}}`",
+ "success": "Project `{{projectName}}` / PDP `{{pdpName}}` successfully unmapped"
+ }
+ },
+ "pdp": {
+ "title": "PDPs",
+ "edit" : {
+ "title": "Pdp `{{pdpName}}` configuration",
+ "update" : "- update",
+ "basic" : {
+ "title" : "Basic Information",
+ "form": {
+ "id": "Id",
+ "name": "Name",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Update"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "error": "Unable to update PDP `{{pdpName}}`",
+ "success": "PDP `{{pdpName}}` successfully updated"
+ },
+ "policy": {
+ "title" : "Policies"
+ }
+ },
+ "list": {
+ "search": {
+ "placeholder": "Search PDPs",
+ "reset": "Reset"
+ },
+ "table": {
+ "name": "Name",
+ "security_pipeline":{
+ "number" : "Number of Securities"
+ },
+ "project": "Project",
+ "loading": {
+ "pdp": "Loading PDPs",
+ "project": "Loading Project"
+ },
+ "mapping" :{
+ "map": "Is not mapped"
+ },
+ "notFound": "There is no PDPs"
+ },
+ "action": {
+ "title": "Actions",
+ "detail": "Consult",
+ "configure": "Configure",
+ "rule": "Rules",
+ "delete": "Delete",
+ "add": "Add PDP",
+ "edit":"Editer"
+ },
+ "error": "Unable to retrieve PDPs"
+ },
+ "add": {
+ "title": "Add new PDP",
+ "form": {
+ "name": "Name",
+ "policy": "Policy",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Create PDP",
+ "cancel": "Cancel"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ },
+ "policy": {
+ "required": "Policy is required"
+ }
+ },
+ "error": "Unable to create PDP `{{pdpName}}`",
+ "success": "PDP `{{pdpName}}` successfully created"
+ },
+ "remove": {
+ "title": "Delete PDP",
+ "content": "Are you sure you want to delete `{{pdpName}}` PDP ?",
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete PDP `{{pdpName}}`",
+ "success": "PDP `{{pdpName}}` successfully deleted"
+ },
+ "configure": {
+ "title": "PDP `{{pdpName}}` configuration",
+ "action": {
+ "back": "Back to PDPs"
+ },
+ "subject": {
+ "panelTitle": "Subjects configuration",
+ "title": "Subjects",
+ "add": {
+ "title": "Add new Subject",
+ "form": {
+ "name": "Name",
+ "domain": "Domain",
+ "enabled": "Enabled",
+ "project": "Project",
+ "password": "Password",
+ "description": "Description"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "add": "Add Subject"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ },
+ "domain": {
+ "required": "Domain is required"
+ },
+ "project": {
+ "required": "Project is required"
+ },
+ "password": {
+ "required": "Password is required"
+ }
+ },
+ "error": "Unable to add Subject `{{subjectName}}`",
+ "success": "Subject `{{subjectName}}` successfully added"
+ },
+ "remove": {
+ "title": "Delete Subject",
+ "content": "Are you sure you want to delete `{{subjectName}}` subject of `{{pdpName}}` PDP ?",
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Subject `{{subjectName}}`",
+ "success": "Subject `{{subjectName}}` successfully deleted"
+ },
+ "category": {
+ "title": "Categories",
+ "add": {
+ "title": "Add new Category",
+ "form": {
+ "name": "Name"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "add": "Add Category"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "error": "Unable to add Subject Category `{{categoryName}}`",
+ "success": "Subject Category `{{categoryName}}` successfully added"
+ },
+ "remove": {
+ "title": "Delete Category",
+ "content": "Are you sure you want to delete `{{categoryName}}` subject category of `{{pdpName}}` PDP ?",
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Subject Category `{{categoryName}}`",
+ "success": "Subject Category `{{categoryName}}` successfully deleted"
+ }
+ },
+ "categoryValue": {
+ "title": "Values",
+ "add": {
+ "title": "Add new Value",
+ "form": {
+ "value": "Value"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "add": "Add Value"
+ },
+ "check": {
+ "value": {
+ "required": "Value is required"
+ }
+ },
+ "error": "Unable to add Subject Category Value`{{valueName}}`",
+ "success": "Subject Category Value `{{valueName}}` successfully added"
+ },
+ "remove": {
+ "title": "Delete Value",
+ "content": "Are you sure you want to delete `{{valueName}}` subject category value of `{{pdpName}}` PDP ?",
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Subject Category Value `{{valueName}}`",
+ "success": "Subject Category Value `{{valueName}}` successfully deleted"
+ }
+ },
+ "assignment": {
+ "title": "Subject Assignments",
+ "action": {
+ "assign": "Assign",
+ "unassign": "Unassign"
+ },
+ "list": {
+ "notFound": "There is no assignments"
+ },
+ "add": {
+ "error": "Unable to assign Subject `{{subjectName}}` / Category `{{categoryName}}` / Value `{{valueName}}`",
+ "success": "Subject `{{subjectName}}` / Category `{{categoryName}}` / Value `{{valueName}}` assignment successfully done"
+ },
+ "remove": {
+ "error": "Unable to unassign Subject `{{subjectName}}` / Category `{{categoryName}}` / Value `{{valueName}}`",
+ "success": "Subject `{{subjectName}}` / Category `{{categoryName}}` / Value `{{valueName}}` unassignment successfully done"
+ }
+ }
+ },
+ "object": {
+ "panelTitle": "Objects configuration",
+ "title": "Objects",
+ "add": {
+ "title": "Add new Object",
+ "form": {
+ "name": "Name",
+ "image": "Image",
+ "flavor": "Flavor"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "add": "Add Object"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ },
+ "image": {
+ "required": "Image is required"
+ },
+ "flavor": {
+ "required": "Flavor is required"
+ }
+ },
+ "error": "Unable to add Object `{{objectName}}`",
+ "success": "Object `{{objectName}}` successfully added"
+ },
+ "remove": {
+ "title": "Delete Object",
+ "content": "Are you sure you want to delete `{{objectName}}` object of `{{pdpName}}` PDP ?",
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Object `{{objectName}}`",
+ "success": "Object `{{objectName}}` successfully deleted"
+ },
+ "category": {
+ "title": "Categories",
+ "add": {
+ "title": "Add new Category",
+ "form": {
+ "name": "Name"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "add": "Add Category"
+ },
+ "check": {
+ "name": {
+ "required": "Name is required"
+ }
+ },
+ "error": "Unable to add Object Category `{{categoryName}}`",
+ "success": "Object Category `{{categoryName}}` successfully added"
+ },
+ "remove": {
+ "title": "Delete Category",
+ "content": "Are you sure you want to delete `{{categoryName}}` object category of `{{pdpName}}` PDP ?",
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Object Category `{{categoryName}}`",
+ "success": "Object Category `{{categoryName}}` successfully deleted"
+ }
+ },
+ "categoryValue": {
+ "title": "Values",
+ "add": {
+ "title": "Add new Value",
+ "form": {
+ "value": "Value"
+ },
+ "action": {
+ "cancel": "Cancel",
+ "add": "Add Value"
+ },
+ "check": {
+ "value": {
+ "required": "Value is required"
+ }
+ },
+ "error": "Unable to add Object Category Value`{{valueName}}`",
+ "success": "Object Category Value `{{valueName}}` successfully added"
+ },
+ "remove": {
+ "title": "Delete Value",
+ "content": "Are you sure you want to delete `{{valueName}}` object category value of `{{pdpName}}` PDP ?",
+ "action": {
+ "cancel": "Cancel",
+ "delete": "Delete"
+ },
+ "error": "Unable to delete Object Category Value `{{valueName}}`",
+ "success": "Object Category Value `{{valueName}}` successfully deleted"
+ }
+ },
+ "assignment": {
+ "title": "Object Assignments",
+ "action": {
+ "assign": "Assign",
+ "unassign": "Unassign"
+ },
+ "list": {
+ "notFound": "There is no assignments"
+ },
+ "add": {
+ "error": "Unable to assign Object `{{objectName}}` / Category `{{categoryName}}` / Value `{{valueName}}`",
+ "success": "Object `{{objectName}}` / Category `{{categoryName}}` / Value `{{valueName}}` assignment successfully done"
+ },
+ "remove": {
+ "error": "Unable to unassign Object `{{ObjectName}}` / Category `{{categoryName}}` / Value `{{valueName}}`",
+ "success": "Object `{{objectName}}` / Category `{{categoryName}}` / Value `{{valueName}}` unassignment successfully done"
+ }
+ }
+ }
+ },
+ "rule": {
+ "title": "PDP `{{pdpName}}` rules",
+ "list": {
+ "table": {
+ "subject": "Subjects",
+ "object": "Objects",
+ "notFound": "There is no Rules"
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Add Rule",
+ "delete": "Delete Rule"
+ }
+ },
+ "add": {
+ "title": "Add new Rule",
+ "action": {
+ "create": "Create Rule",
+ "cancel": "Cancel"
+ },
+ "form": {
+ "subject": {
+ "subject": "Subjects",
+ "category": "Categories",
+ "categoryValue": "Values",
+ "action": {
+ "add": "Add",
+ "delete": "Delete"
+ }
+ },
+ "object": {
+ "object": "Objects",
+ "category": "Categories",
+ "categoryValue": "Values",
+ "action": {
+ "add": "Add",
+ "delete": "Delete"
+ }
+ }
+ },
+ "success": "Rule successfully created",
+ "error": "Unable to create Rule"
+ },
+ "delete": {
+ "title": "Delete Rule",
+ "content": "Are you sure you want to delete rule `{{ruleJson}}` of `{{pdpName}}` PDP ?",
+ "action": {
+ "delete": "Delete Rule",
+ "cancel": "Cancel"
+ },
+ "error": "Unable to delete Rule `{{ruleJson}}`",
+ "success": "Rule `{{ruleJson}}` successfully deleted"
+ },
+ "action": {
+ "back": "Back to PDPs"
+ }
+ }
+ }
+ }
+}
diff --git a/old/moon_gui/static/i18n/fr.json b/old/moon_gui/static/i18n/fr.json
new file mode 100755
index 00000000..85c513b3
--- /dev/null
+++ b/old/moon_gui/static/i18n/fr.json
@@ -0,0 +1,1357 @@
+{
+ "moon": {
+ "global": {
+ "applicationName": "Moon",
+ "404": "Page non trouvée",
+ "error": "Une erreur globale est survenue: {{stacktrace}}"
+ },
+ "compatibility": {
+ "label": "Compatibilité navigateurs Web",
+ "title": "Compatibilité avec les navigateurs existants",
+ "content": "Moon est compatible avec : <ul><li>Internet Explorer 9 ou +</li><li><a href=\"http://www.mozilla.org/fr/firefox/\">Firefox</a> à jour</li><li><a href=\"http://chrome.google.com\">Chrome</a> à jour</li></ul>",
+ "close": "Fermer"
+ },
+ "menu": {
+ "project": "Project",
+ "pdp": "PDP",
+ "logs": "Log",
+ "policy": "Politique",
+ "model": "Modèle"
+ },
+ "login":{
+ "title":"Connexion",
+ "titlePage" : "Page d'idenditifcation",
+ "username" : "Nom d'utilisateur",
+ "password" : "Mot de passe",
+ "login" : "Connexion",
+ "check": {
+ "username": {
+ "required": "Le nom d'utilisateur est requis"
+ },
+ "password": {
+ "required": "Le mot de passe est requis"
+ }
+ },
+ "error" : "Impossible de se connecter à Keystone, code d'erreur {{errorCode}}",
+ "success" : "Connexion établie, Bienvenue sur la GUI de Moon, \"La lune est au dessus des nuages\""
+ },
+ "logout": {
+ "title": "Déconnexion",
+ "success" : "Déconnxion réussie"
+ },
+ "dashboard":{
+ "content" : "Moon:Software-Defined Security Framework"
+ },
+ "policy": {
+ "title": "Politiques",
+ "list" : {
+ "search": {
+ "placeholder": "Rechercher des Politiques",
+ "reset": "Effacer"
+ },
+ "table" : {
+ "name":"Nom",
+ "genre" : "Genre",
+ "description": "Description",
+ "loading": {
+ "category" : "Chargement de la Catégorie"
+ },
+ "notFound": "Il n'existe aucune Politique"
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Ajouter une Politique",
+ "detail": "Consulter",
+ "edit": "Editer",
+ "map" : "Associer une Politique à la PDP",
+ "unmap" : "Dissocier",
+ "delete": "Supprimer"
+ }
+ },
+ "unmap": {
+ "title": "Dissociation de la Policy et de la PDP",
+ "content": "Voulez-vous dissocier la PDP `{{pdpName}}` et la Policy `{{policyName}}` ?",
+ "action": {
+ "unmap": "Dissocier",
+ "cancel": "Annuler"
+ },
+ "error": "Impossible de dissocier la PDP `{{pdpName}}` et la Policy`{{policyName}}`",
+ "success": "La dissociation de la PDP `{{pdpName}}` et de la Policy `{{policyName}}` a été effectuée avec succès"
+ },
+ "map":{
+ "title": "Associer une Politique à la PDP `{{pdpName}}`",
+ "form" :{
+ "list": "Liste des Politiques"
+ },
+ "action": {
+ "create": "Associer une Politique",
+ "cancel": "Fermer",
+ "new": "Créer une Politique",
+ "list": "Associer une Politique existante",
+ "map": "Associer la Politique sélectionnée",
+ "delete" : "Supprimer la Politique sélectionnée"
+ },
+ "check": {
+ "policy":{
+ "required" : "La politique est requise"
+ }
+ },
+ "error": "Impossible d'associer la Politique `{{policyName}}` à la PDP `{{pdpName}}`",
+ "success": "L'association dde la Politique `{{policyName}}` avec la PDP `{{pdpName}}` a été effectuée avec succès"
+ },
+ "remove": {
+ "title": "Supprimer une Politique",
+ "content": {
+ "query": "Voulez-vous supprimer la Politique `{{policyName}}` ?"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer la Politique `{{policyName}}`",
+ "success": "La Politique `{{policyName}}` a été supprimée avec succès"
+ },
+ "edit" : {
+ "title": "Configuration de la Politique `{{policyName}}`",
+ "update": "- mettre à jour",
+ "show": {
+ "open": "( voir )",
+ "close": "( fermer )"
+ },
+ "basic" : {
+ "title" : "Informations de base",
+ "form": {
+ "id": "Id",
+ "name": "Nom",
+ "genre": "Genre",
+ "model": "Modèle",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Mettre à Jour"
+ },
+ "check": {
+ "name": {
+ "required": "Le Nom est requis"
+ },
+ "Genre": {
+ "required": "Le Genre est requis"
+ }
+ },
+ "error": "Impossible de mettre à jour la Politique `{{policyName}}`",
+ "success": "Le Politique `{{policyName}}` a été mise à jour avec succès"
+ },
+ "perimeter": {
+ "title" : "Périmètres"
+ },
+ "data": {
+ "title" : "Données"
+ },
+ "rules" : {
+ "title" : "Règles"
+ },
+ "assignments": {
+ "title" : "Affectations"
+ }
+ },
+ "add": {
+ "title": "Ajouter une nouvelle Politique",
+ "form": {
+ "name": "Nom",
+ "genre" : "Genre",
+ "model": "Modèles",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Créer la Politique",
+ "cancel": "Annuler"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ },
+ "genre" : {
+ "required" :"Le Genre est requis"
+ },
+ "model" : {
+ "required" :"Un Modèle est requis"
+ }
+ },
+ "error": "Impossible de créer la Politique `{{policyName}}`",
+ "success": "La Politique `{{policyName}}` a été créée avec succès"
+ },
+ "perimeter" :{
+ "subject" : {
+ "title" : "Liste des Sujets associées",
+ "delete": {
+ "error" : "Impossible de supprimer le Sujet : {{subjectName}}, la raison : {{reason}}",
+ "success": "Sujet `{{subjectName}}` a été supprimé avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Element Sujet"
+ },
+ "notFound": "Il n'existe aucun Sujet"
+ },
+ "object" : {
+ "title" : "Liste des Objets associées",
+ "delete": {
+ "error" : "Impossible de supprimer l'Objet : {{objectName}}, la raison : {{reason}}",
+ "success": "Objet `{{objectName}}` a été supprimé avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Element Objet"
+ },
+ "notFound": "Il n'existe aucun Objet"
+ },
+ "action" : {
+ "title" : "Liste des Actions associées",
+ "delete": {
+ "error" : "Impossible de supprimer l'Action : {{actionName}}, la raison : {{reason}}",
+ "success": "Action `{{actionName}}` a été supprimé avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Element Action"
+ },
+ "notFound": "Il n'existe aucune Action"
+ },
+ "update":{
+ "error": "Impossible de mettre à jour le Périmètre `{{perimeterName}}`",
+ "success": "Le Périèmtre `{{perimeterName}}` a été mis à jour"
+ },
+ "table": {
+ "id" : "Id",
+ "name" : "Nom",
+ "description" : "Description",
+ "email" : "Email",
+ "partner":{
+ "id" : "Id du Partenaire"
+ },
+ "action": {
+ "title": "Actions",
+ "delete": "Supprimer",
+ "update": "Mettre à jour",
+ "unmap": "Dissocier"
+ }
+ },
+ "edit": {
+ "name" : "Nom",
+ "description" : "Description",
+ "partnerId": "Partner Id",
+ "policies":"Liste des Politiques",
+ "email": "E-mail",
+ "selectedPolicies": "Politiques selectionnées",
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ }
+ },
+ "action": {
+ "list": "Associer un Périmètre existant",
+ "new": "Ajouter un nouveau Périmètre",
+ "create":"Ajouter le Périmètre ",
+ "map":"Asscoier le Périmètre selectionné",
+ "delete": "Supprimer"
+ },
+ "create": {
+ "error": "Impossible de créer l'Element `{{name}}`",
+ "success": "L'Element `{{name}}` a été créé avec succès"
+ },
+ "delete": {
+ "error": "Impossible de supprimer la Element `{{name}}`",
+ "success": "L'Element `{{name}}` a été supprimée avec succès"
+ }
+ }
+ },
+ "data" :{
+ "subject" : {
+ "title" : "Liste des Data Sujets associées",
+ "delete": {
+ "error" : "Impossible de supprimer la Data Sujet : {{subjectName}}, la raison : {{reason}}",
+ "success": "Data Sujet `{{subjectName}}` a été supprimée avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Data Sujet"
+ },
+ "notFound": "Il n'existe aucune Data Sujet"
+ },
+ "object" : {
+ "title" : "Liste des Data Objets associées",
+ "delete": {
+ "error" : "Impossible de supprimer la Data Objet : {{objectName}}, la raison : {{reason}}",
+ "success": "Data Objet `{{objectName}}` a été supprimée avec succès"
+ },
+ "add": {
+ "title": "Ajouter un Data Objet"
+ },
+ "notFound": "Il n'existe aucun Data Objet"
+ },
+ "action" : {
+ "title" : "Liste des Data Actions associées",
+ "delete": {
+ "error" : "Impossible de supprimer la Data Action : {{actionName}}, la raison : {{reason}}",
+ "success": "Data Action `{{actionName}}` a été supprimée avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Data Action"
+ },
+ "notFound": "Il n'existe aucune Data Action"
+ },
+ "table": {
+ "category" : {
+ "id" : "Id de la Catégorie",
+ "name" : "Nom de la Catégorie"
+ },
+ "name" : "Nom",
+ "description" : "Description",
+ "action": {
+ "title": "Actions",
+ "delete": "Supprimer",
+ "update": "Mettre à jour"
+ },
+ "loading": {
+ "category" : "Loading Catégorie"
+ }
+ },
+ "edit": {
+ "name" : "Nom",
+ "description" : "Description",
+ "categories": "Liste des Catégories",
+ "policies": "Liste des Politiques",
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ },
+ "category":{
+ "required": "Une Catégorie est requise"
+ },
+ "policy":{
+ "required": "Une Politique est requise"
+ }
+ },
+ "action": {
+ "list": "Associer une Data existante",
+ "new": "Créer une nouvelle Data",
+ "create":"Créer la Data",
+ "add":"Ajouter la Data selectionnée",
+ "delete": "Supprimer la Data"
+ },
+ "create": {
+ "error": "Impossible de créer l'Element `{{name}}`",
+ "success": "L'Element `{{name}}` a été créé avec succès"
+ },
+ "delete": {
+ "error": "Impossible de supprimer la Element `{{name}}`",
+ "success": "L'Element `{{name}}` a été supprimée avec succès"
+ }
+ }
+ },
+ "rules": {
+ "title": "Règles",
+ "list": {
+ "search": {
+ "placeholder": "Rechercher des Règles",
+ "reset": "Effacer"
+ },
+ "table": {
+ "id" : "Id",
+ "metaRule": "Meta Règle",
+ "description": "Description",
+ "enabled": "Enabled",
+ "rule": "Règle",
+ "instructions": "Instruction",
+ "notFound": "Il n'existe aucune Règle",
+ "loading": {
+ "metaRule" : "Chargement de la Meta Règle"
+ },
+ "action":{
+ "title": "Actions",
+ "delete": "Supprimer"
+ }
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Ajouter une Règle",
+ "detail": "Consulter",
+ "edit": "Editer",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de récupérer la liste des Règles"
+ },
+ "edit": {
+ "title" : "Liste des Règles associées",
+ "action" : {
+ "create": "Créer une Règles",
+ "delete": {
+ "error" : "Impossible de supprimer la Règles{{rulesName}}, raison : {{reason}}",
+ "success": "Règles`{{rulesName}}` supprimée avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Règles",
+ "policies": "Sélectionnez une Politique",
+ "instructions": "Instruction",
+ "metarules" : "Sélectionnez une des MetaRules associée(s)",
+ "categories":{
+ "subject": "Sélectionnez {{number}} Sujet(s)",
+ "object": "Sélectionnez {{number}} Object(s)",
+ "action": "Sélectionnez {{number}} Action(s)"
+ },
+ "selectedSubjects": "Sujets(s) sélectionnés",
+ "selectedObjects": "Objet(s) sélectionnés",
+ "selectedActions": "Action(s) sélectionnées",
+ "details":{
+ "show": "Détails",
+ "close": "Fermer"
+ },
+ "check":{
+ "policy":{
+ "required": "Une Politique est requise"
+ },
+ "instructions":{
+ "required": "Une Instruction au format JSON est requise"
+ },
+ "metarules":{
+ "required": "une MetaRules est requise"
+ },
+ "subject":{
+ "required": "{{number}} Sujets(s) sont requis"
+ },
+ "object":{
+ "required": "{{number}} Obje(s) sont requis"
+ },
+ "action":{
+ "required": "{{number}} Sujets(s) sont requises"
+ }
+ },
+ "create": {
+ "error": "Impossible de créer la Règles `{{name}}`",
+ "success": "La règles `{{name}}` a été créé avec succès"
+ },
+ "delete": {
+ "error": "Impossible de supprimer la Règle, raison: `{{reason}}`",
+ "success": "La Règle a été supprimée avec succès"
+ }
+ },
+ "notFound": "Il n'y a pas de Règles"
+ }
+ }
+ },
+ "assignments" :{
+ "subject" : {
+ "title" : "Liste des Affectations Sujets associées",
+ "delete": {
+ "error" : "Impossible de supprimer l'Affectations, la raison : {{reason}}",
+ "success": "Affectations a été supprimé avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Affectations Sujet"
+ },
+ "notFound": "Il n'existe aucune Affectations Sujet"
+ },
+ "object" : {
+ "title" : "Liste des Affectations Objets associées",
+ "delete": {
+ "error" : "Impossible de supprimer l'Affectations, la raison : {{reason}}",
+ "success": "Affectations a été supprimée avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Affectations Objet"
+ },
+ "notFound": "Il n'existe aucune Affectations Objet"
+ },
+ "action" : {
+ "title" : "Liste des Affectations Actions associées",
+ "delete": {
+ "error" : "Impossible de supprimer l'Affectations, la raison : {{reason}}",
+ "success": "Affectations Action a été supprimée avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Affectations Action"
+ },
+ "notFound": "Il n'existe aucune Affectations Action"
+ },
+ "table": {
+ "action": {
+ "title": "Actions",
+ "delete": "Supprimer",
+ "update": "Mettre à jour"
+ },
+ "perimeter": {
+ "name": "Nom du Périmètre"
+ },
+ "data":{
+ "name" : "Nom des Data"
+ },
+ "category": {
+ "name" : "Nom de la Catégorie"
+ },
+ "loading": {
+ "category" : "Chargement de la Catégorie",
+ "perimeter": "Chargement du Périmètre",
+ "data": "Chargement des Données"
+ }
+ },
+ "edit": {
+ "policies": "Sélectionnez une Politique",
+ "categories": "Sélectionnez une Catégorie",
+ "perimeters": "Sélectionnez un Perimètre",
+ "data": "Sélectionnez une Donnée",
+ "selectedData" : "Données Séléctionnées",
+ "check": {
+ "policy":{
+ "required": "Une Politique est requise"
+ },
+ "category":{
+ "required": "Une Catégorie est requise"
+ },
+ "perimeter":{
+ "required": "Un Perimètre est requis"
+ },
+ "data":{
+ "required": "Une Donnée est requise"
+ }
+ },
+ "action": {
+ "list": "Ajouter une Affectations existante",
+ "new": "Ajouter une nouvelle Affectations",
+ "create":"Créer l'Affectations",
+ "map":"Ajouter l'Affectations selectionnée",
+ "delete": "Supprimer l'Affectations"
+ },
+ "create": {
+ "error": "Impossible de créer l'Affectations`",
+ "success": "L'Affectations a été créé avec succès"
+ },
+ "delete": {
+ "error": "Impossible de supprimer l'Affectations, raison : `{{reason}}`",
+ "success": "L'Affectations a été supprimée avec succès"
+ }
+ }
+ }
+ },
+ "model":{
+ "title": "Modèles",
+ "list": {
+ "search": {
+ "placeholder": "Rechercher des Modèles",
+ "reset": "Effacer"
+ },
+ "table":{
+ "name":"Nom",
+ "description": "Description",
+ "metaRules":{
+ "number" : "Nombre de Meta Règles"
+ },
+ "notFound": "Il n'existe aucun Modèle"
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Ajouter un modèle",
+ "detail": "Consulter",
+ "edit": "Editer",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de récupérer la liste des Modèles"
+ },
+ "edit" : {
+ "title": "Configuration du Modèle `{{modelName}}`",
+ "update": "- mettre à jour",
+ "basic" : {
+ "title" : "Informations de base",
+ "form": {
+ "id": "Id",
+ "name": "Nom",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Mettre à Jour"
+ },
+ "check": {
+ "name": {
+ "required": "Le Nom est requis"
+ }
+ },
+ "error": "Impossible de mettre à jour le Modèle `{{modelName}}`",
+ "success": "Le Modèle `{{modelName}}` a été mis à jour avec succès"
+ },
+ "metarules": {
+ "title" : "Meta Règles"
+ }
+ },
+ "view": {
+ "title": "Détail du Modèle `{{modelName}}`",
+ "name": "Name",
+ "id": "Id",
+ "description": "Description",
+ "action": {
+ "close": "Fermer"
+ }
+ },
+ "remove": {
+ "title": "Supprimer un Modèle",
+ "content": {
+ "query": "Voulez-vous supprimer le Modèle `{{modelName}}` ?"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer le Modèle `{{modelName}}`",
+ "success": "Le Modèle `{{modelName}}` a été supprimé avec succès"
+ },
+ "metarules" :{
+ "title" : "List des Meta Règles",
+ "table":{
+ "name":"Nom",
+ "description": "Description",
+ "metadata": {
+ "subject" : {
+ "number" : "Nombre de Catégories Sujet"
+ },
+ "object" : {
+ "number" : "Nombre de Catégories Objet"
+ },
+ "action" : {
+ "number" : "Nombre de Catégories Action"
+ }
+ },
+ "notFound": "Il n'existe aucune Meta Règles"
+ },
+ "edit" : {
+ "title" : "Configuration de la Meta Règle `{{metaRuleName}}`",
+ "update": "- mettre à jour",
+ "basic" : {
+ "title" : "Informations de base",
+ "form": {
+ "id": "Id",
+ "name": "Nom",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Mettre à Jour"
+ },
+ "check": {
+ "name": {
+ "required": "Le Nom est requis"
+ }
+ },
+ "error": "Impossible de mettre à jour la Meta Règle `{{metaRuleName}}`",
+ "success": "La Meta Règle `{{metaRuleName}}` a été mis à jour avec succès"
+ }
+ },
+ "update":{
+ "error": "Impossible de mettre à jour la Meta Règle `{{metaRuleName}}`",
+ "success": "La Meta Règle `{{metaRuleName}}` a été mis à jour avec succès"
+ },
+ "action": {
+ "title": "Actions",
+ "edit": "Editer",
+ "remove": "Enlever",
+ "settings" : "Paramètres",
+ "add": "Ajouter",
+ "detail": {
+ "open": "Consulter",
+ "close": "Fermer"
+ }
+ },
+ "add":{
+ "title": "Ajouter une nouvelle Meta Règle",
+ "form": {
+ "name": "Nom",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Ajouter la Meta Règle",
+ "cancel": "Annuler"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ }
+ },
+ "error": "Impossible de créer la Meta Règle `{{metaRuleName}}`",
+ "success": "La Meta Règle `{{metaRuleName}}` a été créée avec succès"
+ },
+ "map":{
+ "title": "Ajouter une Meta Règle",
+ "form" :{
+ "list": "Liste des Meta Règles"
+ },
+ "action": {
+ "create": "Ajouter une nouvelle Meta Règle",
+ "cancel": "Fermer",
+ "new": "Ajouter une Meta Règle",
+ "list": "Ajouter une Meta Règle existante",
+ "add": "Ajouter la Meta Règle sélectionnée",
+ "delete" : "Supprimer la Meta Règle sélectionnée"
+ },
+ "error": "Impossible d'associer le Modèle `{{modelName}}` à la Meta Règle `{{metaRuleName}}`",
+ "success": "L'association du Modèle `{{modelName}}` avec la Meta Règle `{{metaRuleName}}` a été effectuée avec succès"
+ },
+ "unmap": {
+ "title": "Enlever de la Meta Règle du Modèle",
+ "content": "Voulez-vous enlever le Modèle `{{modelName}}` de la Meta Règle `{{metaRuleName}}` ?",
+ "action": {
+ "unmap": "Enlever",
+ "cancel": "Annuler"
+ },
+ "error": "Impossible d'enlever le Modèle `{{modelName}}` de la Meta Règle `{{metaRuleName}}`",
+ "success": "La dissociation du Modèle `{{modelName}}` de la Meta Règle `{{metaRuleName}}` a été effectuée avec succès"
+ },
+ "delete": {
+ "error": "Impossible de supprimer la Meta Rule `{{metaRuleName}}`",
+ "success": "La Meta Rule `{{metaRuleName}}` a été supprimée avec succès"
+ }
+ },
+ "metadata" :{
+ "subject" : {
+ "title" : "Liste des Catégories Sujet associées",
+ "delete": {
+ "error" : "Impossible de supprimer le Sujet : {{subjectName}}, la raison : {{reason}}",
+ "success": "Sujet `{{subjectName}}` a été supprimé avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Catégorie Sujet"
+ },
+ "notFound": "Il n'existe aucun Sujet"
+ },
+ "object" : {
+ "title" : "Liste des Catégories Objet associées",
+ "delete": {
+ "error" : "Impossible de supprimer l'Objet : {{objectName}}, la raison : {{reason}}",
+ "success": "Objet `{{objectName}}` a été supprimé avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Catégorie Objet"
+ },
+ "notFound": "Il n'existe aucun Objet"
+ },
+ "action" : {
+ "title" : "Liste des Catégories Action associées",
+ "remove": "Enlever",
+ "delete": {
+ "error" : "Impossible de supprimer l'Action : {{actionName}}, la raison : {{reason}}",
+ "success": "Action `{{actionName}}` a été supprimé avec succès"
+ },
+ "add": {
+ "title": "Ajouter une Catégorie Action"
+ },
+ "notFound": "Il n'existe aucune Action"
+ },
+ "table": {
+ "id" : "Id",
+ "name" : "Nom",
+ "description" : "Description",
+ "action": {
+ "title": "Actions",
+ "delete": "Supprimer",
+ "update": "Mettre à jour"
+ }
+ },
+ "edit": {
+ "name" : "Nom",
+ "description" : "Description",
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ }
+ },
+ "action": {
+ "list": "Ajouter une Catégorie existante",
+ "new": "Ajouter une nouvelle Catégorie",
+ "create":"Ajouter la Catégorie",
+ "add":"Ajouter la Catégorie selectionnée",
+ "delete": "Supprimer"
+ },
+ "create": {
+ "error": "Impossible de créer la Catégorie `{{name}}`",
+ "success": "La Catégorie `{{name}}` a été créé avec succès"
+ },
+ "delete": {
+ "error": "Impossible de supprimer la Catégorie `{{name}}`",
+ "success": "La Catégorie `{{name}}` a été supprimée avec succès"
+ }
+ }
+ },
+ "add":{
+ "title": "Ajouter un nouveau Model",
+ "form": {
+ "name": "Nom",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Créer le Modèle",
+ "cancel": "Annuler"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ }
+ },
+ "error": "Impossible de créer le Modèle `{{modelName}}`",
+ "success": "Le Modèle `{{modelName}}` a été créé avec succès"
+ }
+ },
+ "project": {
+ "title": "Projects",
+ "list": {
+ "search": {
+ "placeholder": "Rechercher des Projects",
+ "reset": "Effacer"
+ },
+ "table": {
+ "name": "Nom",
+ "domain": "Domaine",
+ "managed": "Supervisé",
+ "enabled": "Activé",
+ "description": "Description",
+ "mapping": "PDP",
+ "loading": {
+ "project": "Chargement des Projects",
+ "pdp": "Chargement du PDP"
+ },
+ "notFound": "Il n'existe aucun Project"
+ },
+ "action": {
+ "title": "Actions",
+ "detail": "Consulter",
+ "delete": "Supprimer",
+ "add": "Ajouter un Project",
+ "map": "Associer à un PDP",
+ "unmap": "Dissocier"
+ },
+ "error": "Impossible de récupérer la liste des Projects"
+ },
+ "view": {
+ "title": "Détail du Project `{{projectName}}`",
+ "action": {
+ "close": "Fermer"
+ },
+ "subject": {
+ "title": "Sujets",
+ "name": "Nom",
+ "mail": "Email",
+ "domain": "Domaine",
+ "enabled": "Activé",
+ "error": "Impossible de récupérer la liste des Sujets"
+ },
+ "object": {
+ "title": "Objets",
+ "category": "Catégorie",
+ "description": "Description",
+ "enabled": "Activé",
+ "name": "Nom",
+ "error": "Impossible de récupérer la liste des Objets",
+ "loading": "Chargement des Objets",
+ "notFound": "Il n'existe aucun Objet"
+ },
+ "role": {
+ "title": "Roles",
+ "category": "Catégorie",
+ "value": "Valeur",
+ "description": "Description",
+ "assigned": "Affecté",
+ "enabled": "Activé",
+ "error": "Impossible de récupérer la liste des Roles",
+ "loading": "Chargement des Roles",
+ "notFound": "Il n'existe aucun Role"
+ },
+ "roleAssignment": {
+ "title": "Affectation des roles",
+ "category": "Catégorie",
+ "attributes": "Attributs",
+ "description": "Description",
+ "error": "impossible de récupérer la liste des affectations",
+ "loading": "Chargement des Affectations",
+ "notFound": "Il n'existe aucune Affectation"
+ },
+ "group": {
+ "title": "Groupes",
+ "category": "Catégorie",
+ "value": "Valeur",
+ "description": "Description",
+ "assigned": "Affecté",
+ "enabled": "Activé",
+ "error": "Impossible de récupérer la liste des Groupes",
+ "loading": "Chargement des Groupes",
+ "notFound": "Il n'existe aucun Groupe"
+ },
+ "groupAssignment": {
+ "title": "Affectation des groupes",
+ "category": "Catégorie",
+ "attributes": "Attributs",
+ "description": "Description",
+ "error": "impossible de récupérer la liste des affectations",
+ "loading": "Chargement des Affectations",
+ "notFound": "Il n'existe aucune Affectation"
+ }
+ },
+ "add": {
+ "title": "Ajouter un nouveau Project",
+ "form": {
+ "name": "Nom",
+ "description": "Description",
+ "enabled": "Activé",
+ "domain": "Domaine"
+ },
+ "action": {
+ "create": "Créer le Project",
+ "cancel": "Annuler"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ },
+ "domain": {
+ "required": "Le domaine est requis"
+ }
+ },
+ "error": "Impossible de créer le Project `{{projectName}}`",
+ "success": "Le Project `{{projectName}}` a été créé avec succès"
+ },
+ "remove": {
+ "title": "Supprimer un Project",
+ "content": {
+ "query": "Voulez-vous supprimer le Project `{{projectName}}` ?",
+ "isNotMapped": "Ce Project est associé avec aucune PDP.",
+ "isMapped": "Ce project est associé avec le PDP `{{pdpName}}`, le supprimer va supprimer le mapping associé"
+ },
+ "mapping":{
+ "remove":{
+ "error": "Impossible de supprimer la relation avec `{{pdpName}}`"
+ }
+ },
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer le Project `{{projectName}}`",
+ "success": "Le Project `{{projectName}}` a été supprimé avec succès"
+ },
+ "map": {
+ "title": "Associé le Project `{{projectName}}` avec une PDP",
+ "form": {
+ "pdp": "PDP"
+ },
+ "action": {
+ "map": "Associer",
+ "cancel": "Annuler"
+ },
+ "check": {
+ "pdp": {
+ "required": "L'PDP est requise"
+ }
+ },
+ "error": "Impossible d'associer le Project `{{projectName}}` avec la PDP `{{pdpName}}`",
+ "success": "L'association du Project `{{projectName}}` avec la PDP `{{pdpName}}` a été effectué avec succès"
+ },
+ "unmap": {
+ "title": "Dissociation Project et PDP",
+ "content": "Voulez-vous dissocier le Project `{{projectName}}` et la PDP `{{pdpName}}` ?",
+ "action": {
+ "unmap": "Dissocier",
+ "cancel": "Annuler"
+ },
+ "error": "Impossible de dissocier le Project `{{projectName}}` et la PDP `{{pdpName}}`",
+ "success": "La dissociation du Project `{{projectName}}` et de la PDP `{{pdpName}}` a été effectuée avec succès"
+ }
+ },
+ "pdp": {
+ "title": "PDPs",
+ "edit" : {
+ "title": "configuration du PDP `{{pdpName}}` ",
+ "update" : "- Mettre à jour",
+ "basic" : {
+ "title" : "Information de base",
+ "form": {
+ "id": "Id",
+ "name": "Nom",
+ "description": "Description"
+ },
+ "action": {
+ "init": "Init",
+ "update": "Mettre à jour"
+ },
+ "check": {
+ "name": {
+ "required": "Le Nom est requis"
+ }
+ },
+ "error": "Impossible de mettre à jour la PDP `{{pdpName}}`",
+ "success": "La PDP `{{pdpName}}` a été mis à jour avec succès"
+ },
+ "policy": {
+ "title" : "Politiques"
+ }
+ },
+ "list": {
+ "search": {
+ "placeholder": "Rechercher des PDPs",
+ "reset": "Effacer"
+ },
+ "table": {
+ "name": "Nom",
+ "security_pipeline":{
+ "number" : "Nombre de Règles"
+ },
+ "project": "Project",
+ "loading": {
+ "pdp": "Chargement des PDPs",
+ "project": "Chargement du Project"
+ },
+ "mapping" :{
+ "map": "n'est pas associé à un projet"
+ },
+ "notFound": "Il n'existe aucune PDP"
+ },
+ "action": {
+ "title": "Actions",
+ "detail": "Consulter",
+ "configure": "Configurer",
+ "rule": "Règles",
+ "delete": "Supprimer",
+ "add": "Ajouter une PDP",
+ "edit": "Editer"
+ },
+ "error": "Impossible de récupérer la liste des PDPs"
+ },
+ "add": {
+ "title": "Ajouter une nouvelle PDP",
+ "form": {
+ "name": "Nom",
+ "policy": "Règle",
+ "description": "Description"
+ },
+ "action": {
+ "create": "Créer la PDP",
+ "cancel": "Annuler"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ },
+ "policy": {
+ "required": "Une règle est requise"
+ }
+ },
+ "error": "Impossible de créer la PDP `{{pdpName}}`",
+ "success": "La PDP `{{pdpName}}` a été créée avec succès"
+ },
+ "remove": {
+ "title": "Supprimer une PDP",
+ "content": "Voulez-vous supprimer la PDP `{{pdpName}}` ?",
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer la PDP `{{pdpName}}`",
+ "success": "la PDP `{{pdpName}}` a été supprimé avec succès"
+ },
+ "configure": {
+ "title": "Configuration de la PDP `{{pdpName}}`",
+ "action": {
+ "back": "Liste des PDPs"
+ },
+ "subject": {
+ "panelTitle": "Configuration des Sujets",
+ "title": "Sujets",
+ "add": {
+ "title": "Ajouter un nouveau Sujet",
+ "form": {
+ "name": "Nom",
+ "domain": "Domaine",
+ "enabled": "Activé",
+ "project": "Projet",
+ "password": "Mot de passe",
+ "description": "Description"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "add": "Ajouter Sujet"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ },
+ "domain": {
+ "required": "Le domaine est requis"
+ },
+ "project": {
+ "required": "Le projet est requis"
+ },
+ "password": {
+ "required": "Le mot de passe est requis"
+ }
+ },
+ "error": "Impossible d'ajouter le Sujet `{{subjectName}}`",
+ "success": "Le Sujet `{{subjectName}}` a été ajouté avec succès"
+ },
+ "remove": {
+ "title": "Supprimer un Sujet",
+ "content": "Voulez-vous supprimer le Sujet `{{subjectName}}` de la PDP `{{pdpName}}` ?",
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer le Sujet `{{subjectName}}`",
+ "success": "Le Sujet `{{subjectName}}` a été supprimé avec succès"
+ },
+ "category": {
+ "title": "Catégories",
+ "add": {
+ "title": "Ajouter une nouvelle Catégorie",
+ "form": {
+ "name": "Nom"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "add": "Ajouter Catégorie"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ }
+ },
+ "error": "Impossible d'ajouter la Catégorie `{{categoryName}}`",
+ "success": "Catégorie `{{categoryName}}` ajoutée avec succès"
+ },
+ "remove": {
+ "title": "Supprimer une Catégorie",
+ "content": "Voulez-vous supprimer la Catégorie `{{categoryName}}` de la PDP `{{pdpName}}` ?",
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer la Catégorie `{{categoryName}}`",
+ "success": "La Catégorie `{{categoryName}}` a été supprimée avec succès"
+ }
+ },
+ "categoryValue": {
+ "title": "Valeurs",
+ "add": {
+ "title": "Ajouter une nouvelle Valeur",
+ "form": {
+ "value": "Valeur"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "add": "Ajouter Valeur"
+ },
+ "check": {
+ "value": {
+ "required": "La valeur est requise"
+ }
+ },
+ "error": "Impossible d'ajouter la Valeur `{{valueName}}`",
+ "success": "Valeur `{{valueName}}` ajoutée avec succès"
+ },
+ "remove": {
+ "title": "Supprimer une Valeur",
+ "content": "Voulez-vous supprimer la Valeur `{{valueName}}` de la PDP `{{pdpName}}` ?",
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer la Valeur `{{valueName}}`",
+ "success": "La Valeur `{{valueName}}` a été supprimée avec succès"
+ }
+ },
+ "assignment": {
+ "title": "Affectation des Sujets",
+ "action": {
+ "assign": "Affecter",
+ "unassign": "Désaffecter"
+ },
+ "list": {
+ "notFound": "Il n'existe aucune affectation"
+ },
+ "add": {
+ "error": "Impossible de réaliser l'affectation Sujet `{{subjectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}`",
+ "success": "Affectation de Sujet `{{subjectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}` réalisée avec succès"
+ },
+ "remove": {
+ "error": "Impossible de réaliser la désaffectation Sujet `{{subjectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}`",
+ "success": "Désaffectation de Sujet `{{subjectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}` réalisée avec succès"
+ }
+ }
+ },
+ "object": {
+ "panelTitle": "Configuration des Objets",
+ "title": "Objets",
+ "add": {
+ "title": "Ajouter un nouvel Objet",
+ "form": {
+ "name": "Nom",
+ "image": "Image",
+ "flavor": "Type"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "add": "Ajouter Objet"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ },
+ "image": {
+ "required": "L'image est requise"
+ },
+ "flavor": {
+ "required": "Le type est requis"
+ }
+ },
+ "error": "Impossible d'ajouter l'Objet `{{objectName}}`",
+ "success": "L'Objet `{{objectName}}` a été ajouté avec succès"
+ },
+ "remove": {
+ "title": "Supprimer un Objet",
+ "content": "Voulez-vous supprimer l'Objet `{{objectName}}` de la PDP `{{pdpName}}` ?",
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer l'Objet `{{objectName}}`",
+ "success": "L'Objet `{{objectName}}` a été supprimé avec succès"
+ },
+ "category": {
+ "title": "Catégories",
+ "add": {
+ "title": "Ajouter une nouvelle Catégorie",
+ "form": {
+ "name": "Nom"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "add": "Ajouter Catégorie"
+ },
+ "check": {
+ "name": {
+ "required": "Le nom est requis"
+ }
+ },
+ "error": "Impossible d'ajouter la Catégorie `{{categoryName}}`",
+ "success": "Catégorie `{{categoryName}}` ajoutée avec succès"
+ },
+ "remove": {
+ "title": "Supprimer une Catégorie",
+ "content": "Voulez-vous supprimer la Catégorie `{{categoryName}}` de la PDP `{{pdpName}}` ?",
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer la Catégorie `{{categoryName}}`",
+ "success": "La Catégorie `{{categoryName}}` a été supprimée avec succès"
+ }
+ },
+ "categoryValue": {
+ "title": "Valeurs",
+ "add": {
+ "title": "Ajouter une nouvelle Valeur",
+ "form": {
+ "value": "Valeur"
+ },
+ "action": {
+ "cancel": "Annuler",
+ "add": "Ajouter Valeur"
+ },
+ "check": {
+ "value": {
+ "required": "La valeur est requise"
+ }
+ },
+ "error": "Impossible d'ajouter la Valeur `{{valueName}}`",
+ "success": "Valeur `{{valueName}}` ajoutée avec succès"
+ },
+ "remove": {
+ "title": "Supprimer une Valeur",
+ "content": "Voulez-vous supprimer la Valeur `{{valueName}}` de la PDP `{{pdpName}}` ?",
+ "action": {
+ "cancel": "Annuler",
+ "delete": "Supprimer"
+ },
+ "error": "Impossible de supprimer la Valeur `{{valueName}}`",
+ "success": "La Valeur `{{valueName}}` a été supprimée avec succès"
+ }
+ },
+ "assignment": {
+ "title": "Affectation des Objets",
+ "action": {
+ "assign": "Affecter",
+ "unassign": "Désaffecter"
+ },
+ "list": {
+ "notFound": "Il n'existe aucune affectation"
+ },
+ "add": {
+ "error": "Impossible de réaliser l'affectation Objet `{{objectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}`",
+ "success": "Affectation de Objet `{{objectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}` réalisée avec succès"
+ },
+ "remove": {
+ "error": "Impossible de réaliser la désaffectation Objet `{{objectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}`",
+ "success": "Désaffectation de Objet `{{objectName}}` / Catégorie `{{categoryName}}` / Valeur `{{valueName}}` réalisée avec succès"
+ }
+ }
+ }
+ },
+ "rule": {
+ "title": "Règles de la PDP `{{pdpName}}`",
+ "list": {
+ "table": {
+ "subject": "Sujets",
+ "object": "Objects",
+ "notFound": "Il n'existe aucune règle"
+ },
+ "action": {
+ "title": "Actions",
+ "add": "Ajouter une règle",
+ "delete": "Supprimer une règle"
+ }
+ },
+ "add": {
+ "title": "Ajouter une nouvelle Règle",
+ "action": {
+ "create": "Créer la Règle",
+ "cancel": "Annuler"
+ },
+ "form": {
+ "subject": {
+ "subject": "Sujets",
+ "category": "Catégories",
+ "categoryValue": "Valeur",
+ "action": {
+ "add": "Ajouter",
+ "delete": "Supprimer"
+ }
+ },
+ "object": {
+ "object": "Objets",
+ "category": "Catégories",
+ "categoryValue": "Valeurs",
+ "action": {
+ "add": "Ajouter",
+ "delete": "Supprimer"
+ }
+ }
+ },
+ "success": "La règle a été créée avec succès",
+ "error": "Impossible de créer la règle"
+ },
+ "delete": {
+ "title": "Supprime une Règle",
+ "content": "Voulez-vous supprimer la Valeur règle `{{ruleJson}}` de la PDP `{{pdpName}}` ?",
+ "action": {
+ "delete": "Supprimer la Règle",
+ "cancel": "Annuler"
+ },
+ "error": "Impossible de supprimer la règle `{{ruleJson}}`",
+ "success": "La règle `{{ruleJson}}` a été supprimée avec succès"
+ },
+ "action": {
+ "back": "Liste des PDPs"
+ }
+ }
+ }
+ }
+}
diff --git a/old/moon_gui/static/img/ajax-loader.gif b/old/moon_gui/static/img/ajax-loader.gif
new file mode 100755
index 00000000..d0bce154
--- /dev/null
+++ b/old/moon_gui/static/img/ajax-loader.gif
Binary files differ
diff --git a/old/moon_gui/static/img/ajax-waiting.gif b/old/moon_gui/static/img/ajax-waiting.gif
new file mode 100755
index 00000000..d84f6537
--- /dev/null
+++ b/old/moon_gui/static/img/ajax-waiting.gif
Binary files differ
diff --git a/old/moon_gui/static/img/arrow-link.gif b/old/moon_gui/static/img/arrow-link.gif
new file mode 100755
index 00000000..ca17f44b
--- /dev/null
+++ b/old/moon_gui/static/img/arrow-link.gif
Binary files differ
diff --git a/old/moon_gui/static/img/et.jpg b/old/moon_gui/static/img/et.jpg
new file mode 100644
index 00000000..67cc0a9d
--- /dev/null
+++ b/old/moon_gui/static/img/et.jpg
Binary files differ
diff --git a/old/moon_gui/static/img/logo-openstack.png b/old/moon_gui/static/img/logo-openstack.png
new file mode 100755
index 00000000..60ab0e1e
--- /dev/null
+++ b/old/moon_gui/static/img/logo-openstack.png
Binary files differ
diff --git a/old/moon_gui/static/img/logo-orange.gif b/old/moon_gui/static/img/logo-orange.gif
new file mode 100755
index 00000000..9c612291
--- /dev/null
+++ b/old/moon_gui/static/img/logo-orange.gif
Binary files differ
diff --git a/old/moon_gui/static/styles/main.css b/old/moon_gui/static/styles/main.css
new file mode 100644
index 00000000..4e10370e
--- /dev/null
+++ b/old/moon_gui/static/styles/main.css
@@ -0,0 +1,173 @@
+/* ----------------------------------------------------------------------------------
+# Copyright 2014 Orange
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+---------------------------------------------------------------------------------- */
+
+html {
+ overflow: auto;
+ height: 100%;
+ margin: 0px;
+ padding: 0px;
+}
+
+body {
+ height: 100%;
+ margin: 0px;
+ padding: 0px;
+ color: #323232;
+ font-family: Arial, Helvetica, sans-serif;
+ /* http://clagnut.com/blog/348/ */
+ font-size: 1em;
+}
+
+div, span, td, input, textarea, li {
+ font-size: 1em;
+}
+
+.container {
+ font-size: 1.2em;
+}
+
+.footer {
+ margin: 1em 0 1em 0
+}
+
+input[disabled], textarea[disabled] {
+ background-color: #f6f6f6;
+}
+
+strong, .strong {
+ font-weight: bold;
+}
+
+h1, h2, h3, .likeH2 {
+ color: #FF6600;
+ text-align: center;
+}
+
+h1 {
+ font-size: 2em;
+ margin: 0em;
+}
+
+h2, .likeH2 {
+ font-size: 1.8em;
+ font-weight: lighter;
+ line-height: 1em;
+ margin: 0 0 1em;
+}
+
+h3 {
+ font-size: 1.6em;
+ font-weight: lighter;
+ line-height: 1em;
+ margin: 0 0 1em;
+ text-align: left;
+}
+
+img {
+ border: none;
+ vertical-align: middle;
+}
+
+.banner {
+ margin: 1.5em 0 1.5em 0;
+}
+
+.sub-banner {
+ margin: 0 0 1.5em 0;
+}
+
+.underlined {
+ text-decoration: underline;
+}
+
+.header img {
+ float: left;
+}
+
+.header h1 {
+ position: relative;
+}
+
+hr {
+ margin-top: 10px;
+ margin-bottom: 10px;
+}
+
+.table {
+ text-align: left !important;
+}
+
+.centered {
+ text-align: center;
+ color: #cbcbcb;
+}
+
+.customTables, .dropdown-menu {
+ text-align: left !important;
+}
+
+.resourceCombo {
+ width: 100%;
+}
+
+.top05 { margin-top: 0.5em; }
+.top10 { margin-top: 1.0em; }
+.top15 { margin-top: 1.5em; }
+.top20 { margin-top: 2.0em; }
+.top25 { margin-top: 2.5em; }
+.top30 { margin-top: 3.0em; }
+
+.left05 { margin-left: 0.5em }
+.left10 { margin-left: 1.0em }
+.left15 { margin-left: 1.5em }
+.left20 { margin-left: 2.0em }
+.left25 { margin-left: 2.5em }
+.left30 { margin-left: 3.0em }
+
+.black {
+ color: #333
+}
+
+.divider {
+ height: 1px;
+ margin: 9px 0;
+ overflow: hidden;
+ background-color: #e5e5e5;
+}
+
+.img-dashboard{
+ padding-top:30px;
+ margin:auto;
+}
+/* */
+/*
+.modal-backdrop.am-fade {
+ opacity: .5;
+ transition: opacity .15s linear;
+ &.ng-enter {
+ opacity: 0;
+ &.ng-enter-active {
+ opacity: .5;
+ }
+ }
+ &.ng-leave {
+ opacity: .5;
+ &.ng-leave-active {
+ opacity: 0;
+ }
+ }
+}
+*/ \ No newline at end of file
diff --git a/old/moon_gui/static/version.json b/old/moon_gui/static/version.json
new file mode 100755
index 00000000..4f228d2b
--- /dev/null
+++ b/old/moon_gui/static/version.json
@@ -0,0 +1,3 @@
+{
+ "version": "1.1.0"
+}
diff --git a/old/moon_gui/templates/index.html b/old/moon_gui/templates/index.html
new file mode 100644
index 00000000..7a321543
--- /dev/null
+++ b/old/moon_gui/templates/index.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="moon">
+<head>
+ <meta charset="UTF-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <title>Moon</title>
+ <link href="assets/img/favicon.ico" rel="shortcut icon"/>
+
+ <!-- inject:css -->
+ <!-- endinject -->
+</head>
+<body>
+
+<div class="container">
+ <div ng-controller="HeaderController" ng-include="'html/common/header/header.tpl.html'"></div>
+</div>
+
+<div class="container">
+ <div ui-view></div>
+</div>
+
+<div class="container">
+ <div ng-controller="FooterController" ng-include="'html/common/footer/footer.tpl.html'"></div>
+</div>
+
+<!-- inject:js -->
+<!-- endinject -->
+
+</body>
+</html> \ No newline at end of file
diff --git a/old/moon_interface/Changelog b/old/moon_interface/Changelog
new file mode 100644
index 00000000..361d7840
--- /dev/null
+++ b/old/moon_interface/Changelog
@@ -0,0 +1,36 @@
+# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+CHANGES
+=======
+
+1.0.0
+-----
+- First version of the manager
+
+2.0.0
+-----
+- Version built inside the Keystone component
+
+3.0.0
+-----
+- Version built outside the Keystone component
+
+4.0.0
+-----
+- First micro-architecture version
+
+4.3.3
+-----
+- use the threading capability of Flask app
+
+4.3.3-1
+-----
+- Fix a bug in authz_requests
+
+4.4.0
+-----
+- Add the update API
diff --git a/old/moon_interface/Dockerfile b/old/moon_interface/Dockerfile
new file mode 100644
index 00000000..00880496
--- /dev/null
+++ b/old/moon_interface/Dockerfile
@@ -0,0 +1,15 @@
+FROM python:3
+
+LABEL Name=Interface
+LABEL Description="Interface component for the Moon platform"
+LABEL Maintainer="Thomas Duval"
+LABEL Url="https://wiki.opnfv.org/display/moon/Moon+Project+Proposal"
+
+USER root
+
+ADD . /root
+WORKDIR /root/
+RUN pip3 install --no-cache-dir -r requirements.txt
+RUN pip3 install --no-cache-dir .
+
+CMD ["python3", "-m", "moon_interface"] \ No newline at end of file
diff --git a/old/moon_interface/LICENSE b/old/moon_interface/LICENSE
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/old/moon_interface/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/old/moon_interface/MANIFEST.in b/old/moon_interface/MANIFEST.in
new file mode 100644
index 00000000..1f674d50
--- /dev/null
+++ b/old/moon_interface/MANIFEST.in
@@ -0,0 +1,9 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+include README.rst
+include LICENSE
+include setup.py
+include requirements.txt
diff --git a/old/moon_interface/README.md b/old/moon_interface/README.md
new file mode 100644
index 00000000..4c0e483d
--- /dev/null
+++ b/old/moon_interface/README.md
@@ -0,0 +1,9 @@
+# moon_interface
+
+
+This package contains the core module for the Moon project
+It is designed to provide authorization features to all OpenStack components.
+
+For any other information, refer to the parent project:
+
+ https://git.opnfv.org/moon
diff --git a/old/moon_interface/moon_interface/__init__.py b/old/moon_interface/moon_interface/__init__.py
new file mode 100644
index 00000000..85c245e0
--- /dev/null
+++ b/old/moon_interface/moon_interface/__init__.py
@@ -0,0 +1,6 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+__version__ = "4.4.0"
diff --git a/old/moon_interface/moon_interface/__main__.py b/old/moon_interface/moon_interface/__main__.py
new file mode 100644
index 00000000..9ad7bf2a
--- /dev/null
+++ b/old/moon_interface/moon_interface/__main__.py
@@ -0,0 +1,4 @@
+from moon_interface.server import create_server
+
+server = create_server()
+server.run()
diff --git a/old/moon_interface/moon_interface/api/__init__.py b/old/moon_interface/moon_interface/api/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/moon_interface/moon_interface/api/__init__.py
diff --git a/old/moon_interface/moon_interface/api/authz.py b/old/moon_interface/moon_interface/api/authz.py
new file mode 100644
index 00000000..b82a14f1
--- /dev/null
+++ b/old/moon_interface/moon_interface/api/authz.py
@@ -0,0 +1,162 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Authz is the endpoint to get authorization response
+"""
+
+from flask import request
+from flask_restful import Resource
+import logging
+import pickle
+import time
+from uuid import uuid4
+from python_moonutilities import exceptions
+
+from moon_interface.authz_requests import AuthzRequest
+
+__version__ = "4.3.1"
+
+logger = logging.getLogger("moon.interface.api.authz." + __name__)
+
+
+def get_pdp_from_cache(cache, uuid):
+ """Check if a PDP exist with this ID in the cache of this component
+
+ :param cache: Cache to use
+ :param uuid: Keystone Project ID
+ :return: True or False
+ """
+ if uuid in cache.pdp:
+ return cache.pdp.get(uuid)
+
+ cache.update()
+
+ if uuid in cache.pdp:
+ return cache.pdp.get(uuid)
+
+ raise exceptions.PdpUnknown
+
+
+def create_authz_request(cache, interface_name, manager_url, pdp_id, subject_name, object_name, action_name):
+ """Create the authorization request and make the first call to the Authz function
+
+ :param cache: Cache to use
+ :param interface_name: hostname of the interface
+ :param manager_url: URL of the manager
+ :param pdp_id: Keystone Project ID
+ :param subject_name: name of the subject
+ :param object_name: name of the object
+ :param action_name: name of the action
+ :return: Authorisation request
+ """
+ req_id = uuid4().hex
+ keystone_project_id = cache.get_keystone_project_id_from_pdp_id(pdp_id)
+ logger.info("keystone_project_id={}".format(keystone_project_id))
+ ctx = {
+ "project_id": keystone_project_id,
+ "subject_name": subject_name,
+ "object_name": object_name,
+ "action_name": action_name,
+ "request_id": req_id,
+ "interface_name": interface_name,
+ "manager_url": manager_url,
+ "cookie": uuid4().hex
+ }
+ cache.authz_requests[req_id] = AuthzRequest(ctx)
+ return cache.authz_requests[req_id]
+
+
+def delete_authz_request(cache, req_id):
+ cache.authz_requests.pop(req_id)
+
+
+class Authz(Resource):
+ """
+ Endpoint for authz requests
+ """
+
+ __urls__ = (
+ "/authz/<string:pdp_id>",
+ "/authz/<string:pdp_id>/<string:subject_name>/<string:object_name>/<string:action_name>",
+ )
+
+ def __init__(self, **kwargs):
+ self.CACHE = kwargs.get("cache")
+ self.INTERFACE_NAME = kwargs.get("interface_name", "interface")
+ self.MANAGER_URL = kwargs.get("manager_url", "http://manager:8080")
+ self.TIMEOUT = 5
+
+ def get(self, pdp_id, subject_name=None, object_name=None, action_name=None):
+ """Get a response on an authorization request
+
+ :param pdp_id: uuid of a tenant or an intra_extension
+ :param subject_name: name of the subject or the request
+ :param object_name: name of the object
+ :param action_name: name of the action
+ :return: {
+ "args": {},
+ "ctx": {
+ "action_name": "4567",
+ "id": "123456",
+ "method": "authz",
+ "object_name": "234567",
+ "subject_name": "123456",
+ "user_id": "admin"
+ },
+ "error": {
+ "code": 500,
+ "description": "",
+ "title": "Moon Error"
+ },
+ "intra_extension_id": "123456",
+ "result": false
+ }
+ :internal_api: authz
+ """
+ try:
+ get_pdp_from_cache(self.CACHE, pdp_id)
+ except exceptions.PdpUnknown:
+ return {
+ "result": False,
+ "message": "Unknown PDP ID."}, 403
+
+ authz_request = create_authz_request(
+ cache=self.CACHE,
+ pdp_id=pdp_id,
+ interface_name=self.INTERFACE_NAME,
+ manager_url=self.MANAGER_URL,
+ subject_name=subject_name,
+ object_name=object_name,
+ action_name=action_name)
+ cpt = 0
+ while True:
+ if cpt > self.TIMEOUT*10:
+ delete_authz_request(self.CACHE, authz_request.request_id)
+ return {"result": False,
+ "message": "Authz request had timed out."}, 500
+ if authz_request.is_authz():
+ if authz_request.final_result == "Grant":
+ delete_authz_request(self.CACHE, authz_request.request_id)
+ return {"result": True, "message": ""}, 200
+ delete_authz_request(self.CACHE, authz_request.request_id)
+ return {"result": False, "message": ""}, 401
+ cpt += 1
+ time.sleep(0.1)
+
+ def patch(self, uuid=None, subject_name=None, object_name=None, action_name=None):
+ """Get a response on an authorization request
+
+ :param uuid: uuid of the authorization request
+ :param subject_name: not used
+ :param object_name: not used
+ :param action_name: not used
+ :request body: a Context object
+ :return: {}
+ :internal_api: authz
+ """
+ if uuid in self.CACHE.authz_requests:
+ self.CACHE.authz_requests[uuid].set_result(pickle.loads(request.data))
+ return "", 201
+ return {"result": False, "message": "The request ID is unknown"}, 500
diff --git a/old/moon_interface/moon_interface/api/generic.py b/old/moon_interface/moon_interface/api/generic.py
new file mode 100644
index 00000000..dadac259
--- /dev/null
+++ b/old/moon_interface/moon_interface/api/generic.py
@@ -0,0 +1,96 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Those API are helping API used to manage the Moon platform.
+"""
+
+from flask_restful import Resource
+import logging
+import moon_interface.api
+from python_moonutilities.security_functions import check_auth
+
+__version__ = "4.3.1"
+
+logger = logging.getLogger("moon.interface.api." + __name__)
+
+
+class Status(Resource):
+ """
+ Endpoint for status requests
+ """
+
+ __urls__ = ("/status", "/status/", "/status/<string:component_id>")
+
+ def get(self, component_id=None):
+ """Retrieve status of all components
+
+ :return: {
+ "orchestrator": {
+ "status": "Running"
+ },
+ "security_router": {
+ "status": "Running"
+ }
+ }
+ """
+ return {"result": True, "message": ""}
+
+
+class API(Resource):
+ """
+ Endpoint for API requests
+ """
+
+ __urls__ = (
+ "/api",
+ "/api/",
+ "/api/<string:group_id>",
+ "/api/<string:group_id>/",
+ "/api/<string:group_id>/<string:endpoint_id>")
+
+ @check_auth
+ def get(self, group_id="", endpoint_id="", user_id=""):
+ """Retrieve all API endpoints or a specific endpoint if endpoint_id is given
+
+ :param group_id: the name of one existing group (ie generic, ...)
+ :param endpoint_id: the name of one existing component (ie Logs, Status, ...)
+ :return: {
+ "group_name": {
+ "endpoint_name": {
+ "description": "a description",
+ "methods": {
+ "get": "description of the HTTP method"
+ },
+ "urls": ('/api', '/api/', '/api/<string:endpoint_id>')
+ }
+ }
+ """
+ __methods = ("get", "post", "put", "delete", "options", "patch")
+ api_list = filter(lambda x: "__" not in x, dir(moon_interface.api))
+ api_desc = dict()
+ for api_name in api_list:
+ api_desc[api_name] = {}
+ group_api_obj = eval("moon_interface.api.{}".format(api_name))
+ api_desc[api_name]["description"] = group_api_obj.__doc__
+ if "__version__" in dir(group_api_obj):
+ api_desc[api_name]["version"] = group_api_obj.__version__
+ object_list = list(filter(lambda x: "__" not in x, dir(group_api_obj)))
+ for obj in map(lambda x: eval("moon_interface.api.{}.{}".format(api_name, x)), object_list):
+ if "__urls__" in dir(obj):
+ api_desc[api_name][obj.__name__] = dict()
+ api_desc[api_name][obj.__name__]["urls"] = obj.__urls__
+ api_desc[api_name][obj.__name__]["methods"] = dict()
+ for _method in filter(lambda x: x in __methods, dir(obj)):
+ docstring = eval("moon_interface.api.{}.{}.{}.__doc__".format(api_name, obj.__name__, _method))
+ api_desc[api_name][obj.__name__]["methods"][_method] = docstring
+ api_desc[api_name][obj.__name__]["description"] = str(obj.__doc__)
+ if group_id in api_desc:
+ if endpoint_id in api_desc[group_id]:
+ return {group_id: {endpoint_id: api_desc[group_id][endpoint_id]}}
+ elif len(endpoint_id) > 0:
+ logger.error("Unknown endpoint_id {}".format(endpoint_id))
+ return {"error": "Unknown endpoint_id {}".format(endpoint_id)}
+ return {group_id: api_desc[group_id]}
+ return api_desc
diff --git a/old/moon_interface/moon_interface/api/update.py b/old/moon_interface/moon_interface/api/update.py
new file mode 100644
index 00000000..e798059c
--- /dev/null
+++ b/old/moon_interface/moon_interface/api/update.py
@@ -0,0 +1,49 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Authz is the endpoint to get authorization response
+"""
+
+from flask import request
+from flask_restful import Resource
+import requests
+import logging
+
+__version__ = "4.3.1"
+
+logger = logging.getLogger("moon.interface.api." + __name__)
+
+
+class Update(Resource):
+ """
+ Endpoint for update requests
+ """
+
+ __urls__ = (
+ "/update",
+ )
+
+ def __init__(self, **kwargs):
+ self.CACHE = kwargs.get("cache")
+ self.INTERFACE_NAME = kwargs.get("interface_name", "interface")
+ self.MANAGER_URL = kwargs.get("manager_url", "http://manager:8080")
+ self.TIMEOUT = 5
+
+ def put(self):
+ try:
+ self.CACHE.update_assignments(
+ request.form.get("policy_id", None),
+ request.form.get("perimeter_id", None),
+ )
+ for project_id in self.CACHE.container_chaining:
+ hostname = self.CACHE.container_chaining[project_id][0]["hostip"]
+ port = self.CACHE.container_chaining[project_id][0]["port"]
+ req = requests.put("http://{}:{}/update".format(hostname, port), request.form)
+ if req.status_code != 200:
+ logger.error("Cannot connect to {} on port {}".format(hostname, port))
+ except Exception as e:
+ logger.exception(e)
+ return {"result": False, "reason": str(e)}
+ return {"result": True}
diff --git a/old/moon_interface/moon_interface/authz_requests.py b/old/moon_interface/moon_interface/authz_requests.py
new file mode 100644
index 00000000..cf50dfe5
--- /dev/null
+++ b/old/moon_interface/moon_interface/authz_requests.py
@@ -0,0 +1,163 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import logging
+import itertools
+import pickle
+import requests
+import sys
+from python_moonutilities import exceptions
+from python_moonutilities.context import Context
+from python_moonutilities.cache import Cache
+
+logger = logging.getLogger("moon.interface.authz_requests")
+
+
+CACHE = Cache()
+CACHE.update()
+
+
+class AuthzRequest:
+
+ result = None
+ final_result = "Deny"
+ req_max_delay = 2
+
+ def __init__(self, ctx, args=None):
+ self.context = Context(ctx, CACHE)
+ self.args = args
+ self.request_id = ctx["request_id"]
+ if ctx['project_id'] not in CACHE.container_chaining:
+ raise exceptions.KeystoneProjectError("Unknown Project ID {}".format(ctx['project_id']))
+ self.container_chaining = CACHE.container_chaining[ctx['project_id']]
+
+ if len(self.container_chaining) == 0 or not all(k in self.container_chaining[0] for k in ("container_id", "hostname", "hostip", "port")):
+ raise exceptions.MoonError('Void container chaining')
+
+ self.pdp_container = self.container_chaining[0]["container_id"]
+ self.run()
+
+ def run(self):
+ self.context.delete_cache()
+ req = None
+ tries = 0
+ success = False
+
+ if "hostip" in self.container_chaining[0]:
+ hostname = self.container_chaining[0]["hostip"]
+ elif "hostname" in self.container_chaining[0]:
+ hostname = self.container_chaining[0]["hostname"]
+ else:
+ raise exceptions.AuthzException(
+ "error in address no hostname or hostip"
+ )
+ tried_hostnames = []
+ while tries < 2:
+ tried_hostnames.append(hostname)
+ try:
+ req = requests.post("http://{}:{}/authz".format(
+ hostname,
+ self.container_chaining[0]["port"],
+ ), data=pickle.dumps(self.context))
+ if req.status_code != 200:
+ raise exceptions.AuthzException(
+ "Receive bad response from Authz function "
+ "(with {} -> {})".format(hostname, req.status_code)
+ )
+ success = True
+ except requests.exceptions.ConnectionError:
+ if tries > 1:
+ logger.error("Cannot connect to {}".format(
+ "http://[{}]:{}/authz".format(
+ ", ".join(tried_hostnames),
+ self.container_chaining[0]["port"]
+ )))
+ except Exception as e:
+ logger.exception(e)
+ else:
+ break
+ hostname = self.container_chaining[0]["hostname"],
+ tries += 1
+
+ if not success:
+ raise exceptions.AuthzException("Cannot connect to Authz function")
+
+ self.context.set_cache(CACHE)
+ if req and len(self.container_chaining) == 1:
+ self.result = pickle.loads(req.content)
+
+ # def __exec_next_state(self, rule_found):
+ # index = self.context.index
+ # current_meta_rule = self.context.headers[index]
+ # current_container = self.__get_container_from_meta_rule(current_meta_rule)
+ # current_container_genre = current_container["genre"]
+ # try:
+ # next_meta_rule = self.context.headers[index + 1]
+ # except IndexError:
+ # next_meta_rule = None
+ # if current_container_genre == "authz":
+ # if rule_found:
+ # return True
+ # pass
+ # if next_meta_rule:
+ # # next will be session if current is deny and session is unset
+ # if self.payload["authz_context"]['pdp_set'][next_meta_rule]['effect'] == "unset":
+ # return notify(
+ # request_id=self.payload["authz_context"]["request_id"],
+ # container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'],
+ # payload=self.payload)
+ # # next will be delegation if current is deny and session is passed or deny and delegation is unset
+ # else:
+ # LOG.error("Delegation is not developed!")
+ #
+ # else:
+ # # else next will be None and the request is sent to router
+ # return self.__return_to_router()
+ # elif current_container_genre == "session":
+ # pass
+ # # next will be next container in headers if current is passed
+ # if self.payload["authz_context"]['pdp_set'][current_meta_rule]['effect'] == "passed":
+ # return notify(
+ # request_id=self.payload["authz_context"]["request_id"],
+ # container_id=self.__get_container_from_meta_rule(next_meta_rule)['container_id'],
+ # payload=self.payload)
+ # # next will be None if current is grant and the request is sent to router
+ # else:
+ # return self.__return_to_router()
+ # elif current_container_genre == "delegation":
+ # LOG.error("Delegation is not developed!")
+ # # next will be authz if current is deny
+ # # next will be None if current is grant and the request is sent to router
+
+ def set_result(self, result):
+ self.result = result
+
+ def is_authz(self):
+ if not self.result:
+ return False
+ authz_results = []
+ for key in self.result.pdp_set:
+ if "effect" in self.result.pdp_set[key]:
+
+ if self.result.pdp_set[key]["effect"] == "grant":
+ # the pdp is a authorization PDP and grant the request
+ authz_results.append(True)
+ elif self.result.pdp_set[key]["effect"] == "passed":
+ # the pdp is not a authorization PDP (session or delegation) and had run normally
+ authz_results.append(True)
+ elif self.result.pdp_set[key]["effect"] == "unset":
+ # the pdp is not a authorization PDP (session or delegation) and had not yep run
+ authz_results.append(True)
+ else:
+ # the pdp is (or not) a authorization PDP and had run badly
+ authz_results.append(False)
+ if list(itertools.accumulate(authz_results, lambda x, y: x & y))[-1]:
+ self.result.pdp_set["effect"] = "grant"
+ if self.result:
+ if self.result.pdp_set["effect"] == "grant":
+ self.final_result = "Grant"
+ return True
+ self.final_result = "Deny"
+ return True
diff --git a/old/moon_interface/moon_interface/http_server.py b/old/moon_interface/moon_interface/http_server.py
new file mode 100644
index 00000000..50bf2a62
--- /dev/null
+++ b/old/moon_interface/moon_interface/http_server.py
@@ -0,0 +1,146 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from flask import Flask, jsonify
+from flask_restful import Resource, Api
+import logging
+from moon_interface import __version__
+from moon_interface.api.generic import Status, API
+from moon_interface.api.authz import Authz
+from moon_interface.api.update import Update
+from moon_interface.authz_requests import CACHE
+from python_moonutilities import configuration, exceptions
+
+logger = logging.getLogger("moon.interface.http_server")
+
+__API__ = (
+ Status, API
+ )
+
+
+class Server:
+ """Base class for HTTP server"""
+
+ def __init__(self, host="localhost", port=80, api=None, **kwargs):
+ """Run a server
+
+ :param host: hostname of the server
+ :param port: port for the running server
+ :param kwargs: optional parameters
+ :return: a running server
+ """
+ self._host = host
+ self._port = port
+ self._api = api
+ self._extra = kwargs
+
+ @property
+ def host(self):
+ return self._host
+
+ @host.setter
+ def host(self, name):
+ self._host = name
+
+ @host.deleter
+ def host(self):
+ self._host = ""
+
+ @property
+ def port(self):
+ return self._port
+
+ @port.setter
+ def port(self, number):
+ self._port = number
+
+ @port.deleter
+ def port(self):
+ self._port = 80
+
+ def run(self):
+ raise NotImplementedError()
+
+
+class Root(Resource):
+ """
+ The root of the web service
+ """
+ __urls__ = ("/", )
+ __methods = ("get", "post", "put", "delete", "options")
+
+ def get(self):
+ tree = {"/": {"methods": ("get",),
+ "description": "List all methods for that service."}}
+ for item in __API__:
+ tree[item.__name__] = {"urls": item.__urls__}
+ _methods = []
+ for _method in self.__methods:
+ if _method in dir(item):
+ _methods.append(_method)
+ tree[item.__name__]["methods"] = _methods
+ tree[item.__name__]["description"] = item.__doc__.strip()
+ return {
+ "version": __version__,
+ "tree": tree
+ }
+
+
+class HTTPServer(Server):
+
+ def __init__(self, host="localhost", port=80, **kwargs):
+ super(HTTPServer, self).__init__(host=host, port=port, **kwargs)
+ self.app = Flask(__name__)
+ self.port = port
+ conf = configuration.get_configuration("components/manager")
+ self.manager_hostname = conf["components/manager"].get("hostname",
+ "manager")
+ self.manager_port = conf["components/manager"].get("port", 80)
+ self.api = Api(self.app)
+ self.__set_route()
+ self.__hook_errors()
+
+ # @self.app.errorhandler(exceptions.AuthException)
+ # def _auth_exception(error):
+ # return {"error": "Unauthorized"}, 401
+
+ def __hook_errors(self):
+
+ def get_404_json(e):
+ return jsonify({"result": False, "code": 404, "description": str(e)}), 404
+ self.app.register_error_handler(404, get_404_json)
+
+ def get_400_json(e):
+ return jsonify({"result": False, "code": 400, "description": str(e)}), 400
+
+ self.app.register_error_handler(400, lambda e: get_400_json)
+ self.app.register_error_handler(403, exceptions.AuthException)
+
+ def __set_route(self):
+ self.api.add_resource(Root, '/')
+
+ for api in __API__:
+ self.api.add_resource(api, *api.__urls__)
+ self.api.add_resource(Authz, *Authz.__urls__,
+ resource_class_kwargs={
+ "cache": CACHE,
+ "interface_name": self.host,
+ "manager_url": "http://{}:{}".format(
+ self.manager_hostname,
+ self.manager_port),
+ }
+ )
+ self.api.add_resource(Update, *Update.__urls__,
+ resource_class_kwargs={
+ "cache": CACHE,
+ "interface_name": self.host,
+ "manager_url": "http://{}:{}".format(
+ self.manager_hostname,
+ self.manager_port),
+ }
+ )
+
+ def run(self):
+ self.app.run(host=self._host, port=self._port, threaded=True) # nosec
diff --git a/old/moon_interface/moon_interface/server.py b/old/moon_interface/moon_interface/server.py
new file mode 100644
index 00000000..29403a6b
--- /dev/null
+++ b/old/moon_interface/moon_interface/server.py
@@ -0,0 +1,43 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import logging
+from python_moonutilities import configuration, exceptions
+from moon_interface.http_server import HTTPServer
+
+logger = logging.getLogger("moon.interface.server")
+
+
+def create_server():
+ configuration.init_logging()
+ try:
+
+ conf = configuration.get_configuration("components/pipeline").get(
+ "components/pipeline", {}).get("interface", {})
+
+ hostname = conf.get("hostname", "pipeline")
+ port = conf.get("port", 80)
+ bind = conf.get("bind", "127.0.0.1")
+ except exceptions.ConsulComponentNotFound:
+ hostname = "interface"
+ bind = "127.0.0.1"
+ port = 80
+
+ configuration.add_component(uuid="pipeline",
+ name=hostname,
+ port=port,
+ bind=bind)
+ logger.info("Starting server with IP {} on port {} bind to {}".format(
+ hostname, port, bind))
+ return HTTPServer(host=bind, port=port)
+
+
+def run():
+ server = create_server()
+ server.run()
+
+
+if __name__ == '__main__':
+ run()
diff --git a/old/moon_interface/requirements.txt b/old/moon_interface/requirements.txt
new file mode 100644
index 00000000..f22b38e7
--- /dev/null
+++ b/old/moon_interface/requirements.txt
@@ -0,0 +1,5 @@
+flask
+flask_restful
+flask_cors
+requests
+python_moonutilities \ No newline at end of file
diff --git a/old/moon_interface/setup.py b/old/moon_interface/setup.py
new file mode 100644
index 00000000..f358c598
--- /dev/null
+++ b/old/moon_interface/setup.py
@@ -0,0 +1,47 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from setuptools import setup, find_packages
+import moon_interface
+
+
+setup(
+
+ name='moon_interface',
+
+ version=moon_interface.__version__,
+
+ packages=find_packages(),
+
+ author="Thomas Duval",
+
+ author_email="thomas.duval@orange.com",
+
+ description="",
+
+ long_description=open('README.md').read(),
+
+ # install_requires= ,
+
+ include_package_data=True,
+
+ url='https://git.opnfv.org/cgit/moon',
+
+ classifiers=[
+ "Programming Language :: Python",
+ "Development Status :: 1 - Planning",
+ "License :: OSI Approved",
+ "Natural Language :: French",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python :: 3",
+ ],
+
+ entry_points={
+ 'console_scripts': [
+ 'moon_interface = moon_interface.server:run',
+ ],
+ }
+
+)
diff --git a/old/moon_interface/tests/unit_python/api/__init__.py b/old/moon_interface/tests/unit_python/api/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/moon_interface/tests/unit_python/api/__init__.py
diff --git a/old/moon_interface/tests/unit_python/api/test_authz.py b/old/moon_interface/tests/unit_python/api/test_authz.py
new file mode 100644
index 00000000..a227a303
--- /dev/null
+++ b/old/moon_interface/tests/unit_python/api/test_authz.py
@@ -0,0 +1,83 @@
+import json
+import conftest
+
+
+def get_json(data):
+ return json.loads(data.decode("utf-8"))
+
+
+def test_authz_true(context):
+
+ import moon_interface.server
+ server = moon_interface.server.create_server()
+ client = server.app.test_client()
+ req = client.get("/authz/{p_id}/{s_id}/{o_id}/{a_id}".format(
+ p_id=context["pdp_id"],
+ s_id=context["subject_name"],
+ o_id=context["object_name"],
+ a_id=context["action_name"],
+ ))
+ assert req.status_code == 200
+ data = get_json(req.data)
+ assert data
+ assert "result" in data
+ assert data['result'] is True
+
+
+def test_authz_false(context):
+ import moon_interface.server
+ server = moon_interface.server.create_server()
+ client = server.app.test_client()
+
+ req = client.get("/authz/{p_id}/{s_id}/{o_id}/{a_id}".format(
+ p_id=None,
+ s_id=context["subject_name"],
+ o_id=context["object_name"],
+ a_id=context["action_name"],
+ ))
+ assert req.status_code == 403
+ data = get_json(req.data)
+ assert data
+ assert "result" in data
+ assert data['result'] is False
+
+
+def test_authz_effect_unset(context, set_consul_and_db):
+ import moon_interface.server
+ server = moon_interface.server.create_server()
+ client = server.app.test_client()
+
+ set_consul_and_db.register_uri(
+ 'POST', 'http://127.0.0.1:8081/authz',
+ content=conftest.get_pickled_context_invalid()
+ )
+
+ req = client.get("/authz/{p_id}/{s_id}/{o_id}/{a_id}".format(
+ p_id=context["pdp_id"],
+ s_id=context["subject_name"],
+ o_id=context["object_name"],
+ a_id=context["action_name"],
+ ))
+ assert req.status_code == 401
+ data = get_json(req.data)
+ assert data
+ assert "result" in data
+ assert data['result'] is False
+
+
+def test_authz_invalid_ip(context, set_consul_and_db):
+ import moon_interface.server
+ server = moon_interface.server.create_server()
+ client = server.app.test_client()
+
+ set_consul_and_db.register_uri(
+ 'POST', 'http://127.0.0.1:8081/authz', status_code=500
+ )
+
+ req = client.get("/authz/{p_id}/{s_id}/{o_id}/{a_id}".format(
+ p_id=context["pdp_id"],
+ s_id=context["subject_name"],
+ o_id=context["object_name"],
+ a_id=context["action_name"],
+ ))
+ assert req.status_code == 403
diff --git a/old/moon_interface/tests/unit_python/conftest.py b/old/moon_interface/tests/unit_python/conftest.py
new file mode 100644
index 00000000..f6b204e6
--- /dev/null
+++ b/old/moon_interface/tests/unit_python/conftest.py
@@ -0,0 +1,689 @@
+import base64
+import json
+import os
+import pickle
+import pytest
+import requests_mock
+from uuid import uuid4
+
+CONF = {
+ "openstack": {
+ "keystone": {
+ "url": "http://keystone:5000/v3",
+ "user": "admin",
+ "check_token": False,
+ "password": "p4ssw0rd",
+ "domain": "default",
+ "certificate": False,
+ "project": "admin"
+ }
+ },
+ "components": {
+ "wrapper": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_wrapper:v4.3",
+ "timeout": 5,
+ "hostname": "wrapper"
+ },
+ "manager": {
+ "bind": "0.0.0.0",
+ "port": 8082,
+ "container": "wukongsun/moon_manager:v4.3",
+ "hostname": "manager"
+ },
+ "port_start": 31001,
+ "orchestrator": {
+ "bind": "0.0.0.0",
+ "port": 8083,
+ "container": "wukongsun/moon_orchestrator:v4.3",
+ "hostname": "orchestrator"
+ },
+ "pipeline": {
+ "interface": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_interface:v4.3",
+ "hostname": "interface"
+ },
+ "authz": {
+ "bind": "0.0.0.0",
+ "port": 8081,
+ "container": "wukongsun/moon_authz:v4.3",
+ "hostname": "authz"
+ },
+ }
+ },
+ "logging": {
+ "handlers": {
+ "file": {
+ "filename": "/tmp/moon.log",
+ "class": "logging.handlers.RotatingFileHandler",
+ "level": "DEBUG",
+ "formatter": "custom",
+ "backupCount": 3,
+ "maxBytes": 1048576
+ },
+ "console": {
+ "class": "logging.StreamHandler",
+ "formatter": "brief",
+ "level": "INFO",
+ "stream": "ext://sys.stdout"
+ }
+ },
+ "formatters": {
+ "brief": {
+ "format": "%(levelname)s %(name)s %(message)-30s"
+ },
+ "custom": {
+ "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s"
+ }
+ },
+ "root": {
+ "handlers": [
+ "console"
+ ],
+ "level": "ERROR"
+ },
+ "version": 1,
+ "loggers": {
+ "moon": {
+ "handlers": [
+ "console",
+ "file"
+ ],
+ "propagate": False,
+ "level": "DEBUG"
+ }
+ }
+ },
+ "slave": {
+ "name": None,
+ "master": {
+ "url": None,
+ "login": None,
+ "password": None
+ }
+ },
+ "docker": {
+ "url": "tcp://172.88.88.1:2376",
+ "network": "moon"
+ },
+ "database": {
+ "url": "sqlite:///database.db",
+ # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon",
+ "driver": "sql"
+ },
+ "messenger": {
+ "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon"
+ }
+}
+
+COMPONENTS = (
+ "logging",
+ "openstack/keystone",
+ "database",
+ "slave",
+ "components/manager",
+ "components/orchestrator",
+ "components/pipeline",
+)
+
+CONTEXT = {
+ "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd",
+ "project_id": "a64beb1cc224474fb4badd43173e7101",
+ "subject_name": "testuser",
+ "object_name": "vm1",
+ "action_name": "boot",
+ "request_id": uuid4().hex,
+ "interface_name": "interface",
+ "manager_url": "http://{}:{}".format(
+ CONF["components"]["manager"]["hostname"],
+ CONF["components"]["manager"]["port"]
+ ),
+ "cookie": uuid4().hex
+ }
+
+
+def get_b64_conf(component=None):
+ if component == "components":
+ return base64.b64encode(
+ json.dumps(CONF["components"]).encode('utf-8')+b"\n").decode('utf-8')
+ elif component in CONF:
+ return base64.b64encode(
+ json.dumps(
+ CONF[component]).encode('utf-8')+b"\n").decode('utf-8')
+ elif not component:
+ return base64.b64encode(
+ json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8')
+ elif "/" in component:
+ key1, _, key2 = component.partition("/")
+ return base64.b64encode(
+ json.dumps(
+ CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8')
+
+
+MOCK_URLS = [
+ ('GET', 'http://consul:8500/v1/kv/components?recurse=true',
+ {'json': {"Key": key, "Value": get_b64_conf(key)}
+ for key in COMPONENTS}
+ ),
+ ('POST', 'http://keystone:5000/v3/auth/tokens',
+ {'headers': {'X-Subject-Token': "111111111"}}),
+ ('DELETE', 'http://keystone:5000/v3/auth/tokens',
+ {'headers': {'X-Subject-Token': "111111111"}}),
+ ('POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default',
+ {'json': {"users": {}}}),
+ ('GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default',
+ {'json': {"users": {}}}),
+ ('POST', 'http://keystone:5000/v3/users/',
+ {'json': {"users": [{
+ "id": "1111111111111"
+ }]}}),
+]
+
+
+@pytest.fixture
+def db():
+ return CONF['database']
+
+
+@pytest.fixture
+def context():
+ return CONTEXT
+
+
+def set_env_variables():
+ os.environ['UUID'] = "1111111111"
+ os.environ['TYPE'] = "authz"
+ os.environ['PORT'] = "8081"
+ os.environ['PDP_ID'] = "b3d3e18abf3340e8b635fd49e6634ccd"
+ os.environ['META_RULE_ID'] = "f8f49a779ceb47b3ac810f01ef71b4e0"
+ os.environ['KEYSTONE_PROJECT_ID'] = CONTEXT['project_id']
+
+
+def get_pickled_context():
+ from python_moonutilities.context import Context
+ from python_moonutilities.cache import Cache
+ CACHE = Cache()
+ CACHE.update()
+ _context = Context(context(), CACHE)
+ _context.increment_index()
+ _context.pdp_set['effect'] = 'grant'
+ _context.pdp_set[os.environ['META_RULE_ID']]['effect'] = 'grant'
+ print(_context.pdp_set)
+ return pickle.dumps(_context)
+
+def get_pickled_context_invalid():
+ from python_moonutilities.context import Context
+ from python_moonutilities.cache import Cache
+ CACHE = Cache()
+ CACHE.update()
+ _context = Context(context(), CACHE)
+ _context.increment_index()
+ _context.pdp_set['effect'] = 'invalid'
+ _context.pdp_set[os.environ['META_RULE_ID']]['effect'] = 'invalid'
+ print(_context.pdp_set)
+ return pickle.dumps(_context)
+
+
+
+@pytest.fixture(autouse=True)
+def set_consul_and_db(monkeypatch):
+ """ Modify the response from Requests module
+ """
+ set_env_variables()
+ with requests_mock.Mocker(real_http=True) as m:
+ for component in COMPONENTS:
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/{}'.format(component),
+ json=[{'Key': component, 'Value': get_b64_conf(component)}]
+ )
+ # for _data in MOCK_URLS:
+ # m.register_uri(_data[0], _data[1], **_data[2])
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/components?recurse=true',
+ json=[
+ {"Key": key, "Value": get_b64_conf(key)} for key in COMPONENTS
+ ],
+ )
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/plugins/authz',
+ json=[
+ {
+ "LockIndex": 0,
+ "Key": "plugins/authz",
+ "Flags": 0,
+ "Value": "eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0=",
+ "CreateIndex": 14,
+ "ModifyIndex": 656
+ }
+ ],
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/auth/tokens',
+ headers={'X-Subject-Token': "111111111"}
+ )
+ m.register_uri(
+ 'DELETE', 'http://keystone:5000/v3/auth/tokens',
+ headers={'X-Subject-Token': "111111111"}
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default',
+ json={"users": {}}
+ )
+ m.register_uri(
+ 'GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default',
+ json={"users": {}}
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/users/',
+ json={"users": [{
+ "id": "1111111111111"
+ }]}
+ )
+ m.register_uri(
+ 'GET', 'http://orchestrator:8083/pods',
+ json={
+ "pods": {
+ "721760dd-de5f-11e7-8001-3863bbb766f3": [
+ {
+ "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd",
+ "port": 8080,
+ "genre": "interface",
+ "name": "interface-paltry",
+ "keystone_project_id": "a64beb1cc224474fb4badd43173e7101",
+ "namespace": "moon",
+ "container": "wukongsun/moon_interface:v4.3"
+ },
+ {
+ "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd",
+ "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "port": 8081,
+ "genre": "authz",
+ "name": "authz-economic",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "keystone_project_id": "a64beb1cc224474fb4badd43173e7101",
+ "namespace": "moon",
+ "container": "wukongsun/moon_authz:v4.3"
+ }
+ ],
+ "232399a4-de5f-11e7-8001-3863bbb766f3": [
+ {
+ "port": 8080,
+ "namespace": "moon",
+ "name": "wrapper-paltry",
+ "container": "wukongsun/moon_wrapper:v4.3.1"
+ }
+ ]
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://orchestrator:8083/pods/authz-economic',
+ json={
+ "pods": None
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/pdp',
+ json={
+ "pdps": {
+ "b3d3e18abf3340e8b635fd49e6634ccd": {
+ "description": "test",
+ "security_pipeline": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0"
+ ],
+ "name": "pdp_rbac",
+ "keystone_project_id": "a64beb1cc224474fb4badd43173e7101"
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies',
+ json={
+ "policies": {
+ "f8f49a779ceb47b3ac810f01ef71b4e0": {
+ "name": "RBAC policy example",
+ "model_id": "cd923d8633ff4978ab0e99938f5153d6",
+ "description": "test",
+ "genre": "authz"
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/models',
+ json={
+ "models": {
+ "cd923d8633ff4978ab0e99938f5153d6": {
+ "name": "RBAC",
+ "meta_rules": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0"
+ ],
+ "description": "test"
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/meta_rules',
+ json={
+ "meta_rules": {
+ "f8f49a779ceb47b3ac810f01ef71b4e0": {
+ "subject_categories": [
+ "14e6ae0ba34d458b876c791b73aa17bd"
+ ],
+ "action_categories": [
+ "241a2a791554421a91c9f1bc564aa94d"
+ ],
+ "description": "",
+ "name": "rbac",
+ "object_categories": [
+ "6d48500f639d4c2cab2b1f33ef93a1e8"
+ ]
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/subjects',
+ json={
+ "subjects": {
+ "89ba91c18dd54abfbfde7a66936c51a6": {
+ "description": "test",
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ],
+ "name": "testuser",
+ "email": "mail",
+ "id": "89ba91c18dd54abfbfde7a66936c51a6",
+ "extra": {}
+ },
+ "31fd15ad14784a9696fcc887dddbfaf9": {
+ "description": "test",
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ],
+ "name": "adminuser",
+ "email": "mail",
+ "id": "31fd15ad14784a9696fcc887dddbfaf9",
+ "extra": {}
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/objects',
+ json={
+ "objects": {
+ "67b8008a3f8d4f8e847eb628f0f7ca0e": {
+ "name": "vm1",
+ "description": "test",
+ "id": "67b8008a3f8d4f8e847eb628f0f7ca0e",
+ "extra": {},
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ]
+ },
+ "9089b3d2ce5b4e929ffc7e35b55eba1a": {
+ "name": "vm0",
+ "description": "test",
+ "id": "9089b3d2ce5b4e929ffc7e35b55eba1a",
+ "extra": {},
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ]
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/actions',
+ json={
+ "actions": {
+ "cdb3df220dc05a6ea3334b994827b068": {
+ "name": "boot",
+ "description": "test",
+ "id": "cdb3df220dc04a6ea3334b994827b068",
+ "extra": {},
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ]
+ },
+ "cdb3df220dc04a6ea3334b994827b068": {
+ "name": "stop",
+ "description": "test",
+ "id": "cdb3df220dc04a6ea3334b994827b068",
+ "extra": {},
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ]
+ },
+ "9f5112afe9b34a6c894eb87246ccb7aa": {
+ "name": "start",
+ "description": "test",
+ "id": "9f5112afe9b34a6c894eb87246ccb7aa",
+ "extra": {},
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ]
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/subject_assignments',
+ json={
+ "subject_assignments": {
+ "826c1156d0284fc9b4b2ddb279f63c52": {
+ "category_id": "14e6ae0ba34d458b876c791b73aa17bd",
+ "assignments": [
+ "24ea95256c5f4c888c1bb30a187788df",
+ "6b227b77184c48b6a5e2f3ed1de0c02a",
+ "31928b17ec90438ba5a2e50ae7650e63",
+ "4e60f554dd3147af87595fb6b37dcb13",
+ "7a5541b63a024fa88170a6b59f99ccd7",
+ "dd2af27812f742029d289df9687d6126"
+ ],
+ "id": "826c1156d0284fc9b4b2ddb279f63c52",
+ "subject_id": "89ba91c18dd54abfbfde7a66936c51a6",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ },
+ "7407ffc1232944279b0cbcb0847c86f7": {
+ "category_id": "315072d40d774c43a89ff33937ed24eb",
+ "assignments": [
+ "6b227b77184c48b6a5e2f3ed1de0c02a",
+ "31928b17ec90438ba5a2e50ae7650e63",
+ "7a5541b63a024fa88170a6b59f99ccd7",
+ "dd2af27812f742029d289df9687d6126"
+ ],
+ "id": "7407ffc1232944279b0cbcb0847c86f7",
+ "subject_id": "89ba91c18dd54abfbfde7a66936c51a6",
+ "policy_id": "3e65256389b448cb9897917ea235f0bb"
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/object_assignments',
+ json={
+ "object_assignments": {
+ "201ad05fd3f940948b769ab9214fe295": {
+ "object_id": "9089b3d2ce5b4e929ffc7e35b55eba1a",
+ "assignments": [
+ "030fbb34002e4236a7b74eeb5fd71e35",
+ "06bcb8655b9d46a9b90e67ef7c825b50",
+ "34eb45d7f46d4fb6bc4965349b8e4b83",
+ "4b7793dbae434c31a77da9d92de9fa8c"
+ ],
+ "id": "201ad05fd3f940948b769ab9214fe295",
+ "category_id": "6d48500f639d4c2cab2b1f33ef93a1e8",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ },
+ "90c5e86f8be34c0298fbd1973e4fb043": {
+ "object_id": "67b8008a3f8d4f8e847eb628f0f7ca0e",
+ "assignments": [
+ "a098918e915b4b12bccb89f9a3f3b4e4",
+ "06bcb8655b9d46a9b90e67ef7c825b50",
+ "7dc76c6142af47c88b60cc2b0df650ba",
+ "4b7793dbae434c31a77da9d92de9fa8c"
+ ],
+ "id": "90c5e86f8be34c0298fbd1973e4fb043",
+ "category_id": "33aece52d45b4474a20dc48a76800daf",
+ "policy_id": "3e65256389b448cb9897917ea235f0bb"
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/action_assignments',
+ json={
+ "action_assignments": {
+ "2128e3ffbd1c4ef5be515d625745c2d4": {
+ "category_id": "241a2a791554421a91c9f1bc564aa94d",
+ "action_id": "cdb3df220dc05a6ea3334b994827b068",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "id": "2128e3ffbd1c4ef5be515d625745c2d4",
+ "assignments": [
+ "570c036781e540dc9395b83098c40ba7",
+ "7fe17d7a2e3542719f8349c3f2273182",
+ "015ca6f40338422ba3f692260377d638",
+ "23d44c17bf88480f83e8d57d2aa1ea79"
+ ]
+ },
+ "cffb98852f3a4110af7a0ddfc4e19201": {
+ "category_id": "4a2c5abaeaf644fcaf3ca8df64000d53",
+ "action_id": "cdb3df220dc04a6ea3334b994827b068",
+ "policy_id": "3e65256389b448cb9897917ea235f0bb",
+ "id": "cffb98852f3a4110af7a0ddfc4e19201",
+ "assignments": [
+ "570c036781e540dc9395b83098c40ba7",
+ "7fe17d7a2e3542719f8349c3f2273182",
+ "015ca6f40338422ba3f692260377d638",
+ "23d44c17bf88480f83e8d57d2aa1ea79"
+ ]
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/subject_assignments/89ba91c18dd54abfbfde7a66936c51a6',
+ json={
+ "subject_assignments": {
+ "826c1156d0284fc9b4b2ddb279f63c52": {
+ "category_id": "14e6ae0ba34d458b876c791b73aa17bd",
+ "assignments": [
+ "24ea95256c5f4c888c1bb30a187788df",
+ "6b227b77184c48b6a5e2f3ed1de0c02a",
+ "31928b17ec90438ba5a2e50ae7650e63",
+ "4e60f554dd3147af87595fb6b37dcb13",
+ "7a5541b63a024fa88170a6b59f99ccd7",
+ "dd2af27812f742029d289df9687d6126"
+ ],
+ "id": "826c1156d0284fc9b4b2ddb279f63c52",
+ "subject_id": "89ba91c18dd54abfbfde7a66936c51a6",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/object_assignments/67b8008a3f8d4f8e847eb628f0f7ca0e',
+ json={
+ "object_assignments": {
+ "201ad05fd3f940948b769ab9214fe295": {
+ "object_id": "67b8008a3f8d4f8e847eb628f0f7ca0e",
+ "assignments": [
+ "030fbb34002e4236a7b74eeb5fd71e35",
+ "06bcb8655b9d46a9b90e67ef7c825b50",
+ "34eb45d7f46d4fb6bc4965349b8e4b83",
+ "4b7793dbae434c31a77da9d92de9fa8c"
+ ],
+ "id": "201ad05fd3f940948b769ab9214fe295",
+ "category_id": "6d48500f639d4c2cab2b1f33ef93a1e8",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/action_assignments/cdb3df220dc05a6ea3334b994827b068',
+ json={
+ "action_assignments": {
+ "2128e3ffbd1c4ef5be515d625745c2d4": {
+ "category_id": "241a2a791554421a91c9f1bc564aa94d",
+ "action_id": "cdb3df220dc05a6ea3334b994827b068",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "id": "2128e3ffbd1c4ef5be515d625745c2d4",
+ "assignments": [
+ "570c036781e540dc9395b83098c40ba7",
+ "7fe17d7a2e3542719f8349c3f2273182",
+ "015ca6f40338422ba3f692260377d638",
+ "23d44c17bf88480f83e8d57d2aa1ea79"
+ ]
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/rules',
+ json={
+ "rules": {
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "rules": [
+ {
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "rule": [
+ "24ea95256c5f4c888c1bb30a187788df",
+ "030fbb34002e4236a7b74eeb5fd71e35",
+ "570c036781e540dc9395b83098c40ba7"
+ ],
+ "enabled": True,
+ "id": "0201a2bcf56943c1904dbac016289b71",
+ "instructions": [
+ {
+ "decision": "grant"
+ }
+ ],
+ "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ },
+ {
+ "policy_id": "ecc2451c494e47b5bca7250cd324a360",
+ "rule": [
+ "54f574cd2043468da5d65e4f6ed6e3c9",
+ "6559686961a3490a978f246ac9f85fbf",
+ "ac0d1f600bf447e8bd2f37b7cc47f2dc"
+ ],
+ "enabled": True,
+ "id": "a83fed666af8436192dfd8b3c83a6fde",
+ "instructions": [
+ {
+ "decision": "grant"
+ }
+ ],
+ "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ }
+ ]
+ }
+ }
+ )
+ m.register_uri(
+ 'POST', 'http://127.0.0.1:8081/authz',
+ content=get_pickled_context()
+ )
+ # from moon_db.db_manager import init_engine, run
+ # engine = init_engine()
+ # run("upgrade", logging.getLogger("db_manager"), engine)
+ yield m
+ # os.unlink(CONF['database']['url'].replace("sqlite:///", ""))
+
+
diff --git a/old/moon_interface/tests/unit_python/requirements.txt b/old/moon_interface/tests/unit_python/requirements.txt
new file mode 100644
index 00000000..21975ce3
--- /dev/null
+++ b/old/moon_interface/tests/unit_python/requirements.txt
@@ -0,0 +1,5 @@
+flask
+flask_cors
+flask_restful
+python_moondb
+python_moonutilities \ No newline at end of file
diff --git a/old/moon_manager/.gitignore b/old/moon_manager/.gitignore
new file mode 100644
index 00000000..894a44cc
--- /dev/null
+++ b/old/moon_manager/.gitignore
@@ -0,0 +1,104 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
diff --git a/old/moon_manager/Changelog b/old/moon_manager/Changelog
new file mode 100644
index 00000000..1fb9ac08
--- /dev/null
+++ b/old/moon_manager/Changelog
@@ -0,0 +1,73 @@
+# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+CHANGES
+=======
+
+1.0.0
+-----
+- First version of the manager
+
+2.0.0
+-----
+- Version built inside the Keystone component
+
+3.0.0
+-----
+- Version built outside the Keystone component
+
+4.0.0
+-----
+- First micro-architecture version
+
+4.5.2
+-----
+- use the threading capability of Flask app
+- set the number of manager to 1
+- update to the latest version of the python-moondb library
+
+4.5.2-1
+-----
+- integrating validation to send mandatory key names
+
+4.5.3
+-----
+- Removing try catch from all requets to allow raised exception to be passed to http server, to send actual error to client side
+- fixing test cases to assert on the expected exception after removing try-catch
+- allow 404 to be catched from our side instead of flask itself
+- revert the params in the get/post/patch/delete to be by default = None, so that we could catch the param if it was None
+instead of having not found url if the param is mandatory
+
+4.5.4
+-----
+- fixing test cases after validation dependencies added in moondb
+
+4.5.5
+-----
+- removing validation on meta_rule categories
+- Update to python_moonutilities 1.4.17 and fix tests
+- adding extra test cases for update requests
+- adding None to requests ( to avoid request not found)
+- removing validation on categories, meta_rules so that can be added empty
+
+4.5.5-1
+-------
+- Update to python_moonutilities 1.4.18
+
+4.5.5-2
+-------
+- Update to python_moonutilities 1.4.19
+
+4.5.6
+----
+apply pyLint
+adding extra test cases for policy update
+- separate perimeter add/update with validation
+
+4.6.0
+-----
+- Add a connection to the Update endpoint in Wrapper
+>>>>>>> Stashed changes
diff --git a/old/moon_manager/Dockerfile b/old/moon_manager/Dockerfile
new file mode 100644
index 00000000..d264a113
--- /dev/null
+++ b/old/moon_manager/Dockerfile
@@ -0,0 +1,15 @@
+FROM python:3
+
+LABEL Name=Manager
+LABEL Description="Manager component for the Moon platform"
+LABEL Maintainer="Thomas Duval"
+LABEL Url="https://wiki.opnfv.org/display/moon/Moon+Project+Proposal"
+
+USER root
+
+ADD . /root
+WORKDIR /root/
+RUN pip3 install --no-cache-dir -r requirements.txt
+RUN pip3 install --no-cache-dir .
+
+CMD ["python3", "-m", "moon_manager"] \ No newline at end of file
diff --git a/old/moon_manager/LICENSE b/old/moon_manager/LICENSE
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/old/moon_manager/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/old/moon_manager/MANIFEST.in b/old/moon_manager/MANIFEST.in
new file mode 100644
index 00000000..cf4d2e4e
--- /dev/null
+++ b/old/moon_manager/MANIFEST.in
@@ -0,0 +1,9 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+include README.md
+include LICENSE
+include setup.py
+include requirements.txt
diff --git a/old/moon_manager/README.md b/old/moon_manager/README.md
new file mode 100644
index 00000000..c74ccc28
--- /dev/null
+++ b/old/moon_manager/README.md
@@ -0,0 +1,8 @@
+# moon_manager
+
+This package contains the core module for the Moon project
+It is designed to provide authorization features to all OpenStack components.
+
+For any other information, refer to the parent project:
+
+ https://git.opnfv.org/moon
diff --git a/old/moon_manager/moon_manager/__init__.py b/old/moon_manager/moon_manager/__init__.py
new file mode 100644
index 00000000..f0887748
--- /dev/null
+++ b/old/moon_manager/moon_manager/__init__.py
@@ -0,0 +1,6 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+__version__ = "4.6.0"
diff --git a/old/moon_manager/moon_manager/__main__.py b/old/moon_manager/moon_manager/__main__.py
new file mode 100644
index 00000000..4fed8d10
--- /dev/null
+++ b/old/moon_manager/moon_manager/__main__.py
@@ -0,0 +1,4 @@
+from moon_manager.server import create_server
+
+server = create_server()
+server.run()
diff --git a/old/moon_manager/moon_manager/api/__init__.py b/old/moon_manager/moon_manager/api/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/__init__.py
diff --git a/old/moon_manager/moon_manager/api/assignments.py b/old/moon_manager/moon_manager/api/assignments.py
new file mode 100644
index 00000000..9bc54b2d
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/assignments.py
@@ -0,0 +1,391 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Assignments allow to connect data with elements of perimeter
+
+"""
+import flask
+from flask import request
+from flask_restful import Resource
+import logging
+import requests
+from python_moonutilities.security_functions import check_auth
+from python_moondb.core import PolicyManager
+from python_moonutilities.security_functions import validate_input
+
+__version__ = "4.3.2"
+
+logger = logging.getLogger("moon.manager.api." + __name__)
+
+
+def invalidate_data_in_slaves(
+ policy_id,
+ perimeter_id,
+ category_id,
+ data_id):
+ slaves = requests.get("http://{}/slaves".format(request.host)).json().get("slaves")
+ for slave in slaves:
+ if not slave.get("configured", False):
+ continue
+ try:
+ update = requests.put("http://{}:{}/update".format(
+ slave.get("wrapper_name"), slave.get("internal_port")),
+ data={
+ "policy_id": policy_id,
+ "perimeter_id": perimeter_id,
+ "category_id": category_id,
+ "data_id": data_id
+ },
+ timeout=1
+ )
+ logger.info("result {} {}:{} = {}".format(
+ update.status_code,
+ slave.get("wrapper_name"),
+ slave.get("internal_port"),
+ update.text))
+ except requests.exceptions.ConnectionError:
+ logger.warning("Cannot reach {}:{}".format(slave.get("wrapper_name"), slave.get("port")))
+
+
+class SubjectAssignments(Resource):
+ """
+ Endpoint for subject assignment requests
+ """
+
+ __urls__ = (
+ "/policies/<string:uuid>/subject_assignments",
+ "/policies/<string:uuid>/subject_assignments/",
+ "/policies/<string:uuid>/subject_assignments/<string:perimeter_id>",
+ "/policies/<string:uuid>/subject_assignments/<string:perimeter_id>/<string:category_id>",
+ "/policies/<string:uuid>/subject_assignments/<string:perimeter_id>/<string:category_id>/<string:data_id>",
+ )
+
+ @validate_input("get", kwargs_state=[True, False, False, False, False])
+ @check_auth
+ def get(self, uuid=None, perimeter_id=None, category_id=None,
+ data_id=None, user_id=None):
+ """Retrieve all subject assignments or a specific one for a given policy
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: uuid of the subject
+ :param category_id: uuid of the subject category
+ :param data_id: uuid of the subject scope (not used here)
+ :param user_id: user ID who do the request
+ :return: {
+ "subject_data_id": {
+ "policy_id": "ID of the policy",
+ "subject_id": "ID of the subject",
+ "category_id": "ID of the category",
+ "assignments": "Assignments list (list of data_id)",
+ }
+ }
+ :internal_api: get_subject_assignments
+ """
+
+ data = PolicyManager.get_subject_assignments(
+ user_id=user_id, policy_id=uuid,
+ subject_id=perimeter_id, category_id=category_id)
+
+ return {"subject_assignments": data}
+
+ @validate_input("post", kwargs_state=[True, False, False, False, False],
+ body_state={"id": True, "category_id": True, "data_id": True})
+ @check_auth
+ def post(self, uuid=None, perimeter_id=None, category_id=None,
+ data_id=None, user_id=None):
+ """Create a subject assignment.
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: uuid of the subject (not used here)
+ :param category_id: uuid of the subject category (not used here)
+ :param data_id: uuid of the subject scope (not used here)
+ :param user_id: user ID who do the request
+ :request body: {
+ "id": "UUID of the subject (mandatory)",
+ "category_id": "UUID of the category (mandatory)"
+ "data_id": "UUID of the scope (mandatory)"
+ }
+ :return: {
+ "subject_data_id": {
+ "policy_id": "ID of the policy",
+ "subject_id": "ID of the subject (mandatory)",
+ "category_id": "ID of the category (mandatory)",
+ "assignments": "Assignments list (list of data_id)",
+ }
+ }
+ :internal_api: update_subject_assignment
+ """
+ data_id = request.json.get("data_id")
+ category_id = request.json.get("category_id")
+ perimeter_id = request.json.get("id")
+ data = PolicyManager.add_subject_assignment(
+ user_id=user_id, policy_id=uuid,
+ subject_id=perimeter_id, category_id=category_id,
+ data_id=data_id)
+ invalidate_data_in_slaves(
+ policy_id=uuid,
+ perimeter_id=perimeter_id,
+ category_id=category_id,
+ data_id=data_id)
+
+ return {"subject_assignments": data}
+
+ @validate_input("delete", kwargs_state=[True, True, True, True, False])
+ @check_auth
+ def delete(self, uuid=None, perimeter_id=None, category_id=None,
+ data_id=None, user_id=None):
+ """Delete a subject assignment for a given policy
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: uuid of the subject
+ :param category_id: uuid of the subject category
+ :param data_id: uuid of the subject scope
+ :param user_id: user ID who do the request
+ :return: {
+ "result": "True or False",
+ "message": "optional message"
+ }
+ :internal_api: delete_subject_assignment
+ """
+
+ data = PolicyManager.delete_subject_assignment(
+ user_id=user_id, policy_id=uuid,
+ subject_id=perimeter_id, category_id=category_id,
+ data_id=data_id)
+ invalidate_data_in_slaves(
+ policy_id=uuid,
+ perimeter_id=perimeter_id,
+ category_id=category_id,
+ data_id=data_id)
+
+ return {"result": True}
+
+
+class ObjectAssignments(Resource):
+ """
+ Endpoint for object assignment requests
+ """
+
+ __urls__ = (
+ "/policies/<string:uuid>/object_assignments",
+ "/policies/<string:uuid>/object_assignments/",
+ "/policies/<string:uuid>/object_assignments/<string:perimeter_id>",
+ "/policies/<string:uuid>/object_assignments/<string:perimeter_id>/<string:category_id>",
+ "/policies/<string:uuid>/object_assignments/<string:perimeter_id>/<string:category_id>/<string:data_id>",
+ )
+
+ @validate_input("get", kwargs_state=[True, False, False, False, False])
+ @check_auth
+ def get(self, uuid=None, perimeter_id=None, category_id=None,
+ data_id=None, user_id=None):
+ """Retrieve all object assignment or a specific one for a given policy
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: uuid of the object
+ :param category_id: uuid of the object category
+ :param data_id: uuid of the object scope (not used here)
+ :param user_id: user ID who do the request
+ :return: {
+ "object_data_id": {
+ "policy_id": "ID of the policy",
+ "object_id": "ID of the object",
+ "category_id": "ID of the category",
+ "assignments": "Assignments list (list of data_id)",
+ }
+ }
+ :internal_api: get_object_assignments
+ """
+
+ data = PolicyManager.get_object_assignments(
+ user_id=user_id, policy_id=uuid,
+ object_id=perimeter_id, category_id=category_id)
+
+ return {"object_assignments": data}
+
+ @validate_input("post", kwargs_state=[True, False, False, False, False],
+ body_state={"id": True, "category_id": True, "data_id": True})
+ @check_auth
+ def post(self, uuid=None, perimeter_id=None, category_id=None,
+ data_id=None, user_id=None):
+ """Create an object assignment.
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: uuid of the object (not used here)
+ :param category_id: uuid of the object category (not used here)
+ :param data_id: uuid of the object scope (not used here)
+ :param user_id: user ID who do the request
+ :request body: {
+ "id": "UUID of the action (mandatory)",
+ "category_id": "UUID of the category (mandatory)",
+ "data_id": "UUID of the scope (mandatory)"
+ }
+ :return: {
+ "object_data_id": {
+ "policy_id": "ID of the policy",
+ "object_id": "ID of the object",
+ "category_id": "ID of the category",
+ "assignments": "Assignments list (list of data_id)",
+ }
+ }
+ :internal_api: update_object_assignment
+ """
+
+ data_id = request.json.get("data_id")
+ category_id = request.json.get("category_id")
+ perimeter_id = request.json.get("id")
+ data = PolicyManager.add_object_assignment(
+ user_id=user_id, policy_id=uuid,
+ object_id=perimeter_id, category_id=category_id,
+ data_id=data_id)
+ invalidate_data_in_slaves(
+ policy_id=uuid,
+ perimeter_id=perimeter_id,
+ category_id=category_id,
+ data_id=data_id)
+
+ return {"object_assignments": data}
+
+ @validate_input("delete", kwargs_state=[True, True, True, True, False])
+ @check_auth
+ def delete(self, uuid=None, perimeter_id=None, category_id=None,
+ data_id=None, user_id=None):
+ """Delete a object assignment for a given policy
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: uuid of the object
+ :param category_id: uuid of the object category
+ :param data_id: uuid of the object scope
+ :param user_id: user ID who do the request
+ :return: {
+ "result": "True or False",
+ "message": "optional message"
+ }
+ :internal_api: delete_object_assignment
+ """
+ data = PolicyManager.delete_object_assignment(
+ user_id=user_id, policy_id=uuid,
+ object_id=perimeter_id, category_id=category_id,
+ data_id=data_id)
+ invalidate_data_in_slaves(
+ policy_id=uuid,
+ perimeter_id=perimeter_id,
+ category_id=category_id,
+ data_id=data_id)
+
+ return {"result": True}
+
+
+class ActionAssignments(Resource):
+ """
+ Endpoint for action assignment requests
+ """
+
+ __urls__ = (
+ "/policies/<string:uuid>/action_assignments",
+ "/policies/<string:uuid>/action_assignments/",
+ "/policies/<string:uuid>/action_assignments/<string:perimeter_id>",
+ "/policies/<string:uuid>/action_assignments/<string:perimeter_id>/<string:category_id>",
+ "/policies/<string:uuid>/action_assignments/<string:perimeter_id>/<string:category_id>/<string:data_id>",
+ )
+
+ @validate_input("get", kwargs_state=[True, False, False, False, False])
+ @check_auth
+ def get(self, uuid=None, perimeter_id=None, category_id=None,
+ data_id=None, user_id=None):
+ """Retrieve all action assignment or a specific one for a given policy
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: uuid of the action
+ :param category_id: uuid of the action category
+ :param data_id: uuid of the action scope
+ :param user_id: user ID who do the request
+ :return: {
+ "action_data_id": {
+ "policy_id": "ID of the policy",
+ "object_id": "ID of the action",
+ "category_id": "ID of the category",
+ "assignments": "Assignments list (list of data_id)",
+ }
+ }
+ :internal_api: get_action_assignments
+ """
+ data = PolicyManager.get_action_assignments(
+ user_id=user_id, policy_id=uuid,
+ action_id=perimeter_id, category_id=category_id)
+
+ return {"action_assignments": data}
+
+ @validate_input("post", kwargs_state=[True, False, False, False, False],
+ body_state={"id": True, "category_id": True, "data_id": True})
+ @check_auth
+ def post(self, uuid=None, perimeter_id=None, category_id=None,
+ data_id=None, user_id=None):
+ """Create an action assignment.
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: uuid of the action (not used here)
+ :param category_id: uuid of the action category (not used here)
+ :param data_id: uuid of the action scope (not used here)
+ :param user_id: user ID who do the request
+ :request body: {
+ "id": "UUID of the action (mandatory)",
+ "category_id": "UUID of the category (mandatory)",
+ "data_id": "UUID of the scope (mandatory)"
+ }
+ :return: {
+ "action_data_id": {
+ "policy_id": "ID of the policy",
+ "object_id": "ID of the action",
+ "category_id": "ID of the category",
+ "assignments": "Assignments list (list of data_id)",
+ }
+ }
+ :internal_api: update_action_assignment
+ """
+
+ data_id = request.json.get("data_id")
+ category_id = request.json.get("category_id")
+ perimeter_id = request.json.get("id")
+ data = PolicyManager.add_action_assignment(
+ user_id=user_id, policy_id=uuid,
+ action_id=perimeter_id, category_id=category_id,
+ data_id=data_id)
+ invalidate_data_in_slaves(
+ policy_id=uuid,
+ perimeter_id=perimeter_id,
+ category_id=category_id,
+ data_id=data_id)
+
+ return {"action_assignments": data}
+
+ @validate_input("delete", kwargs_state=[True, True, True, True, False])
+ @check_auth
+ def delete(self, uuid=None, perimeter_id=None, category_id=None,
+ data_id=None, user_id=None):
+ """Delete a action assignment for a given policy
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: uuid of the action
+ :param category_id: uuid of the action category
+ :param data_id: uuid of the action scope
+ :param user_id: user ID who do the request
+ :return: {
+ "result": "True or False",
+ "message": "optional message"
+ }
+ :internal_api: delete_action_assignment
+ """
+
+ data = PolicyManager.delete_action_assignment(
+ user_id=user_id, policy_id=uuid,
+ action_id=perimeter_id, category_id=category_id,
+ data_id=data_id)
+ invalidate_data_in_slaves(
+ policy_id=uuid,
+ perimeter_id=perimeter_id,
+ category_id=category_id,
+ data_id=data_id)
+
+ return {"result": True}
diff --git a/old/moon_manager/moon_manager/api/base_exception.py b/old/moon_manager/moon_manager/api/base_exception.py
new file mode 100644
index 00000000..0a414a59
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/base_exception.py
@@ -0,0 +1,17 @@
+class BaseException(Exception):
+ def __init__(self, message):
+ self._code = 500
+ self._message = message
+ # Call the base class constructor with the parameters it needs
+ super(BaseException, self).__init__(message)
+
+ @property
+ def code(self):
+ return self._code
+
+ @property
+ def message(self):
+ return self._message
+
+ def __str__(self):
+ return "Error " + str(self._code) + " " + self.__class__.__name__ + ': ' + self.message
diff --git a/old/moon_manager/moon_manager/api/data.py b/old/moon_manager/moon_manager/api/data.py
new file mode 100644
index 00000000..92d7b2c6
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/data.py
@@ -0,0 +1,311 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Data are elements used to create rules
+
+"""
+
+from flask import request
+from flask_restful import Resource
+import logging
+from python_moonutilities.security_functions import check_auth
+from python_moondb.core import PolicyManager
+from python_moonutilities.security_functions import validate_input
+
+__version__ = "4.3.2"
+
+logger = logging.getLogger("moon.manager.api." + __name__)
+
+
+class SubjectData(Resource):
+ """
+ Endpoint for subject data requests
+ """
+
+ __urls__ = (
+ "/policies/<string:uuid>/subject_data",
+ "/policies/<string:uuid>/subject_data/",
+ "/policies/<string:uuid>/subject_data/<string:category_id>",
+ "/policies/<string:uuid>/subject_data/<string:category_id>/<string:data_id>",
+ )
+
+ @validate_input("get", kwargs_state=[True, False, False, False])
+ @check_auth
+ def get(self, uuid=None, category_id=None, data_id=None, user_id=None):
+ """Retrieve all subject categories or a specific one if data_id is given
+ for a given policy
+
+ :param uuid: uuid of the policy
+ :param category_id: uuid of the subject category
+ :param data_id: uuid of the subject data
+ :param user_id: user ID who do the request
+ :return: [{
+ "policy_id": "policy_id1",
+ "category_id": "category_id1",
+ "data": {
+ "subject_data_id": {
+ "name": "name of the data",
+ "description": "description of the data (optional)"
+ }
+ }
+ }]
+ :internal_api: get_subject_data
+ """
+ logger.info("api.get {} {} {}".format(uuid, category_id, data_id))
+ data = PolicyManager.get_subject_data(user_id=user_id,
+ policy_id=uuid,
+ category_id=category_id,
+ data_id=data_id)
+ logger.info("api.get data = {}".format(data))
+
+ return {"subject_data": data}
+
+ @validate_input("post", kwargs_state=[True, True, False, False], body_state={"name": True})
+ @check_auth
+ def post(self, uuid=None, category_id=None, data_id=None, user_id=None):
+ """Create or update a subject.
+
+ :param uuid: uuid of the policy
+ :param category_id: uuid of the subject category
+ :param data_id: uuid of the subject data (not used here)
+ :param user_id: user ID who do the request
+ :request body: {
+ "name": "name of the data (mandatory)",
+ "description": "description of the data (optional)"
+ }
+ :return: {
+ "policy_id": "policy_id1",
+ "category_id": "category_id1",
+ "data": {
+ "subject_data_id": {
+ "name": "name of the data (mandatory)",
+ "description": "description of the data (optional)"
+ }
+ }
+ }
+ :internal_api: add_subject_data
+ """
+ data = PolicyManager.set_subject_data(user_id=user_id,
+ policy_id=uuid,
+ category_id=category_id,
+ value=request.json)
+
+ return {"subject_data": data}
+
+ @validate_input("delete", kwargs_state=[True, False, False, False])
+ @check_auth
+ def delete(self, uuid=None, category_id=None, data_id=None, user_id=None):
+ """Delete a subject for a given policy
+
+ :param uuid: uuid of the policy
+ :param category_id: uuid of the subject category
+ :param data_id: uuid of the subject data
+ :param user_id: user ID who do the request
+ :return: [{
+ "result": "True or False",
+ "message": "optional message (optional)"
+ }]
+ :internal_api: delete_subject_data
+ """
+ logger.info("api.delete {} {}".format(uuid, data_id))
+ data = PolicyManager.delete_subject_data(user_id=user_id,
+ policy_id=uuid,
+ category_id=category_id,
+ data_id=data_id)
+
+ return {"result": True}
+
+
+class ObjectData(Resource):
+ """
+ Endpoint for object data requests
+ """
+
+ __urls__ = (
+ "/policies/<string:uuid>/object_data",
+ "/policies/<string:uuid>/object_data/",
+ "/policies/<string:uuid>/object_data/<string:category_id>",
+ "/policies/<string:uuid>/object_data/<string:category_id>/"
+ "<string:data_id>",
+ )
+
+ @validate_input("get", kwargs_state=[True, False, False, False])
+ @check_auth
+ def get(self, uuid=None, category_id=None, data_id=None, user_id=None):
+ """Retrieve all object categories or a specific one if sid is given
+ for a given policy
+
+ :param uuid: uuid of the policy
+ :param category_id: uuid of the object category
+ :param data_id: uuid of the object data
+ :param user_id: user ID who do the request
+ :return: [{
+ "policy_id": "policy_id1",
+ "category_id": "category_id1",
+ "data": {
+ "object_data_id": {
+ "name": "name of the data",
+ "description": "description of the data (optional)"
+ }
+ }
+ }]
+ :internal_api: get_object_data
+ """
+ data = PolicyManager.get_object_data(user_id=user_id,
+ policy_id=uuid,
+ category_id=category_id,
+ data_id=data_id)
+
+ return {"object_data": data}
+
+ @validate_input("post", kwargs_state=[True, True, False, False], body_state={"name": True})
+ @check_auth
+ def post(self, uuid=None, category_id=None, data_id=None, user_id=None):
+ """Create or update a object.
+
+ :param uuid: uuid of the policy
+ :param category_id: uuid of the object category
+ :param data_id: uuid of the object data (not used here)
+ :param user_id: user ID who do the request
+ :request body: {
+ "name": "name of the data (mandatory)",
+ "description": "description of the data (optional)"
+ }
+ :return: {
+ "policy_id": "policy_id1",
+ "category_id": "category_id1",
+ "data": {
+ "object_data_id": {
+ "name": "name of the data",
+ "description": "description of the data (optional)"
+ }
+ }
+ }
+ :internal_api: add_object_data
+ """
+ data = PolicyManager.add_object_data(user_id=user_id,
+ policy_id=uuid,
+ category_id=category_id,
+ value=request.json)
+
+ return {"object_data": data}
+
+ @validate_input("delete", kwargs_state=[True, False, False, False])
+ @check_auth
+ def delete(self, uuid=None, category_id=None, data_id=None, user_id=None):
+ """Delete a object for a given policy
+
+ :param uuid: uuid of the policy
+ :param category_id: uuid of the object category
+ :param data_id: uuid of the object data
+ :param user_id: user ID who do the request
+ :return: {
+ "result": "True or False",
+ "message": "optional message (optional)"
+ }
+ :internal_api: delete_object_data
+ """
+ data = PolicyManager.delete_object_data(user_id=user_id,
+ policy_id=uuid,
+ category_id=category_id,
+ data_id=data_id)
+
+ return {"result": True}
+
+
+class ActionData(Resource):
+ """
+ Endpoint for action data requests
+ """
+
+ __urls__ = (
+ "/policies/<string:uuid>/action_data",
+ "/policies/<string:uuid>/action_data/",
+ "/policies/<string:uuid>/action_data/<string:category_id>",
+ "/policies/<string:uuid>/action_data/<string:category_id>/"
+ "<string:data_id>",
+ )
+
+ @validate_input("get", kwargs_state=[True, False, False, False])
+ @check_auth
+ def get(self, uuid=None, category_id=None, data_id=None, user_id=None):
+ """Retrieve all action categories or a specific one if sid is given
+ for a given policy
+
+ :param uuid: uuid of the policy
+ :param category_id: uuid of the action category
+ :param data_id: uuid of the action data
+ :param user_id: user ID who do the request
+ :return: [{
+ "policy_id": "policy_id1",
+ "category_id": "category_id1",
+ "data": {
+ "action_data_id": {
+ "name": "name of the data",
+ "description": "description of the data (optional)"
+ }
+ }
+ }]
+ :internal_api: get_action_data
+ """
+ data = PolicyManager.get_action_data(user_id=user_id,
+ policy_id=uuid,
+ category_id=category_id,
+ data_id=data_id)
+
+ return {"action_data": data}
+
+ @validate_input("post", kwargs_state=[True, True, False, False], body_state={"name": True})
+ @check_auth
+ def post(self, uuid=None, category_id=None, data_id=None, user_id=None):
+ """Create or update a action.
+
+ :param uuid: uuid of the policy
+ :param category_id: uuid of the action category
+ :param data_id: uuid of the action data
+ :param user_id: user ID who do the request
+ :request body: {
+ "name": "name of the data (mandatory)",
+ "description": "description of the data (optional)"
+ }
+ :return: {
+ "policy_id": "policy_id1",
+ "category_id": "category_id1",
+ "data": {
+ "action_data_id": {
+ "name": "name of the data",
+ "description": "description of the data (optional)"
+ }
+ }
+ }
+ :internal_api: add_action_data
+ """
+ data = PolicyManager.add_action_data(user_id=user_id,
+ policy_id=uuid,
+ category_id=category_id,
+ value=request.json)
+ return {"action_data": data}
+
+ @validate_input("delete", kwargs_state=[True, False, False, False])
+ @check_auth
+ def delete(self, uuid=None, category_id=None, data_id=None, user_id=None):
+ """Delete a action for a given policy
+
+ :param uuid: uuid of the policy
+ :param category_id: uuid of the action category
+ :param data_id: uuid of the action data
+ :param user_id: user ID who do the request
+ :return: {
+ "result": "True or False",
+ "message": "optional message (optional)"
+ }
+ :internal_api: delete_action_data
+ """
+ data = PolicyManager.delete_action_data(user_id=user_id,
+ policy_id=uuid,
+ category_id=category_id,
+ data_id=data_id)
+
+ return {"result": True}
diff --git a/old/moon_manager/moon_manager/api/generic.py b/old/moon_manager/moon_manager/api/generic.py
new file mode 100644
index 00000000..721f6213
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/generic.py
@@ -0,0 +1,144 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Those API are helping API used to manage the Moon platform.
+"""
+
+from flask_restful import Resource, request
+import logging
+import moon_manager.api
+from python_moonutilities.security_functions import check_auth
+
+__version__ = "4.3.2"
+
+logger = logging.getLogger("moon.manager.api." + __name__)
+
+
+class Status(Resource):
+ """
+ Endpoint for status requests
+ """
+
+ __urls__ = (
+ "/status",
+ "/status/",
+ "/status/<string:component_id>"
+ )
+
+ def get(self, component_id=None):
+ """Retrieve status of all components
+
+ :return: {
+ "orchestrator": {
+ "status": "Running"
+ },
+ "security_router": {
+ "status": "Running"
+ }
+ }
+ """
+ raise NotImplemented
+
+
+class Logs(Resource):
+ """
+ Endpoint for logs requests
+ """
+
+ __urls__ = (
+ "/logs",
+ "/logs/",
+ "/logs/<string:component_id>"
+ )
+
+ def get(self, component_id=None):
+ """Get logs from the Moon platform
+
+ :param component_id: the ID of the component your are looking for (optional)
+ :return: [
+ "2015-04-15-13:45:20
+ "2015-04-15-13:45:21
+ "2015-04-15-13:45:22
+ "2015-04-15-13:45:23
+ ]
+ """
+ filter_str = request.args.get('filter', '')
+ from_str = request.args.get('from', '')
+ to_str = request.args.get('to', '')
+ event_number = request.args.get('event_number', '')
+ try:
+ event_number = int(event_number)
+ except ValueError:
+ event_number = None
+ args = dict()
+ args["filter"] = filter_str
+ args["from"] = from_str
+ args["to"] = to_str
+ args["event_number"] = event_number
+
+ raise NotImplemented
+
+
+class API(Resource):
+ """
+ Endpoint for API requests
+ """
+
+ __urls__ = (
+ "/api",
+ "/api/",
+ "/api/<string:group_id>",
+ "/api/<string:group_id>/",
+ "/api/<string:group_id>/<string:endpoint_id>"
+ )
+
+ @check_auth
+ def get(self, group_id="", endpoint_id="", user_id=""):
+ """Retrieve all API endpoints or a specific endpoint if endpoint_id is given
+
+ :param group_id: the name of one existing group (ie generic, ...)
+ :param endpoint_id: the name of one existing component (ie Logs, Status, ...)
+ :return: {
+ "group_name": {
+ "endpoint_name": {
+ "description": "a description",
+ "methods": {
+ "get": "description of the HTTP method"
+ },
+ "urls": ('/api', '/api/', '/api/<string:endpoint_id>')
+ }
+ }
+ """
+ __methods = ("get", "post", "put", "delete", "options", "patch")
+ api_list = filter(lambda x: "__" not in x, dir(moon_manager.api))
+ api_desc = dict()
+ for api_name in api_list:
+ api_desc[api_name] = {}
+ group_api_obj = eval("moon_manager.api.{}".format(api_name))
+ api_desc[api_name]["description"] = group_api_obj.__doc__
+ if "__version__" in dir(group_api_obj):
+ api_desc[api_name]["version"] = group_api_obj.__version__
+ object_list = list(filter(lambda x: "__" not in x,
+ dir(group_api_obj)))
+ for obj in map(lambda x: eval("moon_manager.api.{}.{}".format(api_name, x)),
+ object_list):
+ if "__urls__" in dir(obj):
+ api_desc[api_name][obj.__name__] = dict()
+ api_desc[api_name][obj.__name__]["urls"] = obj.__urls__
+ api_desc[api_name][obj.__name__]["methods"] = dict()
+ for _method in filter(lambda x: x in __methods, dir(obj)):
+ docstring = eval(
+ "moon_manager.api.{}.{}.{}.__doc__".format(api_name, obj.__name__,
+ _method))
+ api_desc[api_name][obj.__name__]["methods"][_method] = docstring
+ api_desc[api_name][obj.__name__]["description"] = str(obj.__doc__)
+ if group_id in api_desc:
+ if endpoint_id in api_desc[group_id]:
+ return {group_id: {endpoint_id: api_desc[group_id][endpoint_id]}}
+ elif len(endpoint_id) > 0:
+ logger.error("Unknown endpoint_id {}".format(endpoint_id))
+ return {"error": "Unknown endpoint_id {}".format(endpoint_id)}
+ return {group_id: api_desc[group_id]}
+ return api_desc
diff --git a/old/moon_manager/moon_manager/api/json_export.py b/old/moon_manager/moon_manager/api/json_export.py
new file mode 100644
index 00000000..069e5884
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/json_export.py
@@ -0,0 +1,279 @@
+# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import logging
+from flask_restful import Resource
+from python_moonutilities.security_functions import check_auth
+from python_moondb.core import PDPManager
+from python_moondb.core import PolicyManager
+from python_moondb.core import ModelManager
+from moon_manager.api.json_utils import JsonUtils, BaseException
+
+__version__ = "4.5.0"
+
+logger = logging.getLogger("moon.manager.api." + __name__)
+
+
+class JsonExport(Resource):
+ __urls__ = (
+ "/export",
+ "/export/",
+ )
+
+ def _export_rules(self, json_content):
+ policies = PolicyManager.get_policies(self._user_id)
+ rules_array = []
+
+ for policy_key in policies:
+ rules = PolicyManager.get_rules(self._user_id, policy_key)
+ rules = rules["rules"]
+ # logger.info(rules)
+ for rule in rules:
+ rule_dict = dict()
+ JsonUtils.copy_field_if_exists(rule, rule_dict, "instructions", dict)
+ JsonUtils.copy_field_if_exists(rule, rule_dict, "enabled", True)
+ JsonUtils.convert_id_to_name(rule["meta_rule_id"], rule_dict, "meta_rule",
+ "meta_rule", ModelManager, self._user_id)
+ JsonUtils.convert_id_to_name(policy_key, rule_dict, "policy", "policy",
+ PolicyManager, self._user_id)
+ ids = rule["rule"]
+ rule_description = dict()
+ meta_rule = ModelManager.get_meta_rules(self._user_id, rule["meta_rule_id"])
+ meta_rule = [v for v in meta_rule.values()]
+ meta_rule = meta_rule[0]
+ index_subject_data = len(meta_rule["subject_categories"]) - 1
+ index_object_data = len(meta_rule["subject_categories"]) + len(
+ meta_rule["object_categories"]) - 1
+ index_action_data = len(meta_rule["subject_categories"]) + len(
+ meta_rule["object_categories"]) + len(meta_rule["action_categories"]) - 1
+ ids_subject_data = [ids[0]] if len(meta_rule["subject_categories"]) == 1 else ids[
+ 0:index_subject_data]
+ ids_object_data = [ids[index_object_data]] if len(
+ meta_rule["object_categories"]) == 1 else ids[
+ index_subject_data + 1:index_object_data]
+ ids_action_date = [ids[index_action_data]] if len(
+ meta_rule["action_categories"]) == 1 else ids[
+ index_object_data + 1:index_action_data]
+ JsonUtils.convert_ids_to_names(ids_subject_data, rule_description, "subject_data",
+ "subject_data", PolicyManager, self._user_id,
+ policy_key)
+ JsonUtils.convert_ids_to_names(ids_object_data, rule_description, "object_data",
+ "object_data", PolicyManager, self._user_id,
+ policy_key)
+ JsonUtils.convert_ids_to_names(ids_action_date, rule_description, "action_data",
+ "action_data", PolicyManager, self._user_id,
+ policy_key)
+ rule_dict["rule"] = rule_description
+ rules_array.append(rule_dict)
+
+ if len(rules_array) > 0:
+ json_content['rules'] = rules_array
+
+ def _export_meta_rules(self, json_content):
+ meta_rules = ModelManager.get_meta_rules(self._user_id)
+ meta_rules_array = []
+ # logger.info(meta_rules)
+ for meta_rule_key in meta_rules:
+ # logger.info(meta_rules[meta_rule_key])
+ meta_rule_dict = dict()
+ JsonUtils.copy_field_if_exists(meta_rules[meta_rule_key], meta_rule_dict, "name", str)
+ JsonUtils.copy_field_if_exists(meta_rules[meta_rule_key], meta_rule_dict, "description",
+ str)
+ JsonUtils.convert_ids_to_names(meta_rules[meta_rule_key]["subject_categories"],
+ meta_rule_dict, "subject_categories", "subject_category",
+ ModelManager, self._user_id)
+ JsonUtils.convert_ids_to_names(meta_rules[meta_rule_key]["object_categories"],
+ meta_rule_dict, "object_categories", "object_category",
+ ModelManager, self._user_id)
+ JsonUtils.convert_ids_to_names(meta_rules[meta_rule_key]["action_categories"],
+ meta_rule_dict, "action_categories", "action_category",
+ ModelManager, self._user_id)
+ logger.info("Exporting meta rule {}".format(meta_rule_dict))
+ meta_rules_array.append(meta_rule_dict)
+ if len(meta_rules_array) > 0:
+ json_content['meta_rules'] = meta_rules_array
+
+ def _export_subject_object_action_assignments(self, type_element, json_content):
+ export_method_data = getattr(PolicyManager, 'get_' + type_element + '_assignments')
+ policies = PolicyManager.get_policies(self._user_id)
+ element_assignments_array = []
+ for policy_key in policies:
+ assignments = export_method_data(self._user_id, policy_key)
+ # logger.info(assignments)
+ for assignment_key in assignments:
+ assignment_dict = dict()
+ JsonUtils.convert_id_to_name(assignments[assignment_key][type_element + "_id"],
+ assignment_dict, type_element, type_element,
+ PolicyManager, self._user_id, policy_key)
+ JsonUtils.convert_id_to_name(assignments[assignment_key]["category_id"],
+ assignment_dict, "category",
+ type_element + "_category", ModelManager,
+ self._user_id, policy_key)
+ JsonUtils.convert_ids_to_names(assignments[assignment_key]["assignments"],
+ assignment_dict, "assignments",
+ type_element + "_data", PolicyManager, self._user_id,
+ policy_key)
+ element_assignments_array.append(assignment_dict)
+ logger.info("Exporting {} assignment {}".format(type_element, assignment_dict))
+ if len(element_assignments_array) > 0:
+ json_content[type_element + '_assignments'] = element_assignments_array
+
+ def _export_subject_object_action_datas(self, type_element, json_content):
+ export_method_data = getattr(PolicyManager, 'get_' + type_element + '_data')
+ policies = PolicyManager.get_policies(self._user_id)
+ element_datas_array = []
+ for policy_key in policies:
+ datas = export_method_data(self._user_id, policy_key)
+ # logger.info("data found : {}".format(datas))
+ for data_group in datas:
+ policy_id = data_group["policy_id"]
+ category_id = data_group["category_id"]
+ # logger.info(data_group["data"])
+ for data_key in data_group["data"]:
+ data_dict = dict()
+ if type_element == 'subject':
+ JsonUtils.copy_field_if_exists(data_group["data"][data_key], data_dict,
+ "name", str)
+ JsonUtils.copy_field_if_exists(data_group["data"][data_key], data_dict,
+ "description", str)
+ else:
+ JsonUtils.copy_field_if_exists(data_group["data"][data_key], data_dict,
+ "name", str)
+ JsonUtils.copy_field_if_exists(data_group["data"][data_key], data_dict,
+ "description", str)
+
+ JsonUtils.convert_id_to_name(policy_id, data_dict, "policy", "policy",
+ PolicyManager, self._user_id)
+ JsonUtils.convert_id_to_name(category_id, data_dict, "category",
+ type_element + "_category", ModelManager,
+ self._user_id, policy_key)
+ logger.info("Exporting {} data {}".format(type_element, data_dict))
+ element_datas_array.append(data_dict)
+
+ if len(element_datas_array) > 0:
+ json_content[type_element + '_data'] = element_datas_array
+
+ def _export_subject_object_action_categories(self, type_element, json_content):
+ export_method = getattr(ModelManager, 'get_' + type_element + '_categories')
+ element_categories = export_method(self._user_id)
+ element_categories_array = []
+ for element_category_key in element_categories:
+ element_category = dict()
+ JsonUtils.copy_field_if_exists(element_categories[element_category_key],
+ element_category, "name", str)
+ JsonUtils.copy_field_if_exists(element_categories[element_category_key],
+ element_category, "description", str)
+ element_categories_array.append(element_category)
+ logger.info("Exporting {} category {}".format(type_element, element_category))
+ if len(element_categories_array) > 0:
+ json_content[type_element + '_categories'] = element_categories_array
+
+ def _export_subject_object_action(self, type_element, json_content):
+ export_method = getattr(PolicyManager, 'get_' + type_element + 's')
+ policies = PolicyManager.get_policies(self._user_id)
+ element_dict = dict()
+ elements_array = []
+ for policy_key in policies:
+ elements = export_method(self._user_id, policy_key)
+ for element_key in elements:
+ # logger.info("Exporting {}".format(elements[element_key]))
+ element = dict()
+ JsonUtils.copy_field_if_exists(elements[element_key], element, "name", str)
+ JsonUtils.copy_field_if_exists(elements[element_key], element, "description", str)
+ JsonUtils.copy_field_if_exists(elements[element_key], element, "extra", dict)
+ if element["name"] not in element_dict:
+ element["policies"] = []
+ element_dict[element["name"]] = element
+ current_element = element_dict[element["name"]]
+ current_element["policies"].append({"name": JsonUtils.convert_id_to_name_string(
+ policy_key, "policy", PolicyManager, self._user_id)})
+
+ for key in element_dict:
+ logger.info("Exporting {} {}".format(type_element, element_dict[key]))
+ elements_array.append(element_dict[key])
+
+ if len(elements_array) > 0:
+ json_content[type_element + 's'] = elements_array
+
+ def _export_policies(self, json_content):
+ policies = PolicyManager.get_policies(self._user_id)
+ policies_array = []
+ for policy_key in policies:
+ policy = dict()
+ JsonUtils.copy_field_if_exists(policies[policy_key], policy, "name", str)
+ JsonUtils.copy_field_if_exists(policies[policy_key], policy, "genre", str)
+ JsonUtils.copy_field_if_exists(policies[policy_key], policy, "description", str)
+ JsonUtils.convert_id_to_name(policies[policy_key]["model_id"], policy, "model", "model",
+ ModelManager, self._user_id)
+ logger.info("Exporting policy {}".format(policy))
+ policies_array.append(policy)
+ if len(policies_array) > 0:
+ json_content["policies"] = policies_array
+
+ def _export_models(self, json_content):
+ models = ModelManager.get_models(self._user_id)
+ models_array = []
+ for model_key in models:
+ model = dict()
+ JsonUtils.copy_field_if_exists(models[model_key], model, "name", str)
+ JsonUtils.copy_field_if_exists(models[model_key], model, "description", str)
+ # logger.info(models[model_key]["meta_rules"])
+ JsonUtils.convert_ids_to_names(models[model_key]["meta_rules"], model, "meta_rules",
+ "meta_rule", ModelManager, self._user_id)
+ logger.info("Exporting model {}".format(model))
+ models_array.append(model)
+ if len(models_array) > 0:
+ json_content["models"] = models_array
+
+ def _export_pdps(self, json_content):
+ pdps = PDPManager.get_pdp(self._user_id)
+ pdps_array = []
+ for pdp_key in pdps:
+ logger.info("Exporting pdp {}".format(pdps[pdp_key]))
+ pdps_array.append(pdps[pdp_key])
+ if len(pdps_array) > 0:
+ json_content["pdps"] = pdps_array
+
+ def _export_json(self, user_id):
+ self._user_id = user_id
+ json_content = dict()
+
+ logger.info("Exporting pdps...")
+ self._export_pdps(json_content)
+ logger.info("Exporting policies...")
+ self._export_policies(json_content)
+ logger.info("Exporting models...")
+ self._export_models(json_content)
+ # export subjects, subject_data, subject_categories, subject_assignements idem for object and action
+ list_element = [{"key": "subject"}, {"key": "object"}, {"key": "action"}]
+ for elt in list_element:
+ logger.info("Exporting {}s...".format(elt["key"]))
+ self._export_subject_object_action(elt["key"], json_content)
+ logger.info("Exporting {} categories...".format(elt["key"]))
+ self._export_subject_object_action_categories(elt["key"], json_content)
+ logger.info("Exporting {} data...".format(elt["key"]))
+ self._export_subject_object_action_datas(elt["key"], json_content)
+ logger.info("Exporting {} assignments...".format(elt["key"]))
+ self._export_subject_object_action_assignments(elt["key"], json_content)
+ logger.info("Exporting meta rules...")
+ self._export_meta_rules(json_content)
+ logger.info("Exporting rules...")
+ self._export_rules(json_content)
+
+ return json_content
+
+ @check_auth
+ def get(self, user_id=None):
+ """Import file.
+
+ :param user_id: user ID who do the request
+ :return: {
+
+ }
+ :internal_api:
+ """
+ json_file = self._export_json(user_id)
+ logger.info(json_file)
+ return {"content": json_file}
diff --git a/old/moon_manager/moon_manager/api/json_import.py b/old/moon_manager/moon_manager/api/json_import.py
new file mode 100644
index 00000000..05f4a0c0
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/json_import.py
@@ -0,0 +1,584 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from flask import request
+from flask_restful import Resource
+import flask_restful
+from flask import abort
+
+from python_moonutilities.security_functions import check_auth
+from python_moonutilities import exceptions
+import logging
+import json
+
+from moon_manager.api.base_exception import BaseException
+from moon_manager.api.json_utils import JsonUtils, UnknownName
+from python_moondb.core import PDPManager
+from python_moondb.core import PolicyManager
+from python_moondb.core import ModelManager
+
+__version__ = "4.5.0"
+
+logger = logging.getLogger("moon.manager.api." + __name__)
+
+INST_CALLBACK = 0
+DATA_CALLBACK = 1
+ASSIGNMENT_CALLBACK = 2
+CATEGORIES_CALLBACK = 3
+
+
+class ForbiddenOverride(BaseException):
+ def __init__(self, message):
+ # Call the base class constructor with the parameters it needs
+ super(ForbiddenOverride, self).__init__(message)
+
+
+class UnknownPolicy(BaseException):
+ def __init__(self, message):
+ # Call the base class constructor with the parameters it needs
+ super(UnknownPolicy, self).__init__(message)
+
+
+class UnknownModel(BaseException):
+ def __init__(self, message):
+ # Call the base class constructor with the parameters it needs
+ super(UnknownModel, self).__init__(message)
+
+
+class UnknownData(BaseException):
+ def __init__(self, message):
+ # Call the base class constructor with the parameters it needs
+ super(UnknownData, self).__init__(message)
+
+
+class MissingPolicy(BaseException):
+ def __init__(self, message):
+ # Call the base class constructor with the parameters it needs
+ super(MissingPolicy, self).__init__(message)
+
+
+class InvalidJson(BaseException):
+ def __init__(self, message):
+ # Call the base class constructor with the parameters it needs
+ super(InvalidJson, self).__init__(message)
+
+
+class JsonImport(Resource):
+ __urls__ = (
+ "/import",
+ "/import/",
+ )
+
+ def _reorder_rules_ids(self, rule, ordered_perimeter_categories_ids, json_data_ids, policy_id,
+ get_function):
+ ordered_json_ids = [None] * len(ordered_perimeter_categories_ids)
+ for json_id in json_data_ids:
+ data = get_function(self._user_id, policy_id, data_id=json_id)
+ data = data[0]
+ if data["category_id"] not in ordered_perimeter_categories_ids:
+ raise InvalidJson(
+ "The category id {} of the rule {} does not match the meta rule".format(
+ data["category_id"], rule))
+ if ordered_json_ids[
+ ordered_perimeter_categories_ids.index(data["category_id"])] is not None:
+ raise InvalidJson(
+ "The category id {} of the rule {} shall not be used twice in the same rule".format(
+ data["category_id"], rule))
+ ordered_json_ids[ordered_perimeter_categories_ids.index(data["category_id"])] = json_id
+ logger.info(ordered_json_ids)
+ return ordered_json_ids
+
+ def _import_rules(self, json_rules):
+ if not isinstance(json_rules, list):
+ raise InvalidJson("rules shall be a list!")
+
+ for json_rule in json_rules:
+ json_to_use = dict()
+ JsonUtils.copy_field_if_exists(json_rule, json_to_use, "instructions", str)
+ JsonUtils.copy_field_if_exists(json_rule, json_to_use, "enabled", bool,
+ default_value=True)
+
+ json_ids = dict()
+ JsonUtils.convert_name_to_id(json_rule, json_ids, "policy", "policy_id", "policy",
+ PolicyManager, self._user_id)
+ JsonUtils.convert_name_to_id(json_rule, json_to_use, "meta_rule", "meta_rule_id",
+ "meta_rule", ModelManager, self._user_id)
+ json_subject_ids = dict()
+ json_object_ids = dict()
+ json_action_ids = dict()
+ JsonUtils.convert_names_to_ids(json_rule["rule"], json_subject_ids, "subject_data",
+ "subject", "subject_data", PolicyManager, self._user_id,
+ json_ids["policy_id"])
+ JsonUtils.convert_names_to_ids(json_rule["rule"], json_object_ids, "object_data",
+ "object", "object_data", PolicyManager, self._user_id,
+ json_ids["policy_id"])
+ JsonUtils.convert_names_to_ids(json_rule["rule"], json_action_ids, "action_data",
+ "action", "action_data", PolicyManager, self._user_id,
+ json_ids["policy_id"])
+
+ meta_rule = ModelManager.get_meta_rules(self._user_id, json_to_use["meta_rule_id"])
+ meta_rule = [v for v in meta_rule.values()]
+ meta_rule = meta_rule[0]
+
+ json_to_use_rule = self._reorder_rules_ids(json_rule, meta_rule["subject_categories"],
+ json_subject_ids["subject"],
+ json_ids["policy_id"],
+ PolicyManager.get_subject_data)
+ json_to_use_rule = json_to_use_rule + self._reorder_rules_ids(json_rule, meta_rule[
+ "object_categories"], json_object_ids["object"], json_ids["policy_id"],
+ PolicyManager.get_object_data)
+ json_to_use_rule = json_to_use_rule + self._reorder_rules_ids(json_rule, meta_rule[
+ "action_categories"], json_action_ids["action"], json_ids["policy_id"],
+ PolicyManager.get_action_data)
+ json_to_use["rule"] = json_to_use_rule
+ try:
+ logger.debug("Adding / updating a rule from json {}".format(json_to_use))
+ PolicyManager.add_rule(self._user_id, json_ids["policy_id"],
+ json_to_use["meta_rule_id"], json_to_use)
+ except exceptions.RuleExisting:
+ pass
+ except exceptions.PolicyUnknown:
+ raise UnknownPolicy("Unknown policy with id {}".format(json_ids["policy_id"]))
+
+ def _import_meta_rules(self, json_meta_rules):
+ logger.info("Input meta rules : {}".format(json_meta_rules))
+ for json_meta_rule in json_meta_rules:
+ json_to_use = dict()
+ JsonUtils.copy_field_if_exists(json_meta_rule, json_to_use, "name", str)
+ JsonUtils.copy_field_if_exists(json_meta_rule, json_to_use, "description", str)
+ JsonUtils.convert_names_to_ids(json_meta_rule, json_to_use, "subject_categories",
+ "subject_categories", "subject_category", ModelManager,
+ self._user_id)
+ JsonUtils.convert_names_to_ids(json_meta_rule, json_to_use, "object_categories",
+ "object_categories", "object_category", ModelManager,
+ self._user_id)
+ JsonUtils.convert_names_to_ids(json_meta_rule, json_to_use, "action_categories",
+ "action_categories", "action_category", ModelManager,
+ self._user_id)
+ logger.debug("Adding / updating a metarule from json {}".format(json_meta_rule))
+ meta_rule = ModelManager.add_meta_rule(self._user_id, meta_rule_id=None,
+ value=json_to_use)
+ logger.debug("Added / updated meta rule : {}".format(meta_rule))
+
+ def _import_subject_object_action_assignments(self, json_item_assignments, type_element):
+ import_method = getattr(PolicyManager, 'add_' + type_element + '_assignment')
+ get_method = getattr(PolicyManager, 'get_' + type_element + '_data')
+
+ if not isinstance(json_item_assignments, list):
+ raise InvalidJson(type_element + " assignments shall be a list!")
+
+ # get the policy id related to the user
+ policies = PolicyManager.get_policies(self._user_id)
+
+ for json_item_assignment in json_item_assignments:
+ item_override = JsonUtils.get_override(json_item_assignment)
+ if item_override is True:
+ raise ForbiddenOverride(
+ "{} assignments do not support override flag !".format(type_element))
+
+ json_assignment = dict()
+ JsonUtils.convert_name_to_id(json_item_assignment, json_assignment, "category",
+ "category_id", type_element + "_category", ModelManager,
+ self._user_id)
+
+ has_found_data = False
+ # loop over policies
+ for policy_id in policies:
+ json_data = dict()
+ try:
+ JsonUtils.convert_name_to_id(json_item_assignment, json_assignment,
+ type_element, "id", type_element, PolicyManager,
+ self._user_id, policy_id)
+ JsonUtils.convert_names_to_ids(json_item_assignment, json_data, "assignments",
+ "data_id", type_element + "_data", PolicyManager,
+ self._user_id, policy_id,
+ json_assignment["category_id"])
+ has_found_data = True
+ except UnknownName:
+ # the category or data has not been found in this policy : we look into the next one
+ continue
+ for data_id in json_data["data_id"]:
+ # find the policy related to the current data
+ data = get_method(self._user_id, policy_id, data_id,
+ json_assignment["category_id"])
+ if data is not None and len(data) == 1:
+ logger.debug(
+ "Adding / updating a {} assignment from json {}".format(type_element,
+ json_assignment))
+ import_method(self._user_id, policy_id, json_assignment["id"],
+ json_assignment["category_id"],
+ data_id)
+ else:
+ raise UnknownData("Unknown data with id {}".format(data_id))
+
+ # case the data has not been found in any policies
+ if has_found_data is False:
+ raise InvalidJson("The json contains unknown {} data or category : {}".format(
+ type_element,
+ json_item_assignment))
+
+ def _import_subject_object_action_datas(self, json_items_data, mandatory_policy_ids,
+ type_element):
+ if type_element == "subject":
+ import_method = getattr(PolicyManager, 'set_' + type_element + '_data')
+ else:
+ import_method = getattr(PolicyManager, 'add_' + type_element + '_data')
+ # get_method = getattr(PolicyManager, 'get_' + type_element + '_data')
+
+ if not isinstance(json_items_data, list):
+ raise InvalidJson(type_element + " data shall be a list!")
+
+ for json_item_data in json_items_data:
+ item_override = JsonUtils.get_override(json_items_data)
+ if item_override is True:
+ raise ForbiddenOverride(
+ "{} datas do not support override flag !".format(type_element))
+ json_to_use = dict()
+ JsonUtils.copy_field_if_exists(json_item_data, json_to_use, "name", str)
+ JsonUtils.copy_field_if_exists(json_item_data, json_to_use, "description", str)
+ json_policy = dict()
+ # field_mandatory : not mandatory if there is some mandatory policies
+ JsonUtils.convert_names_to_ids(json_item_data, json_policy, "policies", "policy_id",
+ "policy",
+ PolicyManager, self._user_id,
+ field_mandatory=len(mandatory_policy_ids) == 0)
+ json_category = dict()
+ JsonUtils.convert_name_to_id(json_item_data, json_category, "category", "category_id",
+ type_element + "_category",
+ ModelManager, self._user_id)
+ policy_ids = []
+ if "policy_id" in json_policy:
+ policy_ids = json_policy["policy_id"]
+
+ for policy_id in policy_ids:
+ if policy_id is not None and policy_id not in mandatory_policy_ids:
+ mandatory_policy_ids.append(policy_id)
+
+ if len(mandatory_policy_ids) == 0:
+ raise InvalidJson("Invalid data, the policy shall be set when importing {}".format(
+ json_item_data))
+ category_id = None
+ if "category_id" in json_category:
+ category_id = json_category["category_id"]
+ if category_id is None:
+ raise InvalidJson(
+ "Invalid data, the category shall be set when importing {}".format(
+ json_item_data))
+
+ for policy_id in mandatory_policy_ids:
+ try:
+ data = import_method(self._user_id, policy_id, category_id=category_id,
+ value=json_to_use)
+ except exceptions.PolicyUnknown:
+ raise UnknownPolicy("Unknown policy with id {}".format(policy_id))
+ except Exception as e:
+ logger.exception(str(e))
+ raise e
+
+ def _import_subject_object_action_categories(self, json_item_categories, type_element):
+ import_method = getattr(ModelManager, 'add_' + type_element + '_category')
+ get_method = getattr(ModelManager, 'get_' + type_element + '_categories')
+
+ categories = get_method(self._user_id)
+
+ if not isinstance(json_item_categories, list):
+ raise InvalidJson(type_element + " categories shall be a list!")
+
+ for json_item_category in json_item_categories:
+ json_to_use = dict()
+ JsonUtils.copy_field_if_exists(json_item_category, json_to_use, "name", str)
+
+ # check if category with the same name exists : do this in moondb ?
+ existing_id = None
+ for category_key in categories:
+ if categories[category_key]["name"] == json_to_use["name"]:
+ existing_id = category_key
+
+ JsonUtils.copy_field_if_exists(json_item_category, json_to_use, "description", str)
+ item_override = JsonUtils.get_override(json_item_category)
+ if item_override is True:
+ raise ForbiddenOverride(
+ "{} categories do not support override flag !".format(type_element))
+
+ try:
+ category = import_method(self._user_id, existing_id, json_to_use)
+ except (exceptions.SubjectCategoryExisting, exceptions.ObjectCategoryExisting,
+ exceptions.ActionCategoryExisting):
+ # it already exists: do nothing
+ logger.warning("Ignored {} category with name {} is already in the database".format(
+ type_element, json_to_use["name"]))
+ except Exception as e:
+ logger.warning("Error while importing the category : {}".format(str(e)))
+ logger.exception(str(e))
+ raise e
+
+ def _import_subject_object_action(self, json_items, mandatory_policy_ids, type_element):
+ import_method = getattr(PolicyManager, 'add_' + type_element)
+ get_method = getattr(PolicyManager, 'get_' + type_element + 's')
+
+ if not isinstance(json_items, list):
+ raise InvalidJson(type_element + " items shall be a list!")
+
+ for json_item in json_items:
+ json_without_policy_name = dict()
+ JsonUtils.copy_field_if_exists(json_item, json_without_policy_name, "name", str)
+ JsonUtils.copy_field_if_exists(json_item, json_without_policy_name, "description", str)
+ JsonUtils.copy_field_if_exists(json_item, json_without_policy_name, "extra", dict)
+ JsonUtils.convert_names_to_ids(json_item, json_without_policy_name, "policies",
+ "policy_list", "policy", PolicyManager, self._user_id,
+ field_mandatory=False)
+ policy_ids = json_without_policy_name["policy_list"]
+ for mandatory_policy_id in mandatory_policy_ids:
+ if mandatory_policy_id not in policy_ids:
+ policy_ids.append(mandatory_policy_id)
+ # policy_ids and json_without_policy_name are references to the same array...
+ # json_without_policy_name["policy_list"].append(mandatory_policy_id)
+
+ item_override = JsonUtils.get_override(json_item)
+ if item_override is True:
+ raise ForbiddenOverride("{} does not support override flag !".format(type_element))
+
+ if len(policy_ids) == 0:
+ raise MissingPolicy(
+ "a {} needs at least one policy to be created or updated : {}".format(
+ type_element, json.dumps(json_item)))
+
+ for policy_id in policy_ids:
+ try:
+ items_in_db = get_method(self._user_id, policy_id)
+ key = None
+ for key_in_db in items_in_db:
+ if items_in_db[key_in_db]["name"] == json_without_policy_name["name"]:
+ key = key_in_db
+ break
+ element = import_method(self._user_id, policy_id, perimeter_id=key,
+ value=json_without_policy_name)
+ logger.debug("Added / updated {} : {}".format(type_element, element))
+
+ except exceptions.PolicyUnknown:
+ raise UnknownPolicy("Unknown policy when adding a {}!".format(type_element))
+ except Exception as e:
+ logger.exception(str(e))
+ raise BaseException(str(e))
+
+ def _import_policies(self, json_policies):
+ policy_mandatory_ids = []
+
+ if not isinstance(json_policies, list):
+ raise InvalidJson("policies shall be a list!")
+
+ for json_policy in json_policies:
+ # TODO put this in moondb
+ # policy_in_db = PolicyManager.get_policies_by_name(json_without_model_name["name"])
+ policies = PolicyManager.get_policies(self._user_id)
+ policy_in_db = None
+ policy_id = None
+ for policy_key in policies:
+ if policies[policy_key]["name"] == json_policy["name"]:
+ policy_in_db = policies[policy_key]
+ policy_id = policy_key
+ # end TODO
+ if policy_in_db is None:
+ policy_does_exist = False
+ else:
+ policy_does_exist = True
+
+ policy_override = JsonUtils.get_override(json_policy)
+ policy_mandatory = JsonUtils.get_mandatory(json_policy)
+
+ if policy_override is False and policy_does_exist:
+ if policy_id:
+ policy_mandatory_ids.append(policy_id)
+ logger.warning(
+ "Existing policy not updated because of the override option is not set !")
+ continue
+
+ json_without_model_name = dict()
+ JsonUtils.copy_field_if_exists(json_policy, json_without_model_name, "name", str)
+ JsonUtils.copy_field_if_exists(json_policy, json_without_model_name, "description", str)
+ JsonUtils.copy_field_if_exists(json_policy, json_without_model_name, "genre", str)
+ JsonUtils.convert_name_to_id(json_policy, json_without_model_name, "model", "model_id",
+ "model", ModelManager, self._user_id,
+ field_mandatory=False)
+
+ if not policy_does_exist:
+ logger.debug("Creating policy {} ".format(json_without_model_name))
+ added_policy = PolicyManager.add_policy(self._user_id, None,
+ json_without_model_name)
+ if policy_mandatory is True:
+ keys = list(added_policy.keys())
+ policy_mandatory_ids.append(keys[0])
+ elif policy_override is True:
+ logger.debug("Updating policy {} ".format(json_without_model_name))
+ updated_policy = PolicyManager.update_policy(self._user_id, policy_id,
+ json_without_model_name)
+ if policy_mandatory is True:
+ policy_mandatory_ids.append(policy_id)
+ return policy_mandatory_ids
+
+ def _import_models_with_new_meta_rules(self, json_models):
+ if not isinstance(json_models, list):
+ raise InvalidJson("models shall be a list!")
+
+ for json_model in json_models:
+ logger.debug("json_model {}".format(json_model))
+ models = ModelManager.get_models(self._user_id)
+ model_in_db = None
+ model_id = None
+ for model_key in models:
+ if ("id" in json_model and model_key == json_model["id"]) or (
+ "name" in json_model and models[model_key]["name"] == json_model["name"]):
+ model_in_db = models[model_key]
+ model_id = model_key
+
+ # this should not occur as the model has been put in db previously in _import_models_without_new_meta_rules
+ if model_in_db is None:
+ raise UnknownModel("Unknown model ")
+
+ json_key = dict()
+ JsonUtils.convert_names_to_ids(json_model, json_key, "meta_rules", "meta_rule_id",
+ "meta_rule", ModelManager, self._user_id)
+ for meta_rule_id in json_key["meta_rule_id"]:
+ if meta_rule_id not in model_in_db["meta_rules"]:
+ model_in_db["meta_rules"].append(meta_rule_id)
+
+ ModelManager.update_model(self._user_id, model_id, model_in_db)
+
+ def _import_models_without_new_meta_rules(self, json_models):
+ if not isinstance(json_models, list):
+ raise InvalidJson("models shall be a list!")
+
+ for json_model in json_models:
+ json_without_new_metarules = dict()
+ JsonUtils.copy_field_if_exists(json_model, json_without_new_metarules, "name", str)
+
+ # TODO put this in moondb
+ # model_in_db = ModelManager.get_models_by_name(json_without_new_metarules["name"])
+ models = ModelManager.get_models(self._user_id)
+ model_in_db = None
+ for model_key in models:
+ if models[model_key]["name"] == json_without_new_metarules["name"]:
+ model_in_db = models[model_key]
+ model_id = model_key
+ # end TODO
+
+ JsonUtils.copy_field_if_exists(json_model, json_without_new_metarules, "description",
+ str)
+ if model_in_db is None:
+ model_does_exist = False
+ else:
+ json_without_new_metarules["meta_rules"] = model_in_db["meta_rules"]
+ model_does_exist = True
+ model_override = JsonUtils.get_override(json_model)
+ if not model_does_exist:
+ logger.debug("Creating model {} ".format(json_without_new_metarules))
+ ModelManager.add_model(self._user_id, None, json_without_new_metarules)
+ elif model_override is True:
+ logger.debug(
+ "Updating model with id {} : {} ".format(model_id, json_without_new_metarules))
+ ModelManager.update_model(self._user_id, model_id, json_without_new_metarules)
+
+ def _import_pdps(self, json_pdps):
+ if not isinstance(json_pdps, list):
+ raise InvalidJson("pdps shall be a list!")
+
+ for json_pdp in json_pdps:
+ json_to_use = dict()
+ JsonUtils.copy_field_if_exists(json_pdp, json_to_use, "name", str)
+ JsonUtils.copy_field_if_exists(json_pdp, json_to_use, "keystone_project_id", str)
+ JsonUtils.copy_field_if_exists(json_pdp, json_to_use, "security_pipeline", list)
+ JsonUtils.copy_field_if_exists(json_pdp, json_to_use, "description", str)
+
+ pdps = PDPManager.get_pdp(self._user_id)
+ exists = False
+ for pdp_key in pdps:
+ if pdps[pdp_key]["name"] == json_to_use["name"]:
+ PDPManager.update_pdp(self._user_id, pdp_id=pdp_key, value=json_to_use)
+ exists = True
+ if exists is False:
+ PDPManager.add_pdp(self._user_id, value=json_to_use)
+
+ def _import_json(self, user_id):
+ self._user_id = user_id
+ if 'file' in request.files:
+ file = request.files['file']
+ logger.debug("Importing {} file...".format(file))
+ json_content = json.load(file)
+ else:
+ json_content = request.json
+ logger.debug("Importing content: {} ...".format(json_content))
+
+ # first import the models without the meta rules as they are not yet defined
+ if "models" in json_content:
+ logger.info("Importing models...")
+ self._import_models_without_new_meta_rules(json_content["models"])
+
+ # import the policies that depends on the models
+ mandatory_policy_ids = []
+ if "policies" in json_content:
+ logger.info("Importing policies...")
+ mandatory_policy_ids = self._import_policies(json_content["policies"])
+
+ # import subjects, subject_data, subject_categories, idem for object and action
+ list_element = [{"key": "subject"}, {"key": "object"}, {"key": "action"}]
+ for elt in list_element:
+ in_key = elt["key"]
+ key = in_key + "s"
+ if key in json_content:
+ logger.info("Importing {}...".format(key))
+ self._import_subject_object_action(json_content[key], mandatory_policy_ids, in_key)
+ key = in_key + "_categories"
+ if key in json_content:
+ logger.info("Importing {}...".format(key))
+ self._import_subject_object_action_categories(json_content[key], in_key)
+
+ # import meta rules
+ if "meta_rules" in json_content:
+ logger.info("Importing meta rules...")
+ self._import_meta_rules(json_content["meta_rules"])
+
+ # add the metarule to model
+ if "models" in json_content:
+ logger.info("Updating models with meta rules...")
+ self._import_models_with_new_meta_rules(json_content["models"])
+
+ for elt in list_element:
+ in_key = elt["key"]
+ key = in_key + "_data"
+ if key in json_content:
+ logger.info("Importing {}...".format(key))
+ self._import_subject_object_action_datas(json_content[key], mandatory_policy_ids,
+ in_key)
+
+ # import subjects assignments, idem for object and action
+ for elt in list_element:
+ in_key = elt["key"]
+ key = in_key + "_assignments"
+ if key in json_content:
+ logger.info("Importing {}...".format(key))
+ self._import_subject_object_action_assignments(json_content[key], in_key)
+
+ # import rules
+ if "rules" in json_content:
+ logger.info("Importing rules...")
+ self._import_rules(json_content["rules"])
+
+ # import pdps
+ if "pdps" in json_content:
+ logger.info("Importing pdps...")
+ self._import_pdps(json_content["pdps"])
+
+ @check_auth
+ def post(self, user_id=None):
+ """Import file.
+
+ :param user_id: user ID who do the request
+ :return: {
+
+ }
+ :internal_api:
+ """
+ self._import_json(user_id)
+ return "Import ok !"
diff --git a/old/moon_manager/moon_manager/api/json_utils.py b/old/moon_manager/moon_manager/api/json_utils.py
new file mode 100644
index 00000000..6a5830f1
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/json_utils.py
@@ -0,0 +1,282 @@
+import logging
+from moon_manager.api.base_exception import BaseException
+
+logger = logging.getLogger("moon.manager.api." + __name__)
+
+
+class UnknownName(BaseException):
+ def __init__(self, message):
+ # Call the base class constructor with the parameters it needs
+ super(UnknownName, self).__init__(message)
+
+
+class UnknownId(BaseException):
+ def __init__(self, message):
+ # Call the base class constructor with the parameters it needs
+ super(UnknownId, self).__init__(message)
+
+
+class MissingIdOrName(BaseException):
+ def __init__(self, message):
+ # Call the base class constructor with the parameters it needs
+ super(MissingIdOrName, self).__init__(message)
+
+
+class UnknownField(BaseException):
+ def __init__(self, message):
+ # Call the base class constructor with the parameters it needs
+ super(UnknownField, self).__init__(message)
+
+
+class JsonUtils:
+ @staticmethod
+ def get_override(json_content):
+ if "override" in json_content:
+ return json_content["override"]
+ return False
+
+ @staticmethod
+ def get_mandatory(json_content):
+ if "mandatory" in json_content:
+ return json_content["mandatory"]
+ return False
+
+ @staticmethod
+ def copy_field_if_exists(json_in, json_out, field_name, type_field, default_value=None):
+ if field_name in json_in:
+ json_out[field_name] = json_in[field_name]
+ else:
+ if type_field is bool:
+ if default_value is None:
+ default_value = False
+ json_out[field_name] = default_value
+ if type_field is str:
+ if default_value is None:
+ default_value = ""
+ json_out[field_name] = default_value
+ if type_field is dict:
+ json_out[field_name] = dict()
+ if type_field is list:
+ json_out[field_name] = []
+
+ @staticmethod
+ def _get_element_in_db_from_id(element_type, element_id, user_id, policy_id, category_id,
+ meta_rule_id, manager):
+ # the item is supposed to be in the db, we check it exists!
+ if element_type == "model":
+ data_db = manager.get_models(user_id, model_id=element_id)
+ elif element_type == "policy":
+ data_db = manager.get_policies(user_id, policy_id=element_id)
+ elif element_type == "subject":
+ data_db = manager.get_subjects(user_id, policy_id, perimeter_id=element_id)
+ elif element_type == "object":
+ data_db = manager.get_objects(user_id, policy_id, perimeter_id=element_id)
+ elif element_type == "action":
+ data_db = manager.get_actions(user_id, policy_id, perimeter_id=element_id)
+ elif element_type == "subject_category":
+ data_db = manager.get_subject_categories(user_id, category_id=element_id)
+ elif element_type == "object_category":
+ data_db = manager.get_object_categories(user_id, category_id=element_id)
+ elif element_type == "action_category":
+ data_db = manager.get_action_categories(user_id, category_id=element_id)
+ elif element_type == "meta_rule":
+ data_db = manager.get_meta_rules(user_id, meta_rule_id=element_id)
+ elif element_type == "subject_data":
+ data_db = manager.get_subject_data(user_id, policy_id, data_id=element_id,
+ category_id=category_id)
+ elif element_type == "object_data":
+ data_db = manager.get_object_data(user_id, policy_id, data_id=element_id,
+ category_id=category_id)
+ elif element_type == "action_data":
+ data_db = manager.get_action_data(user_id, policy_id, data_id=element_id,
+ category_id=category_id)
+ elif element_type == "meta_rule":
+ data_db = manager.get_meta_rules(user_id, meta_rule_id=meta_rule_id)
+ else:
+ raise Exception("Conversion of {} not implemented yet!".format(element_type))
+
+ # logger.info(data_db)
+
+ # do some post processing ... the result should be {key : { .... .... } }
+ if element_type == "subject_data" or element_type == "object_data" or element_type == "action_data":
+ if data_db is not None and isinstance(data_db, list):
+ # TODO remove comments after fixing the bug on moondb when adding metarule : we can have several identical entries !
+ # if len(data_db) > 1:
+ # raise Exception("Several {} with the same id : {}".format(element_type, data_db))
+ data_db = data_db[0]
+
+ if data_db is not None and data_db["data"] is not None and isinstance(data_db["data"],
+ dict):
+ # TODO remove comments after fixing the bug on moondb when adding metarule : we can have several identical entries !
+ # if len(data_db["data"].values()) != 1:
+ # raise Exception("Several {} with the same id : {}".format(element_type, data_db))
+ # data_db = data_db["data"]
+ # TODO remove these two lines after fixing the bug on moondb when adding metarule : we can have several identical entries !
+ list_values = list(data_db["data"].values())
+ data_db = list_values[0]
+ # logger.info("subject data after postprocessing {}".format(data_db))
+ return data_db
+
+ @staticmethod
+ def _get_element_id_in_db_from_name(element_type, element_name, user_id, policy_id, category_id,
+ meta_rule_id, manager):
+ if element_type == "model":
+ data_db = manager.get_models(user_id)
+ elif element_type == "policy":
+ data_db = manager.get_policies(user_id)
+ elif element_type == "subject":
+ data_db = manager.get_subjects(user_id, policy_id)
+ elif element_type == "object":
+ data_db = manager.get_objects(user_id, policy_id)
+ elif element_type == "action":
+ data_db = manager.get_actions(user_id, policy_id)
+ elif element_type == "subject_category":
+ data_db = manager.get_subject_categories(user_id)
+ elif element_type == "object_category":
+ data_db = manager.get_object_categories(user_id)
+ elif element_type == "action_category":
+ data_db = manager.get_action_categories(user_id)
+ elif element_type == "meta_rule":
+ data_db = manager.get_meta_rules(user_id)
+ elif element_type == "subject_data":
+ data_db = manager.get_subject_data(user_id, policy_id, category_id=category_id)
+ elif element_type == "object_data":
+ data_db = manager.get_object_data(user_id, policy_id, category_id=category_id)
+ elif element_type == "action_data":
+ data_db = manager.get_action_data(user_id, policy_id, category_id=category_id)
+ elif element_type == "meta_rule":
+ data_db = manager.get_meta_rules(user_id)
+ elif element_type == "rule":
+ data_db = manager.get_rules(user_id, policy_id)
+ else:
+ raise BaseException("Conversion of {} not implemented yet!".format(element_type))
+
+ if isinstance(data_db, dict):
+ for key_id in data_db:
+ if isinstance(data_db[key_id], dict) and "name" in data_db[key_id]:
+ if data_db[key_id]["name"] == element_name:
+ return key_id
+ else:
+ for elt in data_db:
+ if isinstance(elt,
+ dict) and "data" in elt: # we handle here subject_data, object_data and action_data...
+ for data_key in elt["data"]:
+ # logger.info("data from the db {} ".format(elt["data"][data_key]))
+ data = elt["data"][data_key]
+ if "name" in data and data["name"] == element_name:
+ return data_key
+ if "value" in data and data["value"]["name"] == element_name:
+ return data_key
+ return None
+
+ @staticmethod
+ def convert_name_to_id(json_in, json_out, field_name_in, field_name_out, element_type, manager,
+ user_id, policy_id=None, category_id=None, meta_rule_id=None,
+ field_mandatory=True):
+ if field_name_in not in json_in:
+ raise UnknownField("The field {} is not in the input json".format(field_name_in))
+
+ if "id" in json_in[field_name_in]:
+ data_db = JsonUtils._get_element_in_db_from_id(element_type,
+ json_in[field_name_in]["id"], user_id,
+ policy_id, category_id, meta_rule_id,
+ manager)
+ if data_db is None:
+ raise UnknownId("No {} with id {} found in database".format(element_type,
+ json_in[field_name_in]["id"]))
+ json_out[field_name_out] = json_in[field_name_in]["id"]
+
+ elif "name" in json_in[field_name_in]:
+ id_in_db = JsonUtils._get_element_id_in_db_from_name(element_type,
+ json_in[field_name_in]["name"],
+ user_id, policy_id, category_id,
+ meta_rule_id, manager)
+ if id_in_db is None:
+ raise UnknownName(
+ "No {} with name {} found in database".format(element_type,
+ json_in[field_name_in]["name"]))
+ json_out[field_name_out] = id_in_db
+ elif field_mandatory is True:
+ raise MissingIdOrName("No id or name found in the input json {}".format(json_in))
+
+ @staticmethod
+ def convert_id_to_name(id_, json_out, field_name_out, element_type, manager, user_id,
+ policy_id=None, category_id=None, meta_rule_id=None):
+ json_out[field_name_out] = {
+ "name": JsonUtils.convert_id_to_name_string(id_, element_type, manager, user_id,
+ policy_id, category_id, meta_rule_id)}
+
+ @staticmethod
+ def __convert_results_to_element(element):
+ if isinstance(element, dict) and "name" not in element and "value" not in element:
+ list_values = [v for v in element.values()]
+ elif isinstance(element, list):
+ list_values = element
+ else:
+ list_values = []
+ list_values.append(element)
+ return list_values[0]
+
+ @staticmethod
+ def convert_id_to_name_string(id_, element_type, manager, user_id,
+ policy_id=None, category_id=None, meta_rule_id=None):
+
+ element = JsonUtils._get_element_in_db_from_id(element_type, id_, user_id, policy_id,
+ category_id, meta_rule_id, manager)
+ # logger.info(element)
+ if element is None:
+ raise UnknownId("No {} with id {} found in database".format(element_type, id_))
+ res = JsonUtils.__convert_results_to_element(element)
+ # logger.info(res)
+ if "name" in res:
+ return res["name"]
+ if "value" in res and "name" in res["value"]:
+ return res["value"]["name"]
+ return None
+
+ @staticmethod
+ def convert_names_to_ids(json_in, json_out, field_name_in, field_name_out, element_type,
+ manager, user_id, policy_id=None, category_id=None, meta_rule_id=None,
+ field_mandatory=True):
+ ids = []
+ if field_name_in not in json_in:
+ raise UnknownField("The field {} is not in the input json".format(field_name_in))
+
+ for elt in json_in[field_name_in]:
+ if "id" in elt:
+ data_db = JsonUtils._get_element_in_db_from_id(element_type, elt["id"], user_id,
+ policy_id, category_id,
+ meta_rule_id, manager)
+ if data_db is None:
+ raise UnknownId(
+ "No {} with id {} found in database".format(element_type, elt["id"]))
+ ids.append(elt["id"])
+ elif "name" in elt:
+ id_in_db = JsonUtils._get_element_id_in_db_from_name(element_type, elt["name"],
+ user_id, policy_id,
+ category_id, meta_rule_id,
+ manager)
+ if id_in_db is None:
+ raise UnknownName(
+ "No {} with name {} found in database".format(element_type, elt["name"]))
+ ids.append(id_in_db)
+ elif field_mandatory is True:
+ raise MissingIdOrName("No id or name found in the input json {}".format(elt))
+ json_out[field_name_out] = ids
+
+ @staticmethod
+ def convert_ids_to_names(ids, json_out, field_name_out, element_type, manager, user_id,
+ policy_id=None, category_id=None, meta_rule_id=None):
+ res_array = []
+ for id_ in ids:
+ element = JsonUtils._get_element_in_db_from_id(element_type, id_, user_id, policy_id,
+ category_id, meta_rule_id, manager)
+ if element is None:
+ raise UnknownId("No {} with id {} found in database".format(element_type, id_))
+ res = JsonUtils.__convert_results_to_element(element)
+ # logger.info(res)
+ if "name" in res:
+ res_array.append({"name": res["name"]})
+ if "value" in res and "name" in res["value"]:
+ res_array.append({"name": res["value"]["name"]})
+ json_out[field_name_out] = res_array
diff --git a/old/moon_manager/moon_manager/api/meta_data.py b/old/moon_manager/moon_manager/api/meta_data.py
new file mode 100644
index 00000000..b0b86d10
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/meta_data.py
@@ -0,0 +1,246 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Meta Data are elements used to create Meta data (skeleton of security policies)
+
+"""
+
+from flask import request
+from flask_restful import Resource
+import logging
+from python_moonutilities.security_functions import check_auth
+from python_moondb.core import ModelManager
+from python_moonutilities.security_functions import validate_input
+
+__version__ = "4.3.2"
+
+logger = logging.getLogger("moon.manager.api." + __name__)
+
+
+class SubjectCategories(Resource):
+ """
+ Endpoint for subject categories requests
+ """
+
+ __urls__ = (
+ "/subject_categories",
+ "/subject_categories/",
+ "/subject_categories/<string:category_id>",
+ )
+
+ @validate_input("get", kwargs_state=[False, False])
+ @check_auth
+ def get(self, category_id=None, user_id=None):
+ """Retrieve all subject categories or a specific one
+
+ :param category_id: uuid of the subject category
+ :param user_id: user ID who do the request
+ :return: {
+ "subject_category_id": {
+ "name": "name of the category",
+ "description": "description of the category (optional)"
+ }
+ }
+ :internal_api: get_subject_categories
+ """
+ data = ModelManager.get_subject_categories(
+ user_id=user_id, category_id=category_id)
+
+ return {"subject_categories": data}
+
+ @validate_input("post", body_state={"name": True})
+ @check_auth
+ def post(self, category_id=None, user_id=None):
+ """Create or update a subject category.
+
+ :param category_id: must not be used here
+ :param user_id: user ID who do the request
+ :request body: {
+ "name": "name of the category (mandatory)",
+ "description": "description of the category (optional)"
+ }
+ :return: {
+ "subject_category_id": {
+ "name": "name of the category",
+ "description": "description of the category (optional)"
+ }
+ }
+ :internal_api: add_subject_category
+ """
+ data = ModelManager.add_subject_category(
+ user_id=user_id, value=request.json)
+
+ return {"subject_categories": data}
+
+ @validate_input("delete", kwargs_state=[True, False])
+ @check_auth
+ def delete(self, category_id=None, user_id=None):
+ """Delete a subject category
+
+ :param category_id: uuid of the subject category to delete
+ :param user_id: user ID who do the request
+ :return: {
+ "result": "True or False",
+ "message": "optional message (optional)"
+ }
+ :internal_api: delete_subject_category
+ """
+
+ data = ModelManager.delete_subject_category(
+ user_id=user_id, category_id=category_id)
+
+ return {"result": True}
+
+
+class ObjectCategories(Resource):
+ """
+ Endpoint for object categories requests
+ """
+
+ __urls__ = (
+ "/object_categories",
+ "/object_categories/",
+ "/object_categories/<string:category_id>",
+ )
+
+ @validate_input("get", kwargs_state=[False, False])
+ @check_auth
+ def get(self, category_id=None, user_id=None):
+ """Retrieve all object categories or a specific one
+
+ :param category_id: uuid of the object category
+ :param user_id: user ID who do the request
+ :return: {
+ "object_category_id": {
+ "name": "name of the category",
+ "description": "description of the category (optional)"
+ }
+ }
+ :internal_api: get_object_categories
+ """
+ data = ModelManager.get_object_categories(
+ user_id=user_id, category_id=category_id)
+
+ return {"object_categories": data}
+
+ @validate_input("post", body_state={"name": True})
+ @check_auth
+ def post(self, category_id=None, user_id=None):
+ """Create or update a object category.
+
+ :param category_id: must not be used here
+ :param user_id: user ID who do the request
+ :request body: {
+ "name": "name of the category (mandatory)",
+ "description": "description of the category (optional)"
+ }
+ :return: {
+ "object_category_id": {
+ "name": "name of the category",
+ "description": "description of the category (optional)"
+ }
+ }
+ :internal_api: add_object_category
+ """
+
+ data = ModelManager.add_object_category(
+ user_id=user_id, value=request.json)
+
+ return {"object_categories": data}
+
+ @validate_input("delete", kwargs_state=[True, False])
+ @check_auth
+ def delete(self, category_id=None, user_id=None):
+ """Delete an object category
+
+ :param category_id: uuid of the object category to delete
+ :param user_id: user ID who do the request
+ :return: {
+ "result": "True or False",
+ "message": "optional message (optional)"
+ }
+ :internal_api: delete_object_category
+ """
+
+ data = ModelManager.delete_object_category(
+ user_id=user_id, category_id=category_id)
+
+ return {"result": True}
+
+
+class ActionCategories(Resource):
+ """
+ Endpoint for action categories requests
+ """
+
+ __urls__ = (
+ "/action_categories",
+ "/action_categories/",
+ "/action_categories/<string:category_id>",
+ )
+
+ @validate_input("get", kwargs_state=[False, False])
+ @check_auth
+ def get(self, category_id=None, user_id=None):
+ """Retrieve all action categories or a specific one
+
+ :param category_id: uuid of the action category
+ :param user_id: user ID who do the request
+ :return: {
+ "action_category_id": {
+ "name": "name of the category",
+ "description": "description of the category (optional)"
+ }
+ }
+ :internal_api: get_action_categories
+ """
+
+ data = ModelManager.get_action_categories(
+ user_id=user_id, category_id=category_id)
+
+ return {"action_categories": data}
+
+ @validate_input("post", body_state={"name": True})
+ @check_auth
+ def post(self, category_id=None, user_id=None):
+ """Create or update an action category.
+
+ :param category_id: must not be used here
+ :param user_id: user ID who do the request
+ :request body: {
+ "name": "name of the category (mandatory)",
+ "description": "description of the category (optional)"
+ }
+ :return: {
+ "action_category_id": {
+ "name": "name of the category",
+ "description": "description of the category (optional)"
+ }
+ }
+ :internal_api: add_action_category
+ """
+
+ data = ModelManager.add_action_category(
+ user_id=user_id, value=request.json)
+
+ return {"action_categories": data}
+
+ @validate_input("delete", kwargs_state=[True, False])
+ @check_auth
+ def delete(self, category_id=None, user_id=None):
+ """Delete an action
+
+ :param category_id: uuid of the action category to delete
+ :param user_id: user ID who do the request
+ :return: {
+ "result": "True or False",
+ "message": "optional message (optional)"
+ }
+ :internal_api: delete_action_category
+ """
+ data = ModelManager.delete_action_category(
+ user_id=user_id, category_id=category_id)
+
+ return {"result": True}
diff --git a/old/moon_manager/moon_manager/api/meta_rules.py b/old/moon_manager/moon_manager/api/meta_rules.py
new file mode 100644
index 00000000..738aad71
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/meta_rules.py
@@ -0,0 +1,152 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Meta rules are skeleton for security policies
+
+"""
+
+from flask import request
+from flask_restful import Resource
+import logging
+from python_moonutilities.security_functions import check_auth
+from python_moondb.core import ModelManager
+from python_moonutilities.security_functions import validate_input
+
+__version__ = "4.3.2"
+
+logger = logging.getLogger("moon.manager.api." + __name__)
+
+
+class MetaRules(Resource):
+ """
+ Endpoint for meta rules requests
+ """
+
+ __urls__ = (
+ "/meta_rules",
+ "/meta_rules/",
+ "/meta_rules/<string:meta_rule_id>",
+ "/meta_rules/<string:meta_rule_id>/"
+ )
+
+ @validate_input("get", kwargs_state=[False, False])
+ @check_auth
+ def get(self, meta_rule_id=None, user_id=None):
+ """Retrieve all sub meta rules
+
+ :param meta_rule_id: Meta rule algorithm ID
+ :param user_id: user ID who do the request
+ :return: {
+ "meta_rules": {
+ "meta_rule_id1": {
+ "name": "name of the meta rule",
+ "subject_categories": ["subject_category_id1",
+ "subject_category_id2"],
+ "object_categories": ["object_category_id1"],
+ "action_categories": ["action_category_id1"]
+ },
+ }
+ }
+ :internal_api: get_meta_rules
+ """
+
+ data = ModelManager.get_meta_rules(
+ user_id=user_id, meta_rule_id=meta_rule_id)
+
+ return {"meta_rules": data}
+
+ @validate_input("post", body_state={"name": True, "subject_categories": False,
+ "object_categories": False, "action_categories": False})
+ @check_auth
+ def post(self, meta_rule_id=None, user_id=None):
+ """Add a meta rule
+
+ :param meta_rule_id: Meta rule ID (not used here)
+ :param user_id: user ID who do the request
+ :request body: post = {
+ "name": "name of the meta rule (mandatory)",
+ "subject_categories": ["subject_category_id1 (mandatory)",
+ "subject_category_id2"],
+ "object_categories": ["object_category_id1 (mandatory)"],
+ "action_categories": ["action_category_id1 (mandatory)"]
+ }
+ :return: {
+ "meta_rules": {
+ "meta_rule_id1": {
+ "name": "name of the meta rule",
+ "subject_categories": ["subject_category_id1",
+ "subject_category_id2"],
+ "object_categories": ["object_category_id1"],
+ "action_categories": ["action_category_id1"]
+ },
+ }
+ }
+ :internal_api: add_meta_rules
+ """
+
+ data = ModelManager.add_meta_rule(
+ user_id=user_id, meta_rule_id=None, value=request.json)
+
+ return {"meta_rules": data}
+
+ @validate_input("patch", kwargs_state=[True, False],
+ body_state={"name": True, "subject_categories": False,
+ "object_categories": False, "action_categories": False})
+ @check_auth
+ def patch(self, meta_rule_id=None, user_id=None):
+ """Update a meta rule
+
+ :param meta_rule_id: Meta rule ID
+ :param user_id: user ID who do the request
+ :request body: patch = {
+ "name": "name of the meta rule",
+ "subject_categories": ["subject_category_id1",
+ "subject_category_id2"],
+ "object_categories": ["object_category_id1"],
+ "action_categories": ["action_category_id1"]
+ }
+ :return: {
+ "meta_rules": {
+ "meta_rule_id1": {
+ "name": "name of the meta rule",
+ "subject_categories": ["subject_category_id1",
+ "subject_category_id2"],
+ "object_categories": ["object_category_id1"],
+ "action_categories": ["action_category_id1"]
+ },
+ }
+ }
+ :internal_api: set_meta_rules
+ """
+ data = ModelManager.update_meta_rule(
+ user_id=user_id, meta_rule_id=meta_rule_id, value=request.json)
+
+ return {"meta_rules": data}
+
+ @validate_input("delete", kwargs_state=[True, False])
+ @check_auth
+ def delete(self, meta_rule_id=None, user_id=None):
+ """Delete a meta rule
+
+ :param meta_rule_id: Meta rule ID
+ :param user_id: user ID who do the request
+ :return: {
+ "meta_rules": {
+ "meta_rule_id1": {
+ "name": "name of the meta rule",
+ "subject_categories": ["subject_category_id1",
+ "subject_category_id2"],
+ "object_categories": ["object_category_id1"],
+ "action_categories": ["action_category_id1"]
+ },
+ }
+ }
+ :internal_api: delete_meta_rules
+ """
+
+ data = ModelManager.delete_meta_rule(
+ user_id=user_id, meta_rule_id=meta_rule_id)
+
+ return {"result": True}
diff --git a/old/moon_manager/moon_manager/api/models.py b/old/moon_manager/moon_manager/api/models.py
new file mode 100644
index 00000000..c72396cf
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/models.py
@@ -0,0 +1,117 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Models aggregate multiple meta rules
+"""
+
+from flask import request
+from flask_restful import Resource
+import logging
+from python_moonutilities.security_functions import check_auth
+from python_moondb.core import ModelManager
+from python_moonutilities.security_functions import validate_input
+
+__version__ = "4.3.2"
+
+logger = logging.getLogger("moon.manager.api." + __name__)
+
+
+class Models(Resource):
+ """
+ Endpoint for model requests
+ """
+
+ __urls__ = (
+ "/models",
+ "/models/",
+ "/models/<string:uuid>",
+ "/models/<string:uuid>/",
+ )
+
+ @validate_input("get", kwargs_state=[False, False])
+ @check_auth
+ def get(self, uuid=None, user_id=None):
+ """Retrieve all models
+
+ :param uuid: uuid of the model
+ :param user_id: user ID who do the request
+ :return: {
+ "model_id1": {
+ "name": "...",
+ "description": "... (optional)",
+ "meta_rules": ["meta_rule_id1", ]
+ }
+ }
+ :internal_api: get_models
+ """
+ data = ModelManager.get_models(user_id=user_id, model_id=uuid)
+
+ return {"models": data}
+
+ @validate_input("post", body_state={"name": True, "meta_rules": False})
+ @check_auth
+ def post(self, uuid=None, user_id=None):
+ """Create model.
+
+ :param uuid: uuid of the model (not used here)
+ :param user_id: user ID who do the request
+ :request body: {
+ "name": "name of the model (mandatory)",
+ "description": "description of the model (optional)",
+ "meta_rules": ["meta_rule_id1", ]
+ }
+ :return: {
+ "model_id1": {
+ "name": "name of the model",
+ "description": "description of the model (optional)",
+ "meta_rules": ["meta_rule_id1", ]
+ }
+ }
+ :internal_api: add_model
+ """
+ data = ModelManager.add_model(
+ user_id=user_id, model_id=uuid, value=request.json)
+
+ return {"models": data}
+
+ @validate_input("delete", kwargs_state=[True, False])
+ @check_auth
+ def delete(self, uuid=None, user_id=None):
+ """Delete a model
+
+ :param uuid: uuid of the model to delete
+ :param user_id: user ID who do the request
+ :return: {
+ "result": "True or False",
+ "message": "optional message (optional)"
+ }
+ :internal_api: delete_model
+ """
+
+ data = ModelManager.delete_model(user_id=user_id, model_id=uuid)
+
+ return {"result": True}
+
+ @validate_input("patch", kwargs_state=[True, False],
+ body_state={"name": True, "meta_rules": False})
+ @check_auth
+ def patch(self, uuid=None, user_id=None):
+ """Update a model
+
+ :param uuid: uuid of the model to update
+ :param user_id: user ID who do the request
+ :return: {
+ "model_id1": {
+ "name": "name of the model",
+ "description": "... (optional)",
+ "meta_rules": ["meta_rule_id1", ]
+ }
+ }
+ :internal_api: update_model
+ """
+ data = ModelManager.update_model(
+ user_id=user_id, model_id=uuid, value=request.json)
+
+ return {"models": data}
diff --git a/old/moon_manager/moon_manager/api/pdp.py b/old/moon_manager/moon_manager/api/pdp.py
new file mode 100644
index 00000000..65a6a5f1
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/pdp.py
@@ -0,0 +1,214 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+PDP are Policy Decision Point.
+
+"""
+
+from flask import request
+from flask_restful import Resource
+import logging
+import requests
+import time
+from python_moonutilities.security_functions import check_auth
+from python_moondb.core import PDPManager
+from python_moondb.core import PolicyManager
+from python_moondb.core import ModelManager
+from python_moonutilities import configuration, exceptions
+from python_moonutilities.security_functions import validate_input
+
+__version__ = "4.3.2"
+
+logger = logging.getLogger("moon.manager.api." + __name__)
+
+
+def delete_pod(uuid):
+ conf = configuration.get_configuration("components/orchestrator")
+ hostname = conf["components/orchestrator"].get("hostname", "orchestrator")
+ port = conf["components/orchestrator"].get("port", 80)
+ proto = conf["components/orchestrator"].get("protocol", "http")
+ # while True:
+ # try:
+ url = "{}://{}:{}/pods".format(proto, hostname, port)
+ req = requests.get(url)
+ # except requests.exceptions.ConnectionError:
+ # logger.warning("Orchestrator is not ready, standby... {}".format(url))
+ # time.sleep(1)
+ # else:
+ # break
+ for pod_key, pod_list in req.json().get("pods", {}).items():
+ for pod_value in pod_list:
+ if "pdp_id" in pod_value:
+ if pod_value["pdp_id"] == uuid:
+ req = requests.delete(
+ "{}://{}:{}/pods/{}".format(proto, hostname, port, pod_key))
+ if req.status_code != 200:
+ logger.warning(
+ "Cannot delete pod {} - {}".format(pod_key, pod_value['name']))
+ logger.debug(req.content)
+ # Note (Asteroide): no need to go further if one match
+ break
+
+
+def add_pod(uuid, data):
+ if not data.get("keystone_project_id"):
+ return
+ logger.info("Add a new pod {}".format(data))
+ if "pdp_id" not in data:
+ data["pdp_id"] = uuid
+ data['policies'] = PolicyManager.get_policies(user_id="admin")
+ data['models'] = ModelManager.get_models(user_id="admin")
+ conf = configuration.get_configuration("components/orchestrator")
+ hostname = conf["components/orchestrator"].get("hostname", "orchestrator")
+ port = conf["components/orchestrator"].get("port", 80)
+ proto = conf["components/orchestrator"].get("protocol", "http")
+ while True:
+ try:
+ req = requests.post(
+ "{}://{}:{}/pods".format(proto, hostname, port),
+ json=data,
+ headers={"content-type": "application/json"})
+ except requests.exceptions.ConnectionError as e:
+ logger.warning("add_pod: Orchestrator is not ready, standby...")
+ logger.exception(e)
+ time.sleep(1)
+ else:
+ break
+ logger.info("Pod add request answer : {}".format(req.text))
+
+
+def check_keystone_pid(k_pid):
+ data = PDPManager.get_pdp(user_id="admin")
+ for pdp_key, pdp_value in data.items():
+ logger.info("pdp={}".format(pdp_value))
+ if pdp_value["keystone_project_id"] == k_pid:
+ return True
+
+
+class PDP(Resource):
+ """
+ Endpoint for pdp requests
+ """
+
+ __urls__ = (
+ "/pdp",
+ "/pdp/",
+ "/pdp/<string:uuid>",
+ "/pdp/<string:uuid>/",
+ )
+
+ @validate_input("get", kwargs_state=[False, False])
+ @check_auth
+ def get(self, uuid=None, user_id=None):
+ """Retrieve all pdp
+
+ :param uuid: uuid of the pdp
+ :param user_id: user ID who do the request
+ :return: {
+ "pdp_id1": {
+ "name": "...",
+ "security_pipeline": [...],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "... (optional)",
+ }
+ }
+ :internal_api: get_pdp
+ """
+
+ data = PDPManager.get_pdp(user_id=user_id, pdp_id=uuid)
+
+ return {"pdps": data}
+
+ @validate_input("post", body_state={"name": True, "security_pipeline": True,
+ "keystone_project_id": True})
+ @check_auth
+ def post(self, uuid=None, user_id=None):
+ """Create pdp.
+
+ :param uuid: uuid of the pdp (not used here)
+ :param user_id: user ID who do the request
+ :request body: {
+ "name": "name of the PDP (mandatory)",
+ "security_pipeline": ["may be empty"],
+ "keystone_project_id": "keystone_project_id1 (may be empty)",
+ "description": "description of the PDP (optional)",
+ }
+ :return: {
+ "pdp_id1": {
+ "name": "...",
+ "security_pipeline": [...],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "... (optional)",
+ }
+ }
+ :internal_api: add_pdp
+ """
+
+ data = dict(request.json)
+ if not data.get("keystone_project_id"):
+ data["keystone_project_id"] = None
+ else:
+ if check_keystone_pid(data.get("keystone_project_id")):
+ raise exceptions.PdpKeystoneMappingConflict
+ data = PDPManager.add_pdp(
+ user_id=user_id, pdp_id=None, value=request.json)
+ uuid = list(data.keys())[0]
+ logger.debug("data={}".format(data))
+ logger.debug("uuid={}".format(uuid))
+ add_pod(uuid=uuid, data=data[uuid])
+
+ return {"pdps": data}
+
+ @validate_input("delete", kwargs_state=[True, False])
+ @check_auth
+ def delete(self, uuid, user_id=None):
+ """Delete a pdp
+
+ :param uuid: uuid of the pdp to delete
+ :param user_id: user ID who do the request
+ :return: {
+ "result": "True or False",
+ "message": "optional message (optional)"
+ }
+ :internal_api: delete_pdp
+ """
+ data = PDPManager.delete_pdp(user_id=user_id, pdp_id=uuid)
+ delete_pod(uuid)
+
+ return {"result": True}
+
+ @validate_input("patch", kwargs_state=[True, False],
+ body_state={"name": True, "security_pipeline": True,
+ "keystone_project_id": True})
+ @check_auth
+ def patch(self, uuid, user_id=None):
+ """Update a pdp
+
+ :param uuid: uuid of the pdp to update
+ :param user_id: user ID who do the request
+ :return: {
+ "pdp_id1": {
+ "name": "name of the PDP",
+ "security_pipeline": ["may be empty"],
+ "keystone_project_id": "keystone_project_id1 (may be empty)",
+ "description": "description of the PDP (optional)",
+ }
+ }
+ :internal_api: update_pdp
+ """
+
+ _data = dict(request.json)
+ if not _data.get("keystone_project_id"):
+ _data["keystone_project_id"] = None
+ else:
+ if check_keystone_pid(_data.get("keystone_project_id")):
+ raise exceptions.PdpKeystoneMappingConflict
+ data = PDPManager.update_pdp(
+ user_id=user_id, pdp_id=uuid, value=_data)
+ logger.debug("data={}".format(data))
+ logger.debug("uuid={}".format(uuid))
+ add_pod(uuid=uuid, data=data[uuid])
+
+ return {"pdps": data}
diff --git a/old/moon_manager/moon_manager/api/perimeter.py b/old/moon_manager/moon_manager/api/perimeter.py
new file mode 100644
index 00000000..a0fda4ad
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/perimeter.py
@@ -0,0 +1,375 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+* Subjects are the source of an action on an object
+ (examples : users, virtual machines)
+* Objects are the destination of an action
+ (examples virtual machines, virtual Routers)
+* Actions are what subject wants to do on an object
+"""
+
+from flask import request
+from flask_restful import Resource
+import logging
+from python_moonutilities.security_functions import check_auth
+from python_moondb.core import PolicyManager
+from python_moonutilities.security_functions import validate_input
+
+__version__ = "4.3.2"
+
+logger = logging.getLogger("moon.manager.api." + __name__)
+
+
+class Subjects(Resource):
+ """
+ Endpoint for subjects requests
+ """
+
+ __urls__ = (
+ "/subjects",
+ "/subjects/",
+ "/subjects/<string:perimeter_id>",
+ "/policies/<string:uuid>/subjects",
+ "/policies/<string:uuid>/subjects/",
+ "/policies/<string:uuid>/subjects/<string:perimeter_id>",
+ )
+
+ @validate_input("get", kwargs_state=[False, False, False])
+ @check_auth
+ def get(self, uuid=None, perimeter_id=None, user_id=None):
+ """Retrieve all subjects or a specific one if perimeter_id is
+ given for a given policy
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: uuid of the subject
+ :param user_id: user ID who do the request
+ :return: {
+ "subject_id": {
+ "name": "name of the subject",
+ "keystone_id": "keystone id of the subject",
+ "description": "a description (optional)"
+ }
+ }
+ :internal_api: get_subjects
+ """
+
+ data = PolicyManager.get_subjects(
+ user_id=user_id,
+ policy_id=uuid,
+ perimeter_id=perimeter_id
+ )
+
+ return {"subjects": data}
+
+ @validate_input("post", body_state={"name": True})
+ @check_auth
+ def post(self, uuid=None, perimeter_id=None, user_id=None):
+ """Create or update a subject.
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: must not be used here
+ :param user_id: user ID who do the request
+ :request body: {
+ "name": "name of the subject (mandatory)",
+ "description": "description of the subject (optional)",
+ "password": "password for the subject (optional)",
+ "email": "email address of the subject (optional)"
+ }
+ :return: {
+ "subject_id": {
+ "name": "name of the subject",
+ "keystone_id": "keystone id of the subject",
+ "description": "description of the subject (optional)",
+ "password": "password for the subject (optional)",
+ "email": "email address of the subject (optional)"
+ }
+ }
+ :internal_api: set_subject
+ """
+
+ data = PolicyManager.add_subject(
+ user_id=user_id, policy_id=uuid,
+ perimeter_id=perimeter_id, value=request.json)
+
+ return {"subjects": data}
+
+ @validate_input("patch", kwargs_state=[False, True, False])
+ @check_auth
+ def patch(self, uuid=None, perimeter_id=None, user_id=None):
+ """Create or update a subject.
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: must not be used here
+ :param user_id: user ID who do the request
+ :request body: {
+ "name": "name of the subject",
+ "description": "description of the subject (optional)",
+ "password": "password for the subject (optional)",
+ "email": "email address of the subject (optional)"
+ }
+ :return: {
+ "subject_id": {
+ "name": "name of the subject",
+ "keystone_id": "keystone id of the subject",
+ "description": "description of the subject (optional)",
+ "password": "password for the subject (optional)",
+ "email": "email address of the subject (optional)"
+ }
+ }
+ :internal_api: set_subject
+ """
+ data = PolicyManager.update_subject(user_id=user_id, perimeter_id=perimeter_id,
+ value=request.json)
+ return {"subjects": data}
+
+ @validate_input("delete", kwargs_state=[False, True, False])
+ @check_auth
+ def delete(self, uuid=None, perimeter_id=None, user_id=None):
+ """Delete a subject for a given policy
+
+ :param uuid: uuid of the policy (mandatory if perimeter_id is not set)
+ :param perimeter_id: uuid of the subject (mandatory if uuid is not set)
+ :param user_id: user ID who do the request
+ :return: {
+ "subject_id": {
+ "name": "name of the subject",
+ "keystone_id": "keystone id of the subject",
+ "description": "description of the subject (optional)",
+ "password": "password for the subject (optional)",
+ "email": "email address of the subject (optional)"
+ }
+ }
+ :internal_api: delete_subject
+ """
+
+ data = PolicyManager.delete_subject(
+ user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id)
+
+ return {"result": True}
+
+
+class Objects(Resource):
+ """
+ Endpoint for objects requests
+ """
+
+ __urls__ = (
+ "/objects",
+ "/objects/",
+ "/objects/<string:perimeter_id>",
+ "/policies/<string:uuid>/objects",
+ "/policies/<string:uuid>/objects/",
+ "/policies/<string:uuid>/objects/<string:perimeter_id>",
+ )
+
+ @validate_input("get", kwargs_state=[False, False, False])
+ @check_auth
+ def get(self, uuid=None, perimeter_id=None, user_id=None):
+ """Retrieve all objects or a specific one if perimeter_id is
+ given for a given policy
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: uuid of the object
+ :param user_id: user ID who do the request
+ :return: {
+ "object_id": {
+ "name": "name of the object",
+ "description": "description of the object (optional)"
+ }
+ }
+ :internal_api: get_objects
+ """
+
+ data = PolicyManager.get_objects(
+ user_id=user_id,
+ policy_id=uuid,
+ perimeter_id=perimeter_id
+ )
+
+ return {"objects": data}
+
+ @validate_input("post", body_state={"name": True})
+ @check_auth
+ def post(self, uuid=None, perimeter_id=None, user_id=None):
+ """Create or update a object.
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: must not be used here
+ :param user_id: user ID who do the request
+ :request body: {
+ "object_name": "name of the object (mandatory)",
+ "object_description": "description of the object (optional)"
+ }
+ :return: {
+ "object_id": {
+ "name": "name of the object",
+ "description": "description of the object (optional)"
+ }
+ }
+ :internal_api: set_object
+ """
+ data = PolicyManager.add_object(
+ user_id=user_id, policy_id=uuid,
+ perimeter_id=perimeter_id, value=request.json)
+
+ return {"objects": data}
+
+ @validate_input("patch", kwargs_state=[False, True, False])
+ @check_auth
+ def patch(self, uuid=None, perimeter_id=None, user_id=None):
+ """Create or update a object.
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: must not be used here
+ :param user_id: user ID who do the request
+ :request body: {
+ "object_name": "name of the object",
+ "object_description": "description of the object (optional)"
+ }
+ :return: {
+ "object_id": {
+ "name": "name of the object",
+ "description": "description of the object (optional)"
+ }
+ }
+ :internal_api: set_object
+ """
+ data = PolicyManager.update_object(user_id=user_id, perimeter_id=perimeter_id,
+ value=request.json)
+
+ return {"objects": data}
+
+ @validate_input("delete", kwargs_state=[False, True, False])
+ @check_auth
+ def delete(self, uuid=None, perimeter_id=None, user_id=None):
+ """Delete a object for a given policy
+
+ :param uuid: uuid of the policy (mandatory if perimeter_id is not set)
+ :param perimeter_id: uuid of the object (mandatory if uuid is not set)
+ :param user_id: user ID who do the request
+ :return: {
+ "object_id": {
+ "name": "name of the object",
+ "description": "description of the object (optional)"
+ }
+ }
+ :internal_api: delete_object
+ """
+
+ data = PolicyManager.delete_object(
+ user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id)
+
+ return {"result": True}
+
+
+class Actions(Resource):
+ """
+ Endpoint for actions requests
+ """
+
+ __urls__ = (
+ "/actions",
+ "/actions/",
+ "/actions/<string:perimeter_id>",
+ "/policies/<string:uuid>/actions",
+ "/policies/<string:uuid>/actions/",
+ "/policies/<string:uuid>/actions/<string:perimeter_id>",
+ )
+
+ @validate_input("get", kwargs_state=[False, False, False])
+ @check_auth
+ def get(self, uuid=None, perimeter_id=None, user_id=None):
+ """Retrieve all actions or a specific one if perimeter_id
+ is given for a given policy
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: uuid of the action
+ :param user_id: user ID who do the request
+ :return: {
+ "action_id": {
+ "name": "name of the action",
+ "description": "description of the action (optional)"
+ }
+ }
+ :internal_api: get_actions
+ """
+
+ data = PolicyManager.get_actions(
+ user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id)
+
+ return {"actions": data}
+
+ @validate_input("post", body_state={"name": True})
+ @check_auth
+ def post(self, uuid=None, perimeter_id=None, user_id=None):
+ """Create or update a action.
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: must not be used here
+ :param user_id: user ID who do the request
+ :request body: {
+ "name": "name of the action (mandatory)",
+ "description": "description of the action (optional)"
+ }
+ :return: {
+ "action_id": {
+ "name": "name of the action",
+ "description": "description of the action (optional)"
+ }
+ }
+ :internal_api: set_action
+ """
+ data = PolicyManager.add_action(
+ user_id=user_id, policy_id=uuid,
+ perimeter_id=perimeter_id, value=request.json)
+
+ return {"actions": data}
+
+ @validate_input("patch", kwargs_state=[False, True, False])
+ @check_auth
+ def patch(self, uuid=None, perimeter_id=None, user_id=None):
+ """Create or update a action.
+
+ :param uuid: uuid of the policy
+ :param perimeter_id: must not be used here
+ :param user_id: user ID who do the request
+ :request body: {
+ "name": "name of the action",
+ "description": "description of the action (optional)"
+ }
+ :return: {
+ "action_id": {
+ "name": "name of the action",
+ "description": "description of the action (optional)"
+ }
+ }
+ :internal_api: set_action
+ """
+ data = PolicyManager.update_action(user_id=user_id, perimeter_id=perimeter_id,
+ value=request.json)
+
+ return {"actions": data}
+
+ @validate_input("delete", kwargs_state=[False, True, False])
+ @check_auth
+ def delete(self, uuid=None, perimeter_id=None, user_id=None):
+ """Delete a action for a given policy
+
+ :param uuid: uuid of the policy (mandatory if perimeter_id is not set)
+ :param perimeter_id: uuid of the action (mandatory if uuid is not set)
+ :param user_id: user ID who do the request
+ :return: {
+ "action_id": {
+ "name": "name of the action",
+ "description": "description of the action (optional)"
+ }
+ }
+ :internal_api: delete_action
+ """
+
+ data = PolicyManager.delete_action(
+ user_id=user_id, policy_id=uuid, perimeter_id=perimeter_id)
+
+ return {"result": True}
diff --git a/old/moon_manager/moon_manager/api/policies.py b/old/moon_manager/moon_manager/api/policies.py
new file mode 100644
index 00000000..3264e8e0
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/policies.py
@@ -0,0 +1,125 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Policies are instances of security models and implement security policies
+
+"""
+
+from flask import request
+from flask_restful import Resource
+import logging
+from python_moonutilities.security_functions import check_auth
+from python_moondb.core import PolicyManager
+from python_moonutilities.security_functions import validate_input
+
+__version__ = "4.3.2"
+
+logger = logging.getLogger("moon.manager.api." + __name__)
+
+
+class Policies(Resource):
+ """
+ Endpoint for policy requests
+ """
+
+ __urls__ = (
+ "/policies",
+ "/policies/",
+ "/policies/<string:uuid>",
+ "/policies/<string:uuid>/",
+ )
+
+ @validate_input("get", kwargs_state=[False, False])
+ @check_auth
+ def get(self, uuid=None, user_id=None):
+ """Retrieve all policies
+
+ :param uuid: uuid of the policy
+ :param user_id: user ID who do the request
+ :return: {
+ "policy_id1": {
+ "name": "name of the policy (mandatory)",
+ "model_id": "ID of the model linked to this policy",
+ "genre": "authz of admin (optional, default to authz)",
+ "description": "description of the policy (optional)",
+ }
+ }
+ :internal_api: get_policies
+ """
+
+ data = PolicyManager.get_policies(user_id=user_id, policy_id=uuid)
+
+ return {"policies": data}
+
+ @validate_input("post", body_state={"name": True, "model_id": False})
+ @check_auth
+ def post(self, uuid=None, user_id=None):
+ """Create policy.
+
+ :param uuid: uuid of the policy (not used here if a new policy is created)
+ :param user_id: user ID who do the request
+ :request body: {
+ "name": "name of the policy (mandatory)",
+ "model_id": "ID of the model linked to this policy",
+ "genre": "authz of admin (optional, default to authz)",
+ "description": "description of the policy (optional)",
+ }
+ :return: {
+ "policy_id1": {
+ "name": "name of the policy (mandatory)",
+ "model_id": "ID of the model linked to this policy",
+ "genre": "authz of admin (optional, default to authz)",
+ "description": "description of the policy (optional)",
+ }
+ }
+ :internal_api: add_policy
+ """
+
+ data = PolicyManager.add_policy(
+ user_id=user_id, policy_id=uuid, value=request.json)
+
+ return {"policies": data}
+
+ @validate_input("delete", kwargs_state=[True, False])
+ @check_auth
+ def delete(self, uuid=None, user_id=None):
+ """Delete a policy
+
+ :param uuid: uuid of the policy to delete
+ :param user_id: user ID who do the request
+ :return: {
+ "result": "True or False",
+ "message": "optional message (optional)"
+ }
+ :internal_api: delete_policy
+ """
+
+ data = PolicyManager.delete_policy(user_id=user_id, policy_id=uuid)
+
+ return {"result": True}
+
+ @validate_input("patch", kwargs_state=[True, False],
+ body_state={"name": True, "model_id": False})
+ @check_auth
+ def patch(self, uuid=None, user_id=None):
+ """Update a policy
+
+ :param uuid: uuid of the policy to update
+ :param user_id: user ID who do the request
+ :return: {
+ "policy_id1": {
+ "name": "name of the policy (mandatory)",
+ "model_id": "ID of the model linked to this policy",
+ "genre": "authz of admin (optional, default to authz)",
+ "description": "description of the policy (optional)",
+ }
+ }
+ :internal_api: update_policy
+ """
+
+ data = PolicyManager.update_policy(
+ user_id=user_id, policy_id=uuid, value=request.json)
+
+ return {"policies": data}
diff --git a/old/moon_manager/moon_manager/api/rules.py b/old/moon_manager/moon_manager/api/rules.py
new file mode 100644
index 00000000..cbd39969
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/rules.py
@@ -0,0 +1,135 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Rules (TODO)
+"""
+
+from flask import request
+from flask_restful import Resource
+import logging
+from python_moonutilities.security_functions import check_auth
+from python_moondb.core import PolicyManager
+from python_moonutilities.security_functions import validate_input
+
+__version__ = "4.3.2"
+
+logger = logging.getLogger("moon.manager.api." + __name__)
+
+
+class Rules(Resource):
+ """
+ Endpoint for rules requests
+ """
+
+ __urls__ = ("/policies/<string:uuid>/rules",
+ "/policies/<string:uuid>/rules/",
+ "/policies/<string:uuid>/rules/<string:rule_id>",
+ "/policies/<string:uuid>/rules/<string:rule_id>/",
+ )
+
+ @validate_input("get", kwargs_state=[False, False, False])
+ @check_auth
+ def get(self, uuid=None, rule_id=None, user_id=None):
+ """Retrieve all rules or a specific one
+
+ :param uuid: policy ID
+ :param rule_id: rule ID
+ :param user_id: user ID who do the request
+ :return: {
+ "rules": [
+ "policy_id": "policy_id1",
+ "meta_rule_id": "meta_rule_id1",
+ "rule_id1":
+ ["subject_data_id1", "subject_data_id2", "object_data_id1", "action_data_id1"],
+ "rule_id2":
+ ["subject_data_id3", "subject_data_id4", "object_data_id2", "action_data_id2"],
+ ]
+ }
+ :internal_api: get_rules
+ """
+
+ data = PolicyManager.get_rules(user_id=user_id,
+ policy_id=uuid,
+ rule_id=rule_id)
+
+ return {"rules": data}
+
+ @validate_input("post", kwargs_state=[True, False, False],
+ body_state={"meta_rule_id": True, "rule": True, "instructions": True})
+ @check_auth
+ def post(self, uuid=None, rule_id=None, user_id=None):
+ """Add a rule to a meta rule
+
+ :param uuid: policy ID
+ :param rule_id: rule ID (not used here)
+ :param user_id: user ID who do the request
+ :request body: post = {
+ "meta_rule_id": "meta_rule_id1", # mandatory
+ "rule": ["subject_data_id2", "object_data_id2", "action_data_id2"], # mandatory
+ "instructions": ( # mandatory
+ {"decision": "grant"},
+ )
+ "enabled": True
+ }
+ :return: {
+ "rules": [
+ "meta_rule_id": "meta_rule_id1",
+ "rule_id1": {
+ "rule": ["subject_data_id1",
+ "object_data_id1",
+ "action_data_id1"],
+ "instructions": (
+ {"decision": "grant"},
+ # "grant" to immediately exit,
+ # "continue" to wait for the result of next policy
+ # "deny" to deny the request
+ )
+ }
+ "rule_id2": {
+ "rule": ["subject_data_id2",
+ "object_data_id2",
+ "action_data_id2"],
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ # operations may be "add" or "delete"
+ "target": "rbac:role:admin"
+ # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}}
+ # chain with the policy named rbac
+ )
+ }
+ ]
+ }
+ :internal_api: add_rule
+ """
+ args = request.json
+
+ data = PolicyManager.add_rule(user_id=user_id,
+ policy_id=uuid,
+ meta_rule_id=args['meta_rule_id'],
+ value=args)
+
+ return {"rules": data}
+
+ @validate_input("delete", kwargs_state=[True, True, False])
+ @check_auth
+ def delete(self, uuid=None, rule_id=None, user_id=None):
+ """Delete one rule linked to a specific sub meta rule
+
+ :param uuid: policy ID
+ :param rule_id: rule ID
+ :param user_id: user ID who do the request
+ :return: { "result": true }
+ :internal_api: delete_rule
+ """
+
+ data = PolicyManager.delete_rule(
+ user_id=user_id, policy_id=uuid, rule_id=rule_id)
+
+ return {"result": True}
diff --git a/old/moon_manager/moon_manager/api/slaves.py b/old/moon_manager/moon_manager/api/slaves.py
new file mode 100644
index 00000000..e2928de0
--- /dev/null
+++ b/old/moon_manager/moon_manager/api/slaves.py
@@ -0,0 +1,111 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+PDP are Policy Decision Point.
+
+"""
+
+from flask import request
+from flask_restful import Resource
+import logging
+import requests
+from python_moonutilities.security_functions import check_auth
+
+from python_moonutilities import configuration
+from python_moonutilities.security_functions import validate_input
+
+__version__ = "4.3.0"
+
+logger = logging.getLogger("moon.manager.api." + __name__)
+
+
+class Slaves(Resource):
+ """
+ Endpoint for pdp requests
+ """
+
+ __urls__ = (
+ "/slaves",
+ "/slaves/",
+ "/slaves/<string:uuid>",
+ "/slaves/<string:uuid>/",
+ )
+
+ def __init__(self, **kwargs):
+ conf = configuration.get_configuration("components/orchestrator")
+ self.orchestrator_hostname = conf["components/orchestrator"].get("hostname",
+ "orchestrator")
+ self.orchestrator_port = conf["components/orchestrator"].get("port",
+ 80)
+
+ @validate_input("get", kwargs_state=[False, False])
+ @check_auth
+ def get(self, uuid=None, user_id=None):
+ """Retrieve all slaves
+
+ :param uuid: uuid of the slave
+ :param user_id: user ID who do the request
+ :return: {
+ "slaves": {
+ "XXX": {
+ "name": "...",
+ "installed": True
+ },
+ "YYY": {
+ "name": "...",
+ "installed": False
+ }
+ }
+ }
+ """
+ req = requests.get("http://{}:{}/slaves".format(
+ self.orchestrator_hostname, self.orchestrator_port
+ ))
+ return {"slaves": req.json().get("slaves", dict())}
+
+ @validate_input("patch", kwargs_state=[False, False],
+ body_state={"op": True, "variable": True, "value": True})
+ @check_auth
+ def patch(self, uuid=None, user_id=None):
+ """Update a slave
+
+ :param uuid: uuid of the slave to update
+ :param user_id: user ID who do the request
+ :request body: {
+ "op": "replace",
+ "variable": "configured",
+ "value": True,
+ }
+ :return: 204
+ :internal_api: add_pdp
+ """
+ logger.info("Will made a request for {}".format(uuid))
+ if request.json.get("op") == "replace" \
+ and request.json.get("variable") == "configured" \
+ and request.json.get("value"):
+ req = requests.post("http://{}:{}/pods".format(
+ self.orchestrator_hostname, self.orchestrator_port,
+ ),
+ json={"slave_name": uuid}
+ )
+ if req.status_code != 200:
+ logger.warning("Get error from Orchestrator {} {}".format(
+ req.reason, req.status_code
+ ))
+ return "Orchestrator: " + str(req.reason), req.status_code
+ elif request.json.get("op") == "replace" \
+ and request.json.get("variable") == "configured" \
+ and not request.json.get("value"):
+ req = requests.delete("http://{}:{}/pods/{}".format(
+ self.orchestrator_hostname, self.orchestrator_port, uuid
+ ))
+ if req.status_code != 200:
+ logger.warning("Get error from Orchestrator {} {}".format(
+ req.reason, req.status_code
+ ))
+ return "Orchestrator: " + str(req.reason), req.status_code
+ else:
+ return "Malformed request", 400
+ return {"slaves": req.json()}
diff --git a/old/moon_manager/moon_manager/http_server.py b/old/moon_manager/moon_manager/http_server.py
new file mode 100644
index 00000000..53879529
--- /dev/null
+++ b/old/moon_manager/moon_manager/http_server.py
@@ -0,0 +1,162 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+from flask import Flask, jsonify, Response, make_response
+from flask_cors import CORS, cross_origin
+from json import dumps
+from flask_restful import Resource, Api
+import logging
+import sqlalchemy.exc
+import time
+from moon_manager import __version__
+from moon_manager.api.generic import Status, Logs, API
+from moon_manager.api.models import Models
+from moon_manager.api.policies import Policies
+from moon_manager.api.pdp import PDP
+from moon_manager.api.slaves import Slaves
+from moon_manager.api.meta_rules import MetaRules
+from moon_manager.api.meta_data import SubjectCategories, ObjectCategories, ActionCategories
+from moon_manager.api.perimeter import Subjects, Objects, Actions
+from moon_manager.api.data import SubjectData, ObjectData, ActionData
+from moon_manager.api.assignments import SubjectAssignments, ObjectAssignments, ActionAssignments
+from moon_manager.api.rules import Rules
+from moon_manager.api.json_import import JsonImport
+from moon_manager.api.json_export import JsonExport
+from python_moonutilities import configuration
+from python_moondb.core import PDPManager
+
+logger = logging.getLogger("moon.manager.http_server")
+
+__API__ = (
+ Status, Logs, API,
+ MetaRules, SubjectCategories, ObjectCategories, ActionCategories,
+ Subjects, Objects, Actions, Rules,
+ SubjectAssignments, ObjectAssignments, ActionAssignments,
+ SubjectData, ObjectData, ActionData,
+ Models, Policies, PDP, Slaves, JsonImport, JsonExport
+)
+
+
+class Server:
+ """Base class for HTTP server"""
+
+ def __init__(self, host="localhost", port=80, api=None, **kwargs):
+ """Run a server
+
+ :param host: hostname of the server
+ :param port: port for the running server
+ :param kwargs: optional parameters
+ :return: a running server
+ """
+ self._host = host
+ self._port = port
+ self._api = api
+ self._extra = kwargs
+
+ @property
+ def host(self):
+ return self._host
+
+ @host.setter
+ def host(self, name):
+ self._host = name
+
+ @host.deleter
+ def host(self):
+ self._host = ""
+
+ @property
+ def port(self):
+ return self._port
+
+ @port.setter
+ def port(self, number):
+ self._port = number
+
+ @port.deleter
+ def port(self):
+ self._port = 80
+
+ def run(self):
+ raise NotImplementedError()
+
+
+class Root(Resource):
+ """
+ The root of the web service
+ """
+ __urls__ = ("/",)
+ __methods = ("get", "post", "put", "delete", "options")
+
+ def get(self):
+ tree = {"/": {"methods": ("get",),
+ "description": "List all methods for that service."}}
+ for item in __API__:
+ tree[item.__name__] = {"urls": item.__urls__}
+ _methods = []
+ for _method in self.__methods:
+ if _method in dir(item):
+ _methods.append(_method)
+ tree[item.__name__]["methods"] = _methods
+ tree[item.__name__]["description"] = item.__doc__.strip() if item.__doc__ else ""
+ return {
+ "version": __version__,
+ "tree": tree
+ }
+
+
+class CustomApi(Api):
+
+ @staticmethod
+ def handle_error(e):
+ try:
+ error_message = dumps(
+ {"result": False, 'message': str(e), "code": getattr(e, "code", 500)})
+ logger.error(e, exc_info=True)
+ logger.error(error_message)
+ return make_response(error_message, getattr(e, "code", 500))
+ except Exception as e2: # unhandled exception in the api...
+ logger.exception(str(e2))
+ return make_response(error_message, 500)
+
+
+class HTTPServer(Server):
+
+ def __init__(self, host="localhost", port=80, **kwargs):
+ super(HTTPServer, self).__init__(host=host, port=port, **kwargs)
+ self.app = Flask(__name__)
+ self.app.config['TRAP_HTTP_EXCEPTIONS'] = True
+ conf = configuration.get_configuration("components/manager")
+ self.manager_hostname = conf["components/manager"].get("hostname",
+ "manager")
+ self.manager_port = conf["components/manager"].get("port", 80)
+ # TODO : specify only few urls instead of *
+ CORS(self.app)
+ self.api = CustomApi(self.app, catch_all_404s=True)
+ self.__set_route()
+
+ def __set_route(self):
+ self.api.add_resource(Root, '/')
+
+ for _api in __API__:
+ self.api.add_resource(_api, *_api.__urls__)
+
+ @staticmethod
+ def __check_if_db_is_up():
+ first = True
+ while True:
+ try:
+ PDPManager.get_pdp(user_id="admin", pdp_id=None)
+ except (sqlalchemy.exc.ProgrammingError, sqlalchemy.exc.InternalError):
+ time.sleep(1)
+ if first:
+ logger.warning("Waiting for the database...")
+ first = False
+ else:
+ logger.warning("Database is up, resuming operations...")
+ break
+
+ def run(self):
+ self.__check_if_db_is_up()
+ self.app.run(host=self._host, port=self._port, threaded=True) # nosec
diff --git a/old/moon_manager/moon_manager/server.py b/old/moon_manager/moon_manager/server.py
new file mode 100644
index 00000000..70ddaee0
--- /dev/null
+++ b/old/moon_manager/moon_manager/server.py
@@ -0,0 +1,39 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import logging
+from python_moonutilities import configuration, exceptions
+from moon_manager.http_server import HTTPServer
+
+logger = logging.getLogger("moon.manager.server")
+
+
+def create_server():
+ configuration.init_logging()
+ try:
+ conf = configuration.get_configuration("components/manager")
+ hostname = conf["components/manager"].get("hostname", "manager")
+ port = conf["components/manager"].get("port", 80)
+ bind = conf["components/manager"].get("bind", "127.0.0.1")
+ except exceptions.ConsulComponentNotFound:
+ hostname = "manager"
+ bind = "127.0.0.1"
+ port = 80
+ configuration.add_component(uuid="manager",
+ name=hostname,
+ port=port,
+ bind=bind)
+ logger.info("Starting server with IP {} on port {} bind to {}".format(
+ hostname, port, bind))
+ return HTTPServer(host=bind, port=port)
+
+
+def run():
+ server = create_server()
+ server.run()
+
+
+if __name__ == '__main__':
+ run()
diff --git a/old/moon_manager/requirements.txt b/old/moon_manager/requirements.txt
new file mode 100644
index 00000000..e2dd5c96
--- /dev/null
+++ b/old/moon_manager/requirements.txt
@@ -0,0 +1,5 @@
+flask
+flask_restful
+flask_cors
+python_moonutilities
+python_moondb
diff --git a/old/moon_manager/setup.py b/old/moon_manager/setup.py
new file mode 100644
index 00000000..35c944c3
--- /dev/null
+++ b/old/moon_manager/setup.py
@@ -0,0 +1,47 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from setuptools import setup, find_packages
+import moon_manager
+
+
+setup(
+
+ name='moon_manager',
+
+ version=moon_manager.__version__,
+
+ packages=find_packages(),
+
+ author="Thomas Duval",
+
+ author_email="thomas.duval@orange.com",
+
+ description="",
+
+ long_description=open('README.md').read(),
+
+ # install_requires= ,
+
+ include_package_data=True,
+
+ url='https://git.opnfv.org/cgit/moon',
+
+ classifiers=[
+ "Programming Language :: Python",
+ "Development Status :: 1 - Planning",
+ "License :: OSI Approved",
+ "Natural Language :: French",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python :: 3",
+ ],
+
+ entry_points={
+ 'console_scripts': [
+ 'moon_manager = moon_manager.server:create_server',
+ ],
+ }
+
+)
diff --git a/old/moon_manager/tests/functional_pod/conftest.py b/old/moon_manager/tests/functional_pod/conftest.py
new file mode 100644
index 00000000..b5811755
--- /dev/null
+++ b/old/moon_manager/tests/functional_pod/conftest.py
@@ -0,0 +1,12 @@
+import pytest
+
+print("ANALYSING CONFTEST")
+
+
+@pytest.fixture
+def context():
+ print("CREATING CONTEXT")
+ yield {
+ "hostname": "manager",
+ "port": 8082,
+ }
diff --git a/old/moon_manager/tests/functional_pod/json/mls.json b/old/moon_manager/tests/functional_pod/json/mls.json
new file mode 100644
index 00000000..01ef6deb
--- /dev/null
+++ b/old/moon_manager/tests/functional_pod/json/mls.json
@@ -0,0 +1,89 @@
+{
+ "pdps": [{"name" : "pdp_mls", "keystone_project_id" : "", "description": "", "policies": [{"name": "MLS policy example"}]}],
+
+ "policies":[{ "name": "MLS policy example", "genre": "authz", "description": "", "model": {"name": "MLS"} , "mandatory" :false , "override":true}],
+
+ "models":[{"name":"MLS", "description":"","meta_rules": [{"name" : "mls"}], "override":true}],
+
+
+
+
+
+ "subjects": [{ "name":"adminuser", "description": "", "extra": {}, "policies": [{ "name": "MLS policy example"}]} ,
+ { "name": "user1", "description": "", "extra": {}, "policies": [{ "name": "MLS policy example"}] },
+ { "name": "user2", "description": "", "extra": {}, "policies": [{ "name": "MLS policy example"}] }],
+
+ "subject_categories": [{ "name":"subject-security-level", "description": "" }],
+
+ "subject_data": [{ "name":"low", "description": "", "policies": [{"name" :"MLS policy example"}], "category": {"name": "subject-security-level"}},
+ { "name":"medium", "description": "", "policies": [{"name" :"MLS policy example"}], "category": {"name": "subject-security-level"}},
+ { "name":"high", "description": "", "policies": [{"name" :"MLS policy example"}], "category": {"name": "subject-security-level"}}],
+
+ "subject_assignments":[{ "subject" : {"name": "adminuser"}, "category" : {"name": "subject-security-level"}, "assignments": [{"name" : "high"}]},
+ { "subject" : {"name": "user1"}, "category" : {"name": "subject-security-level"}, "assignments": [{"name" : "medium"}] }],
+
+
+
+
+
+
+ "objects": [{ "name":"vm0", "description": "", "extra": {}, "policies": [{"name": "MLS policy example"}]} ,
+ {"name": "vm1", "description": "", "extra": {}, "policies": [{"name": "MLS policy example"}]} ],
+
+ "object_categories": [{"name":"object-security-level", "description": ""}],
+
+ "object_data": [{ "name":"low", "description": "", "policies": [{"name" :"MLS policy example"}], "category": {"name": "object-security-level"}},
+ { "name":"medium", "description": "", "policies": [{"name" :"MLS policy example"}], "category": {"name": "object-security-level"}},
+ { "name":"high", "description": "", "policies": [{"name" :"MLS policy example"}], "category": {"name": "object-security-level"}}],
+
+ "object_assignments":[{ "object" : {"name": "vm0"}, "category" : {"name": "object-security-level"}, "assignments": [{"name" : "medium"}]},
+ { "object" : {"name": "vm1"}, "category" : {"name": "object-security-level"}, "assignments": [{"name" : "low"}]}],
+
+
+
+
+
+
+ "actions": [{ "name": "start", "description": "", "extra": {}, "policies": [{"name": "MLS policy example"}]} ,
+ { "name": "stop", "description": "", "extra": {}, "policies": [{"name": "MLS policy example"}]}],
+
+ "action_categories": [{"name":"action-type", "description": ""}],
+
+ "action_data": [{"name":"vm-action", "description": "", "policies": [{"name": "MLS policy example"}], "category": {"name": "action-type"}},
+ {"name":"storage-action", "description": "", "policies": [{"name" :"MLS policy example"}], "category": {"name": "action-type"}}],
+
+ "action_assignments":[{ "action" : {"name": "start"}, "category" : {"name": "action-type"}, "assignments": [{"name" : "vm-action"}]},
+ { "action" : {"name": "stop"}, "category" : {"name": "action-type"}, "assignments": [{"name" : "vm-action"}]}],
+
+
+
+
+
+
+ "meta_rules":[{"name":"mls", "description": "",
+ "subject_categories": [{"name": "subject-security-level"}],
+ "object_categories": [{"name": "object-security-level"}],
+ "action_categories": [{"name": "action-type"}]
+ }],
+
+ "rules": [{
+ "meta_rule": {"name" : "mls"},
+ "rule": {"subject_data" : [{"name":"high"}], "object_data": [{"name": "medium"}], "action_data": [{"name": "vm-action"}]},
+ "policy": {"name" :"MLS policy example"},
+ "instructions" : {"decision" : "grant"}
+ }, {
+ "meta_rule": {"name" : "mls"},
+ "rule": {"subject_data" : [{"name":"high"}], "object_data": [{"name": "low"}], "action_data": [{"name": "vm-action"}]},
+ "policy": {"name" :"MLS policy example"},
+ "instructions" : {"decision" : "grant"}
+ }, {
+ "meta_rule": {"name" : "mls"},
+ "rule": {"subject_data" : [{"name":"medium"}], "object_data": [{"name": "low"}], "action_data": [{"name": "vm-action"}]},
+ "policy": {"name" :"MLS policy example"},
+ "instructions" : {"decision" : "grant"}
+ }]
+
+
+
+
+} \ No newline at end of file
diff --git a/old/moon_manager/tests/functional_pod/json/rbac.json b/old/moon_manager/tests/functional_pod/json/rbac.json
new file mode 100644
index 00000000..a75f291b
--- /dev/null
+++ b/old/moon_manager/tests/functional_pod/json/rbac.json
@@ -0,0 +1,85 @@
+{
+ "pdps": [{"name" : "pdp_rbac", "keystone_project_id" : "", "description": "", "policies": [{"name": "RBAC policy example"}]}],
+
+ "policies":[{ "name": "RBAC policy example", "genre": "authz", "description": "", "model": {"name": "RBAC"} , "mandatory" :true , "override":true}],
+
+ "models":[{"name":"RBAC", "description":"","meta_rules": [{"name" : "rbac"}], "override":true}],
+
+
+
+
+
+ "subjects": [{ "name":"adminuser", "description": "", "extra": {}, "policies": [{ "name": "RBAC policy example"}]} ,
+ { "name": "user1", "description": "", "extra": {}, "policies": [{ "name": "RBAC policy example"}] },
+ { "name": "public", "description": "", "extra": {}, "policies": [] }],
+
+ "subject_categories": [{ "name":"role", "description": "" }],
+
+ "subject_data": [{ "name":"admin", "description": "", "policies": [{"name" :"RBAC policy example"}], "category": {"name": "role"}},
+ { "name":"employee", "description": "", "policies": [{"name" :"RBAC policy example"}], "category": {"name": "role"}},
+ { "name":"*", "description": "", "policies": [{"name" :"RBAC policy example"}], "category": {"name": "role"}}],
+
+ "subject_assignments":[{ "subject" : {"name": "adminuser"}, "category" : {"name": "role"}, "assignments": [{"name" : "admin"}, {"name" : "employee"}, {"name" : "*"}]},
+ { "subject" : {"name": "user1"}, "category" : {"name": "role"}, "assignments": [{"name" : "employee"}, {"name" : "*"}] }],
+
+
+
+
+
+
+ "objects": [{ "name":"vm0", "description": "", "extra": {}, "policies": [{"name": "RBAC policy example"}]} ,
+ {"name": "vm1", "description": "", "extra": {}, "policies": [{"name": "RBAC policy example"}]} ],
+
+ "object_categories": [{"name":"id", "description": ""}],
+
+ "object_data": [{ "name":"vm0", "description": "", "policies": [{"name" :"RBAC policy example"}], "category": {"name": "id"}},
+ { "name":"vm1", "description": "", "policies": [{"name" :"RBAC policy example"}], "category": {"name": "id"}},
+ { "name":"*", "description": "", "policies": [{"name" :"RBAC policy example"}], "category": {"name": "id"}}],
+
+ "object_assignments":[{ "object" : {"name": "vm0"}, "category" : {"name": "id"}, "assignments": [{"name" : "vm0"}, {"name" : "*"}]},
+ { "object" : {"name": "vm1"}, "category" : {"name": "id"}, "assignments": [{"name" : "vm1"}, {"name" : "*"}]}],
+
+
+
+
+
+
+ "actions": [{ "name": "start", "description": "", "extra": {}, "policies": [{"name": "RBAC policy example"}]} ,
+ { "name": "stop", "description": "", "extra": {}, "policies": [{"name": "RBAC policy example"}]}],
+
+ "action_categories": [{"name":"action-type", "description": ""}],
+
+ "action_data": [{"name":"vm-action", "description": "", "policies": [{"name": "RBAC policy example"}], "category": {"name": "action-type"}},
+ {"name":"*", "description": "", "policies": [{"name" :"RBAC policy example"}], "category": {"name": "action-type"}}],
+
+ "action_assignments":[{ "action" : {"name": "start"}, "category" : {"name": "action-type"}, "assignments": [{"name" : "vm-action"}, {"name" : "*"}]},
+ { "action" : {"name": "stop"}, "category" : {"name": "action-type"}, "assignments": [{"name" : "vm-action"}, {"name" : "*"}]}],
+
+
+
+
+
+
+ "meta_rules":[{"name":"rbac", "description": "",
+ "subject_categories": [{"name": "role"}],
+ "object_categories": [{"name": "id"}],
+ "action_categories": [{"name": "action-type"}]
+ }],
+
+ "rules": [{
+ "meta_rule": {"name" : "rbac"},
+ "rule": {"subject_data" : [{"name":"admin"}], "object_data": [{"name": "vm0"}], "action_data": [{"name": "vm-action"}]},
+ "policy": {"name" :"RBAC policy example"},
+ "instructions" : {"decision" : "grant"},
+ "enabled": true
+ }, {
+ "meta_rule": {"name" : "rbac"},
+ "rule": {"subject_data" : [{"name":"employee"}], "object_data": [{"name": "vm1"}], "action_data": [{"name": "vm-action"}]},
+ "policy": {"name" :"RBAC policy example"},
+ "instructions" : {"decision" : "grant"}
+ }]
+
+
+
+
+} \ No newline at end of file
diff --git a/old/moon_manager/tests/functional_pod/run_functional_tests.sh b/old/moon_manager/tests/functional_pod/run_functional_tests.sh
new file mode 100644
index 00000000..960e9480
--- /dev/null
+++ b/old/moon_manager/tests/functional_pod/run_functional_tests.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+if [ -d /data/dist ];
+then
+ pip install /data/dist/*.tar.gz --upgrade
+ pip install /data/dist/*.whl --upgrade
+fi
+
+
+cd /data/tests/functional_pod
+pytest .
diff --git a/old/moon_manager/tests/functional_pod/test_manager.py b/old/moon_manager/tests/functional_pod/test_manager.py
new file mode 100644
index 00000000..454d861b
--- /dev/null
+++ b/old/moon_manager/tests/functional_pod/test_manager.py
@@ -0,0 +1,116 @@
+import json
+import requests
+
+def test_import_rbac(context):
+ files = {'file': open('/data/tests/functional_pod/json/rbac.json', 'r')}
+ req = requests.post("http://{}:{}/import".format(
+ context.get("hostname"),
+ context.get("port"))
+ , files=files)
+ print(req)
+ result = req.json()
+ print(result)
+ req.raise_for_status()
+
+def test_import_mls(context):
+ files = {'file': open('/data/tests/functional_pod/json/mls.json', 'r')}
+ req = requests.post("http://{}:{}/import".format(
+ context.get("hostname"),
+ context.get("port"))
+ , files=files)
+ req.raise_for_status()
+
+
+def test_export_rbac(context):
+ test_import_rbac(context)
+ req = requests.get("http://{}:{}/export".format(
+ context.get("hostname"),
+ context.get("port")),
+ data={"filename":"/data/tests/functional_pod/json/rbac_export.json"}
+ )
+ req.raise_for_status()
+
+
+def test_export_mls(context):
+ test_import_mls(context)
+ req = requests.get("http://{}:{}/export".format(
+ context.get("hostname"),
+ context.get("port")),
+ data={"filename":"/data/tests/functional_pod/json/mls_export.json"}
+ )
+ req.raise_for_status()
+
+
+def get_json(data):
+ return json.loads(data.decode("utf-8"))
+
+
+def get_pdp(context):
+ req = requests.get("http://{}:{}/pdp".format(
+ context.get("hostname"),
+ context.get("port")),
+ timeout=3)
+ pdp = req.json()
+ return req, pdp
+
+
+def add_pdp(context, data):
+ req = requests.post("http://{}:{}/pdp".format(
+ context.get("hostname"),
+ context.get("port")),
+ data=json.dumps(data),
+ headers={'Content-Type': 'application/json'},
+ timeout=3)
+ pdp = req.json()
+ return req, pdp
+
+
+def delete_pdp(context, key):
+ req = requests.delete("http://{}:{}/pdp/{}".format(
+ context.get("hostname"),
+ context.get("port"), key),
+ timeout=3)
+ return req
+
+
+def delete_pdp_without_id(context):
+ req = requests.delete("http://{}:{}/pdp/{}".format(
+ context.get("hostname"),
+ context.get("port"), ""),
+ timeout=3)
+ return req
+
+
+def test_get_pdp(context):
+ req, pdp = get_pdp(context)
+ assert req.status_code == 200
+ assert isinstance(pdp, dict)
+ assert "pdps" in pdp
+
+
+def test_add_pdp(context):
+ data = {
+ "name": "testuser",
+ "security_pipeline": ["policy_id_1", "policy_id_2"],
+ "keystone_project_id": "keystone_project_id",
+ "description": "description of testuser"
+ }
+ req, pdp = add_pdp(context, data)
+ assert req.status_code == 200
+ assert isinstance(pdp, dict)
+ value = list(pdp["pdps"].values())[0]
+ assert "pdps" in pdp
+ assert value['name'] == "testuser"
+ assert value["description"] == "description of {}".format("testuser")
+ assert value["keystone_project_id"] == "keystone_project_id"
+
+
+def test_delete_pdp(context):
+ request, pdp = get_pdp(context)
+ success_req = None
+ for key, value in pdp['pdps'].items():
+ if value['name'] == "testuser":
+ success_req = delete_pdp(context, key)
+ break
+ assert success_req
+ assert success_req.status_code == 200
diff --git a/old/moon_manager/tests/functional_pod/test_models.py b/old/moon_manager/tests/functional_pod/test_models.py
new file mode 100644
index 00000000..8b4ceef5
--- /dev/null
+++ b/old/moon_manager/tests/functional_pod/test_models.py
@@ -0,0 +1,79 @@
+import json
+import requests
+
+
+def get_models(context):
+ req = requests.get("http://{}:{}/models".format(
+ context.get("hostname"),
+ context.get("port")),
+ timeout=3)
+ models = req.json()
+ return req, models
+
+
+def add_models(context, name):
+ data = {
+ "name": name,
+ "description": "description of {}".format(name),
+ "meta_rules": ["meta_rule_id1", "meta_rule_id2"]
+ }
+ req = requests.post("http://{}:{}/models".format(
+ context.get("hostname"),
+ context.get("port")),
+ data=json.dumps(data),
+ headers={'Content-Type': 'application/json'},
+ timeout=3)
+ models = req.json()
+ return req, models
+
+
+def delete_models(context, name):
+ _, models = get_models(context)
+ request = None
+ for key, value in models['models'].items():
+ if value['name'] == name:
+ request = requests.delete("http://{}:{}/models/{}".format(
+ context.get("hostname"),
+ context.get("port"),
+ key),
+ timeout=3)
+ break
+ return request
+
+
+def delete_models_without_id(context):
+ req = requests.delete("http://{}:{}/models/{}".format(
+ context.get("hostname"),
+ context.get("port"),
+ ""),
+ timeout=3)
+ return req
+
+
+def test_get_models(context):
+ req, models = get_models(context)
+ assert req.status_code == 200
+ assert isinstance(models, dict)
+ assert "models" in models
+
+
+def test_add_models(context):
+ req, models = add_models(context, "testuser")
+ assert req.status_code == 200
+ assert isinstance(models, dict)
+ value = list(models["models"].values())[0]
+ assert "models" in models
+ assert value['name'] == "testuser"
+ assert value["description"] == "description of {}".format("testuser")
+ assert value["meta_rules"][0] == "meta_rule_id1"
+
+
+def test_delete_models(context):
+ req = delete_models(context, "testuser")
+ assert req.status_code == 200
+
+
+def test_delete_models_without_id(context):
+ req = delete_models_without_id(context)
+ assert req.status_code == 500
+
diff --git a/old/moon_manager/tests/unit_python/api/import_export_utilities.py b/old/moon_manager/tests/unit_python/api/import_export_utilities.py
new file mode 100644
index 00000000..2ee2627d
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/import_export_utilities.py
@@ -0,0 +1,202 @@
+# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import api.test_unit_models as test_models
+import api.test_policies as test_policies
+import api.test_perimeter as test_perimeter
+import api.test_meta_data as test_categories
+import api.test_data as test_data
+import api.test_meta_rules as test_meta_rules
+import api.test_assignement as test_assignments
+import api.test_rules as test_rules
+import logging
+
+logger = logging.getLogger("moon.manager.test.api." + __name__)
+
+
+def clean_models(client):
+ req, models = test_models.get_models(client)
+ for key in models["models"]:
+ client.delete("/models/{}".format(key))
+
+
+def clean_policies(client):
+ req, policies = test_policies.get_policies(client)
+ for key in policies["policies"]:
+ req = client.delete("/policies/{}".format(key))
+ assert req.status_code == 200
+
+
+def clean_subjects(client):
+ subjects = test_perimeter.get_subjects(client)
+ logger.info("subjects {}".format(subjects))
+ for key in subjects[1]["subjects"]:
+ subject = subjects[1]["subjects"][key]
+ policy_keys = subject["policy_list"]
+ logger.info("subjects policy_keys {}".format(policy_keys))
+ for policy_key in policy_keys:
+ client.delete("/policies/{}/subjects/{}".format(policy_key, key))
+
+
+def clean_objects(client):
+ objects = test_perimeter.get_objects(client)
+ logger.info("objects {}".format(objects))
+ for key in objects[1]["objects"]:
+ object_ = objects[1]["objects"][key]
+ policy_keys = object_["policy_list"]
+ logger.info("objects policy_keys {}".format(policy_keys))
+ for policy_key in policy_keys:
+ client.delete("/policies/{}/objects/{}".format(policy_key, key))
+
+
+def clean_actions(client):
+ actions = test_perimeter.get_actions(client)
+ actions = test_perimeter.get_actions(client)
+ logger.info("actions {}".format(actions))
+ for key in actions[1]["actions"]:
+ action = actions[1]["actions"][key]
+ policy_keys = action["policy_list"]
+ logger.info("action policy_keys {}".format(policy_keys))
+ for policy_key in policy_keys:
+ client.delete("/policies/{}/actions/{}".format(policy_key, key))
+
+
+def clean_subject_categories(client):
+ req, categories = test_categories.get_subject_categories(client)
+ logger.info(categories)
+ for key in categories["subject_categories"]:
+ client.delete("/subject_categories/{}".format(key))
+
+
+def clean_object_categories(client):
+ req, categories = test_categories.get_object_categories(client)
+ logger.info(categories)
+ for key in categories["object_categories"]:
+ client.delete("/object_categories/{}".format(key))
+
+
+def clean_action_categories(client):
+ req, categories = test_categories.get_action_categories(client)
+ logger.info(categories)
+ for key in categories["action_categories"]:
+ client.delete("/action_categories/{}".format(key))
+
+
+def clean_subject_data(client):
+ req, policies = test_policies.get_policies(client)
+ logger.info("clean_subject_data on {}".format(policies))
+ for policy_key in policies["policies"]:
+ req, data = test_data.get_subject_data(client, policy_id=policy_key)
+ logger.info("============= data {}".format(data))
+ for data_item in data["subject_data"]:
+ if data_item["data"]:
+ for data_id in data_item["data"]:
+ logger.info("============= Deleting {}/{}".format(policy_key, data_id))
+ client.delete("/policies/{}/subject_data/{}/{}".format(policy_key, data_item['category_id'], data_id))
+
+
+def clean_object_data(client):
+ req, policies = test_policies.get_policies(client)
+ for policy_key in policies["policies"]:
+ req, data = test_data.get_object_data(client, policy_id=policy_key)
+ for data_item in data["object_data"]:
+ if data_item["data"]:
+ for data_id in data_item["data"]:
+ logger.info("============= object_data {}/{}".format(policy_key, data_id))
+ client.delete("/policies/{}/object_data/{}/{}".format(policy_key, data_item['category_id'], data_id))
+
+
+def clean_action_data(client):
+ req, policies = test_policies.get_policies(client)
+ for policy_key in policies["policies"]:
+ req, data = test_data.get_action_data(client, policy_id=policy_key)
+ for data_item in data["action_data"]:
+ if data_item["data"]:
+ for data_id in data_item["data"]:
+ logger.info("============= action_data {}/{}".format(policy_key, data_id))
+ client.delete("/policies/{}/action_data/{}/{}".format(policy_key, data_item['category_id'], data_id))
+
+
+def clean_meta_rule(client):
+ req, meta_rules = test_meta_rules.get_meta_rules(client)
+ meta_rules = meta_rules["meta_rules"]
+ for meta_rule_key in meta_rules:
+ logger.info("clean_meta_rule.meta_rule_key={}".format(meta_rule_key))
+ logger.info("clean_meta_rule.meta_rule={}".format(meta_rules[meta_rule_key]))
+ client.delete("/meta_rules/{}".format(meta_rule_key))
+
+
+def clean_subject_assignments(client):
+ req, policies = test_policies.get_policies(client)
+ for policy_key in policies["policies"]:
+ req, assignments = test_assignments.get_subject_assignment(client, policy_key)
+ for key in assignments["subject_assignments"]:
+ subject_key = assignments["subject_assignments"][key]["subject_id"]
+ cat_key = assignments["subject_assignments"][key]["category_id"]
+ data_keys = assignments["subject_assignments"][key]["assignments"]
+ for data_key in data_keys:
+ client.delete("/policies/{}/subject_assignments/{}/{}/{}".format(policy_key, subject_key,
+ cat_key, data_key))
+
+
+def clean_object_assignments(client):
+ req, policies = test_policies.get_policies(client)
+ for policy_key in policies["policies"]:
+ req, assignments = test_assignments.get_object_assignment(client, policy_key)
+ for key in assignments["object_assignments"]:
+ object_key = assignments["object_assignments"][key]["object_id"]
+ cat_key = assignments["object_assignments"][key]["category_id"]
+ data_keys = assignments["object_assignments"][key]["assignments"]
+ for data_key in data_keys:
+ client.delete("/policies/{}/object_assignments/{}/{}/{}".format(policy_key, object_key,
+ cat_key, data_key))
+
+
+def clean_action_assignments(client):
+ req, policies = test_policies.get_policies(client)
+ for policy_key in policies["policies"]:
+ req, assignments = test_assignments.get_action_assignment(client, policy_key)
+ for key in assignments["action_assignments"]:
+ action_key = assignments["action_assignments"][key]["action_id"]
+ cat_key = assignments["action_assignments"][key]["category_id"]
+ data_keys = assignments["action_assignments"][key]["assignments"]
+ for data_key in data_keys:
+ client.delete("/policies/{}/action_assignments/{}/{}/{}".format(policy_key, action_key,
+ cat_key, data_key))
+
+
+def clean_rules(client):
+ req, policies = test_policies.get_policies(client)
+ for policy_key in policies["policies"]:
+ req, rules = test_rules.get_rules(client, policy_key)
+ rules = rules["rules"]["rules"]
+ for rule_key in rules:
+ req = client.delete("/policies/{}/rules/{}".format(policy_key, rule_key["id"]))
+
+
+def clean_all(client):
+ clean_rules(client)
+
+ clean_subject_assignments(client)
+ clean_object_assignments(client)
+ clean_action_assignments(client)
+
+
+ clean_subject_data(client)
+ clean_object_data(client)
+ clean_action_data(client)
+
+ clean_actions(client)
+ clean_objects(client)
+ clean_subjects(client)
+
+ clean_subject_categories(client)
+ clean_object_categories(client)
+ clean_action_categories(client)
+
+
+ clean_policies(client)
+ clean_models(client)
+ clean_meta_rule(client) \ No newline at end of file
diff --git a/old/moon_manager/tests/unit_python/api/meta_data_test.py b/old/moon_manager/tests/unit_python/api/meta_data_test.py
new file mode 100644
index 00000000..8609f0b5
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/meta_data_test.py
@@ -0,0 +1,238 @@
+import json
+import api.utilities as utilities
+
+#subject_categories_test
+
+
+def get_subject_categories(client):
+ req = client.get("/subject_categories")
+ subject_categories = utilities.get_json(req.data)
+ return req, subject_categories
+
+
+def add_subject_categories(client, name):
+ data = {
+ "name": name,
+ "description": "description of {}".format(name)
+ }
+ req = client.post("/subject_categories", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ subject_categories = utilities.get_json(req.data)
+ return req, subject_categories
+
+
+def delete_subject_categories(client, name):
+ request, subject_categories = get_subject_categories(client)
+ for key, value in subject_categories['subject_categories'].items():
+ if value['name'] == name:
+ req = client.delete("/subject_categories/{}".format(key))
+ break
+ return req
+
+
+def delete_subject_categories_without_id(client):
+ req = client.delete("/subject_categories/{}".format(""))
+ return req
+
+
+def test_get_subject_categories():
+ client = utilities.register_client()
+ req, subject_categories = get_subject_categories(client)
+ assert req.status_code == 200
+ assert isinstance(subject_categories, dict)
+ assert "subject_categories" in subject_categories
+
+
+def test_add_subject_categories():
+ client = utilities.register_client()
+ req, subject_categories = add_subject_categories(client, "testuser")
+ assert req.status_code == 200
+ assert isinstance(subject_categories, dict)
+ value = list(subject_categories["subject_categories"].values())[0]
+ assert "subject_categories" in subject_categories
+ assert value['name'] == "testuser"
+ assert value['description'] == "description of {}".format("testuser")
+
+
+def test_add_subject_categories_with_empty_user():
+ client = utilities.register_client()
+ req, subject_categories = add_subject_categories(client, "")
+ assert req.status_code == 500
+ assert json.loads(req.data)["message"] == "Empty String"
+
+
+def test_add_subject_categories_with_user_contain_space():
+ client = utilities.register_client()
+ req, subject_categories = add_subject_categories(client, "test user")
+ assert req.status_code == 500
+ assert json.loads(req.data)["message"] == "String contains space"
+
+
+def test_delete_subject_categories():
+ client = utilities.register_client()
+ req = delete_subject_categories(client, "testuser")
+ assert req.status_code == 200
+
+
+def test_delete_subject_categories_without_id():
+ client = utilities.register_client()
+ req = delete_subject_categories_without_id(client)
+ assert req.status_code == 500
+
+
+#---------------------------------------------------------------------------
+#object_categories_test
+
+def get_object_categories(client):
+ req = client.get("/object_categories")
+ object_categories = utilities.get_json(req.data)
+ return req, object_categories
+
+
+def add_object_categories(client, name):
+ data = {
+ "name": name,
+ "description": "description of {}".format(name)
+ }
+ req = client.post("/object_categories", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ object_categories = utilities.get_json(req.data)
+ return req, object_categories
+
+
+def delete_object_categories(client, name):
+ request, object_categories = get_object_categories(client)
+ for key, value in object_categories['object_categories'].items():
+ if value['name'] == name:
+ req = client.delete("/object_categories/{}".format(key))
+ break
+ return req
+
+
+def delete_object_categories_without_id(client):
+ req = client.delete("/object_categories/{}".format(""))
+ return req
+
+
+def test_get_object_categories():
+ client = utilities.register_client()
+ req, object_categories = get_object_categories(client)
+ assert req.status_code == 200
+ assert isinstance(object_categories, dict)
+ assert "object_categories" in object_categories
+
+
+def test_add_object_categories():
+ client = utilities.register_client()
+ req, object_categories = add_object_categories(client, "testuser")
+ assert req.status_code == 200
+ assert isinstance(object_categories, dict)
+ value = list(object_categories["object_categories"].values())[0]
+ assert "object_categories" in object_categories
+ assert value['name'] == "testuser"
+ assert value['description'] == "description of {}".format("testuser")
+
+
+def test_add_object_categories_with_empty_user():
+ client = utilities.register_client()
+ req, object_categories = add_object_categories(client, "")
+ assert req.status_code == 500
+ assert json.loads(req.data)["message"] == "Empty String"
+
+
+def test_add_object_categories_with_user_contain_space():
+ client = utilities.register_client()
+ req, object_categories = add_object_categories(client, "test user")
+ assert req.status_code == 500
+ assert json.loads(req.data)["message"] == "String contains space"
+
+
+def test_delete_object_categories():
+ client = utilities.register_client()
+ req = delete_object_categories(client, "testuser")
+ assert req.status_code == 200
+
+
+def test_delete_object_categories_without_id():
+ client = utilities.register_client()
+ req = delete_object_categories_without_id(client)
+ assert req.status_code == 500
+
+
+#---------------------------------------------------------------------------
+#action_categories_test
+
+def get_action_categories(client):
+ req = client.get("/action_categories")
+ action_categories = utilities.get_json(req.data)
+ return req, action_categories
+
+
+def add_action_categories(client, name):
+ data = {
+ "name": name,
+ "description": "description of {}".format(name)
+ }
+ req = client.post("/action_categories", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ action_categories = utilities.get_json(req.data)
+ return req, action_categories
+
+
+def delete_action_categories(client, name):
+ request, action_categories = get_action_categories(client)
+ for key, value in action_categories['action_categories'].items():
+ if value['name'] == name:
+ req = client.delete("/action_categories/{}".format(key))
+ break
+ return req
+
+
+def delete_action_categories_without_id(client):
+ req = client.delete("/action_categories/{}".format(""))
+ return req
+
+
+def test_get_action_categories():
+ client = utilities.register_client()
+ req, action_categories = get_action_categories(client)
+ assert req.status_code == 200
+ assert isinstance(action_categories, dict)
+ assert "action_categories" in action_categories
+
+
+def test_add_action_categories():
+ client = utilities.register_client()
+ req, action_categories = add_action_categories(client, "testuser")
+ assert req.status_code == 200
+ assert isinstance(action_categories, dict)
+ value = list(action_categories["action_categories"].values())[0]
+ assert "action_categories" in action_categories
+ assert value['name'] == "testuser"
+ assert value['description'] == "description of {}".format("testuser")
+
+
+def test_add_action_categories_with_empty_user():
+ client = utilities.register_client()
+ req, action_categories = add_action_categories(client, "")
+ assert req.status_code == 500
+ assert json.loads(req.data)["message"] == "Empty String"
+
+
+def test_add_action_categories_with_user_contain_space():
+ client = utilities.register_client()
+ req, action_categories = add_action_categories(client, "test user")
+ assert req.status_code == 500
+ assert json.loads(req.data)["message"] == "String contains space"
+
+
+def test_delete_action_categories():
+ client = utilities.register_client()
+ req = delete_action_categories(client, "testuser")
+ assert req.status_code == 200
+
+
+def test_delete_action_categories_without_id():
+ client = utilities.register_client()
+ req = delete_action_categories_without_id(client)
+ assert req.status_code == 500
diff --git a/old/moon_manager/tests/unit_python/api/meta_rules_test.py b/old/moon_manager/tests/unit_python/api/meta_rules_test.py
new file mode 100644
index 00000000..a87c16f3
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/meta_rules_test.py
@@ -0,0 +1,162 @@
+import json
+import api.utilities as utilities
+
+
+def get_meta_rules(client):
+ req = client.get("/meta_rules")
+ meta_rules = utilities.get_json(req.data)
+ return req, meta_rules
+
+
+def add_meta_rules(client, name):
+ data = {
+ "name": name,
+ "subject_categories": ["subject_category_id1",
+ "subject_category_id2"],
+ "object_categories": ["object_category_id1"],
+ "action_categories": ["action_category_id1"]
+ }
+ req = client.post("/meta_rules", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ meta_rules = utilities.get_json(req.data)
+ return req, meta_rules
+
+
+def add_meta_rules_without_subject_category_ids(client, name):
+ data = {
+ "name": name,
+ "subject_categories": [],
+ "object_categories": ["object_category_id1"],
+ "action_categories": ["action_category_id1"]
+ }
+ req = client.post("/meta_rules", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ meta_rules = utilities.get_json(req.data)
+ return req, meta_rules
+
+
+def update_meta_rules(client, name, metaRuleId):
+ data = {
+ "name": name,
+ "subject_categories": ["subject_category_id1_update",
+ "subject_category_id2_update"],
+ "object_categories": ["object_category_id1_update"],
+ "action_categories": ["action_category_id1_update"]
+ }
+ req = client.patch("/meta_rules/{}".format(metaRuleId), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ meta_rules = utilities.get_json(req.data)
+ return req, meta_rules
+
+
+def update_meta_rules_without_subject_category_ids(client, name):
+ data = {
+ "name": name,
+ "subject_categories": [],
+ "object_categories": ["object_category_id1"],
+ "action_categories": ["action_category_id1"]
+ }
+ req = client.post("/meta_rules", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ meta_rules = utilities.get_json(req.data)
+ return req, meta_rules
+
+
+def delete_meta_rules(client, name):
+ request, meta_rules = get_meta_rules(client)
+ for key, value in meta_rules['meta_rules'].items():
+ if value['name'] == name:
+ req = client.delete("/meta_rules/{}".format(key))
+ break
+ return req
+
+
+def delete_meta_rules_without_id(client):
+ req = client.delete("/meta_rules/{}".format(""))
+ return req
+
+
+def test_get_meta_rules():
+ client = utilities.register_client()
+ req, meta_rules = get_meta_rules(client)
+ assert req.status_code == 200
+ assert isinstance(meta_rules, dict)
+ assert "meta_rules" in meta_rules
+
+
+def test_add_meta_rules():
+ client = utilities.register_client()
+ req, meta_rules = add_meta_rules(client, "testuser")
+ assert req.status_code == 200
+ assert isinstance(meta_rules, dict)
+ value = list(meta_rules["meta_rules"].values())[0]
+ assert "meta_rules" in meta_rules
+ assert value['name'] == "testuser"
+ assert value["subject_categories"][0] == "subject_category_id1"
+ assert value["object_categories"][0] == "object_category_id1"
+ assert value["action_categories"][0] == "action_category_id1"
+
+
+def test_add_meta_rules_with_empty_user():
+ client = utilities.register_client()
+ req, meta_rules = add_meta_rules(client, "")
+ assert req.status_code == 500
+ assert json.loads(req.data)["message"] == "Empty String"
+
+
+def test_add_meta_rules_with_user_contain_space():
+ client = utilities.register_client()
+ req, meta_rules = add_meta_rules(client, "test user")
+ assert req.status_code == 500
+ assert json.loads(req.data)["message"] == "String contains space"
+
+
+def test_add_meta_rules_without_subject_categories():
+ client = utilities.register_client()
+ req, meta_rules = add_meta_rules_without_subject_category_ids(client, "testuser")
+ assert req.status_code == 500
+ assert json.loads(req.data)["message"] == 'Empty Container'
+
+
+def test_delete_meta_rules():
+ client = utilities.register_client()
+ req = delete_meta_rules(client, "testuser")
+ assert req.status_code == 200
+
+
+def test_delete_meta_rules_without_id():
+ client = utilities.register_client()
+ req = delete_meta_rules_without_id(client)
+ assert req.status_code == 500
+
+
+def test_update_meta_rules():
+ client = utilities.register_client()
+ req = add_meta_rules(client, "testuser")
+ meta_rule_id = list(req[1]['meta_rules'])[0]
+ req_update = update_meta_rules(client, "testuser", meta_rule_id)
+ assert req_update[0].status_code == 200
+ value = list(req_update[1]["meta_rules"].values())[0]
+ assert value["subject_categories"][0] == "subject_category_id1_update"
+ delete_meta_rules(client, "testuser")
+ get_meta_rules(client)
+
+
+def test_update_meta_rules_without_id():
+ client = utilities.register_client()
+ req_update = update_meta_rules(client, "testuser", "")
+ assert req_update[0].status_code == 500
+
+
+def test_update_meta_rules_without_user():
+ client = utilities.register_client()
+ req_update = update_meta_rules(client, "", "")
+ assert req_update[0].status_code == 500
+ assert json.loads(req_update[0].data)["message"] == "Empty String"
+
+
+def test_update_meta_rules_without_subject_categories():
+ client = utilities.register_client()
+ req_update = update_meta_rules_without_subject_category_ids(client, "testuser")
+ assert req_update[0].status_code == 500
+ assert json.loads(req_update[0].data)["message"] == "Empty Container"
diff --git a/old/moon_manager/tests/unit_python/api/test_assignement.py b/old/moon_manager/tests/unit_python/api/test_assignement.py
new file mode 100644
index 00000000..b56fb420
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/test_assignement.py
@@ -0,0 +1,280 @@
+import api.utilities as utilities
+import json
+from helpers import data_builder as builder
+from uuid import uuid4
+
+
+# subject_categories_test
+
+
+def get_subject_assignment(client, policy_id):
+ req = client.get("/policies/{}/subject_assignments".format(policy_id))
+ subject_assignment = utilities.get_json(req.data)
+ return req, subject_assignment
+
+
+def add_subject_assignment(client):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex)
+ subject_id = builder.create_subject(policy_id)
+ data_id = builder.create_subject_data(policy_id=policy_id, category_id=subject_category_id)
+
+ data = {
+ "id": subject_id,
+ "category_id": subject_category_id,
+ "data_id": data_id
+ }
+ req = client.post("/policies/{}/subject_assignments".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ subject_assignment = utilities.get_json(req.data)
+ return req, subject_assignment
+
+
+def add_subject_assignment_without_cat_id(client):
+
+ data = {
+ "id": "subject_id",
+ "category_id": "",
+ "data_id": "data_id"
+ }
+ req = client.post("/policies/{}/subject_assignments".format("1111"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ subject_assignment = utilities.get_json(req.data)
+ return req, subject_assignment
+
+
+def delete_subject_assignment(client, policy_id, sub_id, cat_id,data_id):
+ req = client.delete("/policies/{}/subject_assignments/{}/{}/{}".format(policy_id, sub_id, cat_id,data_id))
+ return req
+
+
+def test_add_subject_assignment():
+ client = utilities.register_client()
+ req, subject_assignment = add_subject_assignment(client)
+ assert req.status_code == 200
+ assert isinstance(subject_assignment, dict)
+ assert "subject_assignments" in subject_assignment
+
+
+# def test_add_subject_assignment_without_cat_id():
+# client = utilities.register_client()
+# req, subject_assignment = add_subject_assignment_without_cat_id(client)
+# assert req.status_code == 400
+# assert json.loads(req.data)["message"] == "Key: 'category_id', [Empty String]"
+
+
+def test_get_subject_assignment():
+ client = utilities.register_client()
+ policy_id = builder.get_policy_id_with_subject_assignment()
+ req, subject_assignment = get_subject_assignment(client, policy_id)
+ assert req.status_code == 200
+ assert isinstance(subject_assignment, dict)
+ assert "subject_assignments" in subject_assignment
+
+
+def test_delete_subject_assignment():
+ client = utilities.register_client()
+ policy_id = builder.get_policy_id_with_subject_assignment()
+ req, subject_assignment = get_subject_assignment(client, policy_id)
+ value = subject_assignment["subject_assignments"]
+ _id = list(value.keys())[0]
+ success_req = delete_subject_assignment(client,
+ policy_id,
+ value[_id]['subject_id'],
+ value[_id]['category_id'],
+ value[_id]['assignments'][0])
+ assert success_req.status_code == 200
+
+
+def test_delete_subject_assignment_without_policy_id():
+ client = utilities.register_client()
+ success_req = delete_subject_assignment(client, "", "id1", "111", "data_id1")
+ assert success_req.status_code == 404
+
+
+# ---------------------------------------------------------------------------
+# object_categories_test
+
+
+def get_object_assignment(client, policy_id):
+ req = client.get("/policies/{}/object_assignments".format(policy_id))
+ object_assignment = utilities.get_json(req.data)
+ return req, object_assignment
+
+
+def add_object_assignment(client):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex)
+ object_id = builder.create_object(policy_id)
+ data_id = builder.create_object_data(policy_id=policy_id, category_id=object_category_id)
+
+ data = {
+ "id": object_id,
+ "category_id": object_category_id,
+ "data_id": data_id
+ }
+
+ req = client.post("/policies/{}/object_assignments".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ object_assignment = utilities.get_json(req.data)
+ return req, object_assignment
+
+
+def add_object_assignment_without_cat_id(client):
+
+ data = {
+ "id": "object_id",
+ "category_id": "",
+ "data_id": "data_id"
+ }
+ req = client.post("/policies/{}/object_assignments".format("1111"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ object_assignment = utilities.get_json(req.data)
+ return req, object_assignment
+
+
+def delete_object_assignment(client, policy_id, obj_id, cat_id, data_id):
+ req = client.delete("/policies/{}/object_assignments/{}/{}/{}".format(policy_id, obj_id, cat_id, data_id))
+ return req
+
+
+def test_get_object_assignment():
+ policy_id = builder.get_policy_id_with_object_assignment()
+ client = utilities.register_client()
+ req, object_assignment = get_object_assignment(client, policy_id)
+ assert req.status_code == 200
+ assert isinstance(object_assignment, dict)
+ assert "object_assignments" in object_assignment
+
+
+def test_add_object_assignment():
+ client = utilities.register_client()
+ req, object_assignment = add_object_assignment(client)
+ assert req.status_code == 200
+ assert "object_assignments" in object_assignment
+
+
+# def test_add_object_assignment_without_cat_id():
+# client = utilities.register_client()
+# req, object_assignment = add_object_assignment_without_cat_id(client)
+# assert req.status_code == 400
+# assert json.loads(req.data)["message"] == "Key: 'category_id', [Empty String]"
+
+
+def test_delete_object_assignment():
+ client = utilities.register_client()
+ policy_id = builder.get_policy_id_with_object_assignment()
+ req, object_assignment = get_object_assignment(client, policy_id)
+ value = object_assignment["object_assignments"]
+ _id = list(value.keys())[0]
+ success_req = delete_object_assignment(client,
+ policy_id,
+ value[_id]['object_id'],
+ value[_id]['category_id'],
+ value[_id]['assignments'][0])
+ assert success_req.status_code == 200
+
+
+def test_delete_object_assignment_without_policy_id():
+ client = utilities.register_client()
+ success_req = delete_object_assignment(client, "", "id1", "111", "data_id1")
+ assert success_req.status_code == 404
+
+
+# ---------------------------------------------------------------------------
+# action_categories_test
+
+
+def get_action_assignment(client, policy_id):
+ req = client.get("/policies/{}/action_assignments".format(policy_id))
+ action_assignment = utilities.get_json(req.data)
+ return req, action_assignment
+
+
+def add_action_assignment(client):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex)
+ action_id = builder.create_action(policy_id)
+ data_id = builder.create_action_data(policy_id=policy_id, category_id=action_category_id)
+
+ data = {
+ "id": action_id,
+ "category_id": action_category_id,
+ "data_id": data_id
+ }
+ req = client.post("/policies/{}/action_assignments".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ action_assignment = utilities.get_json(req.data)
+ return req, action_assignment
+
+
+def add_action_assignment_without_cat_id(client):
+
+ data = {
+ "id": "action_id",
+ "category_id": "",
+ "data_id": "data_id"
+ }
+ req = client.post("/policies/{}/action_assignments".format("1111"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ action_assignment = utilities.get_json(req.data)
+ return req, action_assignment
+
+
+def delete_action_assignment(client, policy_id, action_id, cat_id, data_id):
+ req = client.delete("/policies/{}/action_assignments/{}/{}/{}".format(policy_id, action_id, cat_id, data_id))
+ return req
+
+
+def test_get_action_assignment():
+ policy_id = builder.get_policy_id_with_action_assignment()
+ client = utilities.register_client()
+ req, action_assignment = get_action_assignment(client, policy_id)
+ assert req.status_code == 200
+ assert isinstance(action_assignment, dict)
+ assert "action_assignments" in action_assignment
+
+
+def test_add_action_assignment():
+ client = utilities.register_client()
+ req, action_assignment = add_action_assignment(client)
+ assert req.status_code == 200
+ assert "action_assignments" in action_assignment
+
+
+# def test_add_action_assignment_without_cat_id():
+# client = utilities.register_client()
+# req, action_assignment = add_action_assignment_without_cat_id(client)
+# assert req.status_code == 400
+# assert json.loads(req.data)["message"] == "Key: 'category_id', [Empty String]"
+
+
+def test_delete_action_assignment():
+ client = utilities.register_client()
+ policy_id = builder.get_policy_id_with_action_assignment()
+ req, action_assignment = get_action_assignment(client, policy_id)
+ value = action_assignment["action_assignments"]
+ id = list(value.keys())[0]
+ success_req = delete_action_assignment(client,
+ policy_id,
+ value[id]['action_id'],
+ value[id]['category_id'],
+ value[id]['assignments'][0])
+ assert success_req.status_code == 200
+
+
+def test_delete_action_assignment_without_policy_id():
+ client = utilities.register_client()
+ success_req = delete_action_assignment(client, "", "id1", "111", "data_id1")
+ assert success_req.status_code == 404
+
+# ---------------------------------------------------------------------------
diff --git a/old/moon_manager/tests/unit_python/api/test_assignemnt.py b/old/moon_manager/tests/unit_python/api/test_assignemnt.py
new file mode 100644
index 00000000..22c727af
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/test_assignemnt.py
@@ -0,0 +1,270 @@
+import api.utilities as utilities
+import json
+from helpers import data_builder as builder
+from uuid import uuid4
+
+
+# subject_categories_test
+
+
+def get_subject_assignment(client, policy_id):
+ req = client.get("/policies/{}/subject_assignments".format(policy_id))
+ subject_assignment = utilities.get_json(req.data)
+ return req, subject_assignment
+
+
+def add_subject_assignment(client):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex)
+ subject_id = builder.create_subject(policy_id)
+ data_id = builder.create_subject_data(policy_id=policy_id, category_id=subject_category_id)
+
+ data = {
+ "id": subject_id,
+ "category_id": subject_category_id,
+ "data_id": data_id
+ }
+ req = client.post("/policies/{}/subject_assignments".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ subject_assignment = utilities.get_json(req.data)
+ return req, subject_assignment
+
+
+def add_subject_assignment_without_cat_id(client):
+
+ data = {
+ "id": "subject_id",
+ "category_id": "",
+ "data_id": "data_id"
+ }
+ req = client.post("/policies/{}/subject_assignments".format("1111"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ subject_assignment = utilities.get_json(req.data)
+ return req, subject_assignment
+
+
+def delete_subject_assignment(client, policy_id, sub_id, cat_id,data_id):
+ req = client.delete("/policies/{}/subject_assignments/{}/{}/{}".format(policy_id, sub_id, cat_id,data_id))
+ return req
+
+
+def test_add_subject_assignment():
+ client = utilities.register_client()
+ req, subject_assignment = add_subject_assignment(client)
+ assert req.status_code == 200
+ assert isinstance(subject_assignment, dict)
+ assert "subject_assignments" in subject_assignment
+
+
+def test_add_subject_assignment_without_cat_id():
+ client = utilities.register_client()
+ req, subject_assignment = add_subject_assignment_without_cat_id(client)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'category_id', [Empty String]"
+
+
+def test_get_subject_assignment():
+ client = utilities.register_client()
+ policy_id = builder.get_policy_id_with_subject_assignment()
+ req, subject_assignment = get_subject_assignment(client, policy_id)
+ assert req.status_code == 200
+ assert isinstance(subject_assignment, dict)
+ assert "subject_assignments" in subject_assignment
+
+
+def test_delete_subject_assignment():
+ client = utilities.register_client()
+ policy_id = builder.get_policy_id_with_subject_assignment()
+ req, subject_assignment = get_subject_assignment(client, policy_id)
+ value = subject_assignment["subject_assignments"]
+ id = list(value.keys())[0]
+ success_req = delete_subject_assignment(client, policy_id, value[id]['subject_id'], value[id]['category_id'],value[id]['assignments'][0])
+ assert success_req.status_code == 200
+
+
+def test_delete_subject_assignment_without_policy_id():
+ client = utilities.register_client()
+ success_req = delete_subject_assignment(client, "", "id1", "111" ,"data_id1")
+ assert success_req.status_code == 404
+
+
+# ---------------------------------------------------------------------------
+
+# object_categories_test
+
+
+def get_object_assignment(client, policy_id):
+ req = client.get("/policies/{}/object_assignments".format(policy_id))
+ object_assignment = utilities.get_json(req.data)
+ return req, object_assignment
+
+
+def add_object_assignment(client):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex)
+ object_id = builder.create_object(policy_id)
+ data_id = builder.create_object_data(policy_id=policy_id, category_id=object_category_id)
+
+ data = {
+ "id": object_id,
+ "category_id": object_category_id,
+ "data_id": data_id
+ }
+
+ req = client.post("/policies/{}/object_assignments".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ object_assignment = utilities.get_json(req.data)
+ return req, object_assignment
+
+
+def add_object_assignment_without_cat_id(client):
+
+ data = {
+ "id": "object_id",
+ "category_id": "",
+ "data_id": "data_id"
+ }
+ req = client.post("/policies/{}/object_assignments".format("1111"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ object_assignment = utilities.get_json(req.data)
+ return req, object_assignment
+
+
+def delete_object_assignment(client, policy_id, obj_id, cat_id, data_id):
+ req = client.delete("/policies/{}/object_assignments/{}/{}/{}".format(policy_id, obj_id, cat_id, data_id))
+ return req
+
+
+def test_get_object_assignment():
+ policy_id = builder.get_policy_id_with_object_assignment()
+ client = utilities.register_client()
+ req, object_assignment = get_object_assignment(client, policy_id)
+ assert req.status_code == 200
+ assert isinstance(object_assignment, dict)
+ assert "object_assignments" in object_assignment
+
+
+def test_add_object_assignment():
+ client = utilities.register_client()
+ req, object_assignment = add_object_assignment(client)
+ assert req.status_code == 200
+ assert "object_assignments" in object_assignment
+
+
+def test_add_object_assignment_without_cat_id():
+ client = utilities.register_client()
+ req, object_assignment = add_object_assignment_without_cat_id(client)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'category_id', [Empty String]"
+
+
+def test_delete_object_assignment():
+ client = utilities.register_client()
+ policy_id = builder.get_policy_id_with_object_assignment()
+ req, object_assignment = get_object_assignment(client, policy_id)
+ value = object_assignment["object_assignments"]
+ id = list(value.keys())[0]
+ success_req = delete_object_assignment(client, policy_id, value[id]['object_id'], value[id]['category_id'],value[id]['assignments'][0])
+ assert success_req.status_code == 200
+
+
+def test_delete_object_assignment_without_policy_id():
+ client = utilities.register_client()
+ success_req = delete_object_assignment(client, "", "id1", "111","data_id1")
+ assert success_req.status_code == 404
+
+
+# ---------------------------------------------------------------------------
+
+# action_categories_test
+
+
+def get_action_assignment(client, policy_id):
+ req = client.get("/policies/{}/action_assignments".format(policy_id))
+ action_assignment = utilities.get_json(req.data)
+ return req, action_assignment
+
+
+def add_action_assignment(client):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex)
+ action_id = builder.create_action(policy_id)
+ data_id = builder.create_action_data(policy_id=policy_id, category_id=action_category_id)
+
+ data = {
+ "id": action_id,
+ "category_id": action_category_id,
+ "data_id": data_id
+ }
+ req = client.post("/policies/{}/action_assignments".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ action_assignment = utilities.get_json(req.data)
+ return req, action_assignment
+
+
+def add_action_assignment_without_cat_id(client):
+
+ data = {
+ "id": "action_id",
+ "category_id": "",
+ "data_id": "data_id"
+ }
+ req = client.post("/policies/{}/action_assignments".format("1111"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ action_assignment = utilities.get_json(req.data)
+ return req, action_assignment
+
+
+def delete_action_assignment(client, policy_id, action_id, cat_id, data_id):
+ req = client.delete("/policies/{}/action_assignments/{}/{}/{}".format(policy_id, action_id, cat_id, data_id))
+ return req
+
+
+def test_get_action_assignment():
+ policy_id = builder.get_policy_id_with_action_assignment()
+ client = utilities.register_client()
+ req, action_assignment = get_action_assignment(client, policy_id)
+ assert req.status_code == 200
+ assert isinstance(action_assignment, dict)
+ assert "action_assignments" in action_assignment
+
+
+def test_add_action_assignment():
+ client = utilities.register_client()
+ req, action_assignment = add_action_assignment(client)
+ assert req.status_code == 200
+ assert "action_assignments" in action_assignment
+
+
+def test_add_action_assignment_without_cat_id():
+ client = utilities.register_client()
+ req, action_assignment = add_action_assignment_without_cat_id(client)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'category_id', [Empty String]"
+
+
+def test_delete_action_assignment():
+ client = utilities.register_client()
+ policy_id = builder.get_policy_id_with_action_assignment()
+ req, action_assignment = get_action_assignment(client, policy_id)
+ value = action_assignment["action_assignments"]
+ id = list(value.keys())[0]
+ success_req = delete_action_assignment(client, policy_id, value[id]['action_id'], value[id]['category_id'],value[id]['assignments'][0])
+ assert success_req.status_code == 200
+
+
+def test_delete_action_assignment_without_policy_id():
+ client = utilities.register_client()
+ success_req = delete_action_assignment(client, "", "id1", "111" ,"data_id1")
+ assert success_req.status_code == 404
+
+# ---------------------------------------------------------------------------
diff --git a/old/moon_manager/tests/unit_python/api/test_data.py b/old/moon_manager/tests/unit_python/api/test_data.py
new file mode 100644
index 00000000..433f69e6
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/test_data.py
@@ -0,0 +1,239 @@
+# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import api.utilities as utilities
+import json
+from helpers import data_builder as builder
+from uuid import uuid4
+
+# subject_categories_test
+
+
+def get_subject_data(client, policy_id, category_id=None):
+ if category_id is None:
+ req = client.get("/policies/{}/subject_data".format(policy_id))
+ else:
+ req = client.get("/policies/{}/subject_data/{}".format(policy_id, category_id))
+ subject_data = utilities.get_json(req.data)
+ return req, subject_data
+
+
+def add_subject_data(client, name):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex)
+ data = {
+ "name": name,
+ "description": "description of {}".format(name)
+ }
+ req = client.post("/policies/{}/subject_data/{}".format(policy_id, subject_category_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ subject_data = utilities.get_json(req.data)
+ return req, subject_data
+
+
+def delete_subject_data(client, policy_id, category_id, data_id):
+ req = client.delete("/policies/{}/subject_data/{}/{}".format(policy_id,category_id,data_id))
+ return req
+
+
+def test_get_subject_data():
+ policy_id = utilities.get_policy_id()
+ client = utilities.register_client()
+ req, subject_data = get_subject_data(client, policy_id)
+ assert req.status_code == 200
+ assert isinstance(subject_data, dict)
+ assert "subject_data" in subject_data
+
+
+def test_add_subject_data():
+ client = utilities.register_client()
+ req, subject_data = add_subject_data(client, "testuser")
+ assert req.status_code == 200
+ assert isinstance(subject_data, dict)
+ value = subject_data["subject_data"]['data']
+ assert "subject_data" in subject_data
+ id = list(value.keys())[0]
+ assert value[id]['name'] == "testuser"
+ assert value[id]['description'] == "description of {}".format("testuser")
+
+
+def test_delete_subject_data():
+ client = utilities.register_client()
+ subject_category_id, object_category_id, action_category_id, meta_rule_id,policy_id = builder.create_new_policy()
+ data_id = builder.create_subject_data(policy_id,subject_category_id)
+ success_req = delete_subject_data(client, policy_id, subject_category_id, data_id )
+ assert success_req.status_code == 200
+
+
+def test_add_subject_data_with_forbidden_char_in_user():
+ client = utilities.register_client()
+ req, subject_data = add_subject_data(client, "<a>")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_delete_subject_data_without_policy_id():
+ client = utilities.register_client()
+ success_req = delete_subject_data(client, "", "", "")
+ assert success_req.status_code == 404
+
+# ---------------------------------------------------------------------------
+# object_categories_test
+
+
+def get_object_data(client, policy_id, category_id=None):
+ if category_id is None:
+ req = client.get("/policies/{}/object_data".format(policy_id))
+ else:
+ req = client.get("/policies/{}/object_data/{}".format(policy_id, category_id))
+ object_data = utilities.get_json(req.data)
+ return req, object_data
+
+
+def add_object_data(client, name):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex)
+ data = {
+ "name": name,
+ "description": "description of {}".format(name)
+ }
+ req = client.post("/policies/{}/object_data/{}".format(policy_id, object_category_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ object_data = utilities.get_json(req.data)
+ return req, object_data
+
+
+def delete_object_data(client, policy_id, category_id, data_id):
+ req = client.delete("/policies/{}/object_data/{}/{}".format(policy_id, category_id, data_id))
+ return req
+
+
+def test_get_object_data():
+ policy_id = utilities.get_policy_id()
+ client = utilities.register_client()
+ req, object_data = get_object_data(client, policy_id)
+ assert req.status_code == 200
+ assert isinstance(object_data, dict)
+ assert "object_data" in object_data
+
+
+def test_add_object_data():
+ client = utilities.register_client()
+ req, object_data = add_object_data(client, "testuser")
+ assert req.status_code == 200
+ assert isinstance(object_data, dict)
+ value = object_data["object_data"]['data']
+ assert "object_data" in object_data
+ _id = list(value.keys())[0]
+ assert value[_id]['name'] == "testuser"
+ assert value[_id]['description'] == "description of {}".format("testuser")
+
+
+def test_delete_object_data():
+ client = utilities.register_client()
+
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy()
+ data_id = builder.create_object_data(policy_id, object_category_id)
+
+ success_req = delete_object_data(client, policy_id, data_id, object_category_id)
+ assert success_req.status_code == 200
+
+
+def test_add_object_data_with_forbidden_char_in_user():
+ client = utilities.register_client()
+ req, subject_data = add_object_data(client, "<a>")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_delete_object_data_without_policy_id():
+ client = utilities.register_client()
+ success_req = delete_object_data(client, "", "", "")
+ assert success_req.status_code == 404
+
+# ---------------------------------------------------------------------------
+# action_categories_test
+
+
+def get_action_data(client, policy_id, category_id=None):
+ if category_id is None:
+ req = client.get("/policies/{}/action_data".format(policy_id))
+ else:
+ req = client.get("/policies/{}/action_data/{}".format(policy_id, category_id))
+ action_data = utilities.get_json(req.data)
+ return req, action_data
+
+
+def add_action_data(client, name):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex)
+ data = {
+ "name": name,
+ "description": "description of {}".format(name)
+ }
+ req = client.post("/policies/{}/action_data/{}".format(policy_id, action_category_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ action_data = utilities.get_json(req.data)
+ return req, action_data
+
+
+def delete_action_data(client, policy_id, categorgy_id, data_id):
+ req = client.delete("/policies/{}/action_data/{}/{}".format(policy_id, categorgy_id, data_id))
+ return req
+
+
+def test_get_action_data():
+ policy_id = utilities.get_policy_id()
+ client = utilities.register_client()
+ req, action_data = get_action_data(client, policy_id)
+ assert req.status_code == 200
+ assert isinstance(action_data, dict)
+ assert "action_data" in action_data
+
+
+def test_add_action_data():
+ client = utilities.register_client()
+ req, action_data = add_action_data(client, "testuser")
+ assert req.status_code == 200
+ assert isinstance(action_data, dict)
+ value = action_data["action_data"]['data']
+ assert "action_data" in action_data
+ id = list(value.keys())[0]
+ assert value[id]['name'] == "testuser"
+ assert value[id]['description'] == "description of {}".format("testuser")
+
+
+def test_delete_action_data():
+ client = utilities.register_client()
+
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy()
+ data_id = builder.create_action_data(policy_id, action_category_id)
+
+ success_req = delete_action_data(client, policy_id, data_id, action_category_id)
+
+ assert success_req.status_code == 200
+
+
+def test_add_action_data_with_forbidden_char_in_user():
+ client = utilities.register_client()
+ req, action_data = add_action_data(client, "<a>")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_delete_action_data_without_policy_id():
+ client = utilities.register_client()
+ success_req = delete_action_data(client, "", "", "")
+ assert success_req.status_code == 404
+# ---------------------------------------------------------------------------
diff --git a/old/moon_manager/tests/unit_python/api/test_export.py b/old/moon_manager/tests/unit_python/api/test_export.py
new file mode 100644
index 00000000..ac8e8d17
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/test_export.py
@@ -0,0 +1,282 @@
+# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import json
+import api.utilities as utilities
+import api.import_export_utilities as import_export_utilities
+
+
+MODEL_WITHOUT_META_RULES = {"models": [{"name": "test model", "description": "model description", "meta_rules": []}]}
+
+POLICIES = {"models": [{"name": "test model", "description": "", "meta_rules": []}],
+ "policies": [{"name": "test policy", "genre": "authz", "description": "policy description", "model": {"name" : "test model"}}]}
+
+SUBJECTS_OBJECTS_ACTIONS = {"models": [{"name": "test model", "description": "", "meta_rules": []}],
+ "policies": [{"name": "test policy", "genre": "authz", "description": "policy description", "model": {"name" : "test model"}}],
+ "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {"field_extra_subject": "value extra subject"}, "policies": [{"name": "test policy"}]}],
+ "objects": [{"name": "test object", "description": "description of the object", "extra": {"field_extra_object": "value extra object"}, "policies": [{"name": "test policy"}]}],
+ "actions": [{"name": "test action", "description": "description of the action", "extra": {"field_extra_action": "value extra action"}, "policies": [{"name": "test policy"}]}]}
+
+
+SUBJECT_OBJECT_ACTION_CATEGORIES = {"subject_categories": [{"name": "test subject categories", "description": "subject category description"}],
+ "object_categories": [{"name": "test object categories", "description": "object category description"}],
+ "action_categories": [{"name": "test action categories", "description": "action category description"}]}
+
+SUBJECT_OBJECT_ACTION_DATA = {"models": [{"name": "test model", "description": "", "meta_rules": [{"name": "meta rule"}]}],
+ "policies": [{"name": "test policy", "genre": "authz", "description": "policy description", "model": {"name" : "test model"}}],
+ "subject_categories": [{"name": "test subject categories", "description": "subject category description"}],
+ "object_categories": [{"name": "test object categories", "description": "object category description"}],
+ "action_categories": [{"name": "test action categories", "description": "action category description"}],
+ "subject_data": [{"name": "test subject data", "description": "subject data description", "policies": [{"name": "test policy"}], "category": {"name": "test subject categories"}}],
+ "object_data": [{"name": "test object data", "description": "object data description", "policies": [{"name": "test policy"}], "category": {"name": "test object categories"}}],
+ "action_data": [{"name": "test action data", "description": "action data description", "policies": [{"name": "test policy"}], "category": {"name": "test action categories"}}],
+ "meta_rules": [{"name": "meta rule", "description": "valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}]}
+
+
+META_RULES = {"subject_categories": [{"name": "test subject categories", "description": "subject category description"}],
+ "object_categories": [{"name": "test object categories", "description": "object category description"}],
+ "action_categories": [{"name": "test action categories", "description": "object action description"}],
+ "meta_rules": [{"name": "meta rule", "description": "valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}]}
+
+
+ASSIGNMENTS = {"models": [{"name": "test model", "description": "", "meta_rules": [{"name": "meta rule"}]}],
+ "policies": [{"name": "test policy", "genre": "authz", "description": "policy description", "model": {"name" : "test model"}}],
+ "subject_categories": [{"name": "test subject categories", "description": "subject category description"}],
+ "object_categories": [{"name": "test object categories", "description": "object category description"}],
+ "action_categories": [{"name": "test action categories", "description": "action category description"}],
+ "subject_data": [{"name": "test subject data", "description": "subject data description", "policies": [{"name": "test policy"}], "category": {"name": "test subject categories"}}],
+ "object_data": [{"name": "test object data", "description": "object data description", "policies": [{"name": "test policy"}], "category": {"name": "test object categories"}}],
+ "action_data": [{"name": "test action data", "description": "action data description", "policies": [{"name": "test policy"}], "category": {"name": "test action categories"}}],
+ "meta_rules": [{"name": "meta rule", "description": "valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}],
+ "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {"field_extra_subject": "value extra subject"}, "policies": [{"name": "test policy"}]}],
+ "objects": [{"name": "test object e0", "description": "description of the object", "extra": {"field_extra_object": "value extra object"}, "policies": [{"name": "test policy"}]}],
+ "actions": [{"name": "test action e0", "description": "description of the action", "extra": {"field_extra_action": "value extra action"}, "policies": [{"name": "test policy"}]}],
+ "subject_assignments": [{"subject": {"name": "testuser"}, "category": {"name": "test subject categories"}, "assignments": [{"name": "test subject data"}]}],
+ "object_assignments": [{"object": {"name": "test object e0"}, "category": {"name": "test object categories"}, "assignments": [{"name": "test object data"}]}],
+ "action_assignments": [{"action": {"name": "test action e0"}, "category": {"name": "test action categories"}, "assignments": [{"name": "test action data"}]}]}
+
+RULES = {"models": [{"name": "test model", "description": "", "meta_rules": [{"name": "meta rule"}]}],
+ "policies": [{"name": "test policy", "genre": "authz", "description": "policy description", "model": {"name" : "test model"}}],
+ "subject_categories": [{"name": "test subject categories", "description": "subject category description"}],
+ "object_categories": [{"name": "test object categories", "description": "object category description"}],
+ "action_categories": [{"name": "test action categories", "description": "action category description"}],
+ "subject_data": [{"name": "test subject data", "description": "subject data description", "policies": [{"name": "test policy"}], "category": {"name": "test subject categories"}}],
+ "object_data": [{"name": "test object data", "description": "object data description", "policies": [{"name": "test policy"}], "category": {"name": "test object categories"}}],
+ "action_data": [{"name": "test action data", "description": "action data description", "policies": [{"name": "test policy"}], "category": {"name": "test action categories"}}],
+ "meta_rules": [{"name": "meta rule", "description": "valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}],
+ "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {"field_extra_subject": "value extra subject"}, "policies": [{"name": "test policy"}]}],
+ "objects": [{"name": "test object e1", "description": "description of the object", "extra": {"field_extra_object": "value extra object"}, "policies": [{"name": "test policy"}]}],
+ "actions": [{"name": "test action e1", "description": "description of the action", "extra": {"field_extra_action": "value extra action"}, "policies": [{"name": "test policy"}]}],
+ "subject_assignments": [{"subject": {"name": "testuser"}, "category": {"name": "test subject categories"}, "assignments": [{"name": "test subject data"}]}],
+ "object_assignments": [{"object": {"name": "test object e1"}, "category": {"name": "test object categories"}, "assignments": [{"name": "test object data"}]}],
+ "action_assignments": [{"action": {"name": "test action e1"}, "category": {"name": "test action categories"}, "assignments": [{"name": "test action data"}]}],
+ "rules": [{"meta_rule": {"name": "meta rule"}, "rule": {"subject_data": [{"name": "test subject data"}], "object_data": [{"name": "test object data"}], "action_data": [{"name": "test action data"}]}, "policy": {"name":"test policy"}, "instructions": {"decision": "grant"}, "enabled": True}]
+ }
+
+
+def test_export_models():
+ client = utilities.register_client()
+ import_export_utilities.clean_all(client)
+ req = client.post("/import", content_type='application/json', data=json.dumps(MODEL_WITHOUT_META_RULES))
+ data = utilities.get_json(req.data)
+ assert data == "Import ok !"
+
+ req = client.get("/export")
+ assert req.status_code == 200
+ data = utilities.get_json(req.data)
+
+ assert "content" in data
+ assert "models" in data["content"]
+ assert isinstance(data["content"]["models"], list)
+ assert len(data["content"]["models"]) == 1
+ model = data["content"]["models"][0]
+ assert model["name"] == "test model"
+ assert model["description"] == "model description"
+ assert isinstance(model["meta_rules"], list)
+ assert len(model["meta_rules"]) == 0
+
+
+def test_export_policies():
+ client = utilities.register_client()
+ import_export_utilities.clean_all(client)
+ req = client.post("/import", content_type='application/json', data=json.dumps(POLICIES))
+ data = utilities.get_json(req.data)
+ assert data == "Import ok !"
+
+ req = client.get("/export")
+ assert req.status_code == 200
+ data = utilities.get_json(req.data)
+
+ assert "content" in data
+ assert "policies" in data["content"]
+ assert isinstance(data["content"]["policies"], list)
+ assert len(data["content"]["policies"]) == 1
+ policy = data["content"]["policies"][0]
+ assert policy["name"] == "test policy"
+ assert policy["genre"] == "authz"
+ assert policy["description"] == "policy description"
+ assert "model" in policy
+ assert "name" in policy["model"]
+ model = policy["model"]
+ assert model["name"] == "test model"
+
+
+def test_export_subject_object_action():
+ client = utilities.register_client()
+ import_export_utilities.clean_all(client)
+ req = client.post("/import", content_type='application/json', data=json.dumps(SUBJECTS_OBJECTS_ACTIONS))
+ data = utilities.get_json(req.data)
+ assert data == "Import ok !"
+
+ req = client.get("/export")
+ assert req.status_code == 200
+ data = utilities.get_json(req.data)
+
+ assert "content" in data
+ type_elements = ["subject", "object", "action"]
+ for type_element in type_elements:
+ key = type_element + "s"
+ assert key in data["content"]
+ assert isinstance(data["content"][key], list)
+ assert len(data["content"][key]) == 1
+ element = data["content"][key][0]
+ if type_element == "subject":
+ assert element["name"] == "testuser"
+ else:
+ assert element["name"] == "test "+ type_element
+ assert element["description"] == "description of the " + type_element
+ assert "policies" in element
+ assert isinstance(element["policies"], list)
+ assert len(element["policies"]) == 1
+ assert isinstance(element["policies"][0], dict)
+ assert element["policies"][0]["name"] == "test policy"
+ assert isinstance(element["extra"], dict)
+ key_dict = "field_extra_" + type_element
+ value_dict = "value extra " + type_element
+ assert key_dict in element["extra"]
+ assert element["extra"][key_dict] == value_dict
+
+
+def test_export_subject_object_action_categories():
+ client = utilities.register_client()
+ import_export_utilities.clean_all(client)
+ req = client.post("/import", content_type='application/json', data=json.dumps(SUBJECT_OBJECT_ACTION_CATEGORIES))
+ data = utilities.get_json(req.data)
+ assert data == "Import ok !"
+
+ req = client.get("/export")
+ assert req.status_code == 200
+ data = utilities.get_json(req.data)
+ assert "content" in data
+ type_elements = ["subject", "object", "action"]
+ for type_element in type_elements:
+ key = type_element + "_categories"
+ assert key in data["content"]
+ assert isinstance(data["content"][key], list)
+ assert len(data["content"][key]) == 1
+ category = data["content"][key][0]
+ assert category["name"] == "test " + type_element + " categories"
+ assert category["description"] == type_element + " category description"
+
+
+def test_export_subject_object_action_data():
+ client = utilities.register_client()
+ import_export_utilities.clean_all(client)
+ req = client.post("/import", content_type='application/json', data=json.dumps(SUBJECT_OBJECT_ACTION_DATA))
+ data = utilities.get_json(req.data)
+ assert data == "Import ok !"
+
+ req = client.get("/export")
+ assert req.status_code == 200
+ data = utilities.get_json(req.data)
+ assert "content" in data
+ type_elements = ["subject", "object", "action"]
+ for type_element in type_elements:
+ key = type_element + "_data"
+ assert key in data["content"]
+ assert isinstance(data["content"][key], list)
+ assert len(data["content"][key]) == 1
+ data_elt = data["content"][key][0]
+ assert data_elt["name"] == "test " + type_element + " data"
+ assert data_elt["description"] == type_element + " data description"
+ assert isinstance(data_elt["policy"], dict)
+ assert data_elt["policy"]["name"] == "test policy"
+ assert isinstance(data_elt["category"], dict)
+ assert data_elt["category"]["name"] == "test " + type_element + " categories"
+
+
+def test_export_assignments():
+ client = utilities.register_client()
+ import_export_utilities.clean_all(client)
+ req = client.post("/import", content_type='application/json', data=json.dumps(ASSIGNMENTS))
+ data = utilities.get_json(req.data)
+ assert data == "Import ok !"
+
+ req = client.get("/export")
+ assert req.status_code == 200
+ data = utilities.get_json(req.data)
+ assert "content" in data
+ type_elements = ["subject", "object", "action"]
+ for type_element in type_elements:
+ key = type_element + "_assignments"
+ assert key in data["content"]
+ assert isinstance(data["content"][key], list)
+ assert len(data["content"][key]) == 1
+ assignment_elt = data["content"][key][0]
+ assert type_element in assignment_elt
+ assert isinstance(assignment_elt[type_element], dict)
+ if type_element == "subject":
+ assert assignment_elt[type_element]["name"] == "testuser"
+ else:
+ assert assignment_elt[type_element]["name"] == "test " + type_element + " e0"
+ assert "category" in assignment_elt
+ assert isinstance(assignment_elt["category"], dict)
+ assert assignment_elt["category"]["name"] == "test " + type_element + " categories"
+ assert "assignments" in assignment_elt
+ assert isinstance(assignment_elt["assignments"], list)
+ assert len(assignment_elt["assignments"]) == 1
+ assert assignment_elt["assignments"][0]["name"] == "test " + type_element + " data"
+
+ import_export_utilities.clean_all(client)
+
+
+def test_export_rules():
+ client = utilities.register_client()
+ import_export_utilities.clean_all(client)
+ req = client.post("/import", content_type='application/json', data=json.dumps(RULES))
+ data = utilities.get_json(req.data)
+ assert data == "Import ok !"
+
+ req = client.get("/export")
+ assert req.status_code == 200
+ data = utilities.get_json(req.data)
+ assert "content" in data
+ assert "rules" in data["content"]
+ assert isinstance(data["content"]["rules"], list)
+ assert len(data["content"]["rules"]) == 1
+ rule = data["content"]["rules"][0]
+ assert "instructions" in rule
+ assert "decision" in rule["instructions"]
+ assert rule["instructions"]["decision"] == "grant"
+ assert "enabled" in rule
+ assert rule["enabled"]
+ assert "meta_rule" in rule
+ assert rule["meta_rule"]["name"] == "meta rule"
+ assert "policy" in rule
+ assert rule["policy"]["name"] == "test policy"
+ assert "rule" in rule
+ rule = rule["rule"]
+ assert "subject_data" in rule
+ assert isinstance(rule["subject_data"], list)
+ assert len(rule["subject_data"]) == 1
+ assert rule["subject_data"][0]["name"] == "test subject data"
+ assert "object_data" in rule
+ assert isinstance(rule["object_data"], list)
+ assert len(rule["object_data"]) == 1
+ assert rule["object_data"][0]["name"] == "test object data"
+ assert "action_data" in rule
+ assert isinstance(rule["action_data"], list)
+ assert len(rule["action_data"]) == 1
+ assert rule["action_data"][0]["name"] == "test action data"
diff --git a/old/moon_manager/tests/unit_python/api/test_import.py b/old/moon_manager/tests/unit_python/api/test_import.py
new file mode 100644
index 00000000..af5f753a
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/test_import.py
@@ -0,0 +1,510 @@
+# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import api.utilities as utilities
+import api.test_unit_models as test_models
+import api.test_policies as test_policies
+import api.test_meta_data as test_categories
+import api.test_data as test_data
+import api.test_meta_rules as test_meta_rules
+import api.test_assignement as test_assignments
+import api.test_rules as test_rules
+import api.import_export_utilities as import_export_utilities
+
+import json
+
+
+MODEL_WITHOUT_META_RULES = [
+ {"models": [{"name": "test model", "description": "", "meta_rules": []}]},
+ {"models": [{"name": "test model", "description": "new description", "meta_rules": [], "override": True}]},
+ {"models": [{"name": "test model", "description": "description not taken into account", "meta_rules": [], "override": False}]}
+ ]
+
+POLICIES = [
+ {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {}, "mandatory": False}]},
+ {"policies": [{"name": "test policy", "genre": "authz", "description": "new description not taken into account", "model": {"name" : "test model"}, "mandatory": True}]},
+ {"policies": [{"name": "test policy", "genre": "not authz ?", "description": "generates an exception", "model": {"name" : "test model"}, "override": True}]},
+ {"models": [{"name": "test model", "description": "", "meta_rules": []}], "policies": [{"name": "test policy", "genre": "not authz ?", "description": "changes taken into account", "model": {"name" : "test model"}, "override": True}]},
+]
+
+SUBJECTS = [{"subjects": [{"name": "testuser", "description": "description of the subject", "extra": {}, "policies": []}]},
+ {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {}, "mandatory": False}], "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {}, "policies": []}]},
+ {"policies": [{"name": "test other policy", "genre": "authz", "description": "description", "model": {}, "mandatory": True}], "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {}, "policies": []}]},
+ {"subjects": [{"name": "testuser", "description": "new description of the subject", "extra": {"email": "new-email@test.com"}, "policies": [{"name": "test other policy"}]}]},
+ {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {}, "mandatory": False}], "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {}, "policies": [{"name": "test policy"}]}]}]
+
+
+OBJECTS = [
+ {"objects": [{"name": "test object", "description": "description of the object", "extra": {}, "policies": []}]},
+ {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {}, "mandatory": False}],
+ "objects": [{"name": "test object", "description": "description of the object", "extra": {}, "policies": []}]},
+ {"policies": [{"name": "test other policy", "genre": "authz", "description": "description", "model": {}, "mandatory": True}],
+ "objects": [{"name": "test object", "description": "description of the object", "extra": {}, "policies": []}]},
+ {"objects": [{"name": "test object", "description": "new description of the object",
+ "extra": {"test": "test extra"},
+ "policies": [{"name": "test other policy"}]}]},
+ {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {}, "mandatory": False}],
+ "objects": [{"name": "test object", "description": "description of the object", "extra": {}, "policies": [{"name": "test policy"}]}]},
+]
+
+
+ACTIONS = [{"actions": [{"name": "test action", "description": "description of the action", "extra": {}, "policies": []}]},
+ {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {}, "mandatory": False}], "actions": [{"name": "test action", "description": "description of the action", "extra": {}, "policies": []}]},
+ {"policies": [{"name": "test other policy", "genre": "authz", "description": "description", "model": {}, "mandatory": True}], "actions": [{"name": "test action", "description": "description of the action", "extra": {}, "policies": []}]},
+ {"actions": [{"name": "test action", "description": "new description of the action", "extra": {"test": "test extra"}, "policies": [{"name": "test other policy"}]}]},
+ {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {}, "mandatory": False}], "actions": [{"name": "test action", "description": "description of the action", "extra": {}, "policies": [{"name": "test policy"}]}]}]
+
+
+SUBJECT_CATEGORIES = [{"subject_categories": [{"name": "test subject categories", "description": "subject category description"}]},
+ {"subject_categories": [{"name": "test subject categories", "description": "new subject category description"}]}]
+
+
+OBJECT_CATEGORIES = [{"object_categories": [{"name": "test object categories", "description": "object category description"}]},
+ {"object_categories": [{"name": "test object categories", "description": "new object category description"}]}]
+
+
+ACTION_CATEGORIES = [{"action_categories": [{"name": "test action categories", "description": "action category description"}]},
+ {"action_categories": [{"name": "test action categories", "description": "new action category description"}]}]
+
+# meta_rules import is needed otherwise the search for data do not work !!!
+PRE_DATA = {"models": [{"name": "test model", "description": "", "meta_rules": [{"name": "good meta rule"}, {"name": "other good meta rule"}]}],
+ "policies": [{"name": "test other policy", "genre": "authz", "description": "description", "model": {"name": "test model"}, "mandatory": True}],
+ "subject_categories": [{"name": "test subject categories", "description": "subject category description"}, {"name": "other test subject categories", "description": "subject category description"}],
+ "object_categories": [{"name": "test object categories", "description": "object category description"}, {"name": "other test object categories", "description": "object category description"}],
+ "action_categories": [{"name": "test action categories", "description": "action category description"}, {"name": "other test action categories", "description": "action category description"}],
+ "meta_rules": [{"name": "good meta rule", "description": "valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]},
+ {"name": "other good meta rule", "description": "valid meta rule", "subject_categories": [{"name": "other test subject categories"}], "object_categories": [{"name": "other test object categories"}], "action_categories": [{"name": "other test action categories"}]}]}
+
+SUBJECT_DATA = [{"subject_data": [{"name": "not valid subject data", "description": "", "policies": [{}], "category": {}}]},
+ {"subject_data": [{"name": "not valid subject data", "description": "", "policies": [{}], "category": {"name": "test subject categories"}}]},
+ {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {"name": "test model"}, "mandatory": True}], "subject_data": [{"name": "one valid subject data", "description": "description", "policies": [{}], "category": {"name": "test subject categories"}}]},
+ {"subject_data": [{"name": "valid subject data", "description": "description", "policies": [{"name": "test policy"}], "category": {"name": "test subject categories"}}]},
+ {"subject_data": [{"name": "valid subject data", "description": "new description", "policies": [{"name": "test other policy"}], "category": {"name": "test subject categories"}}]}]
+
+OBJECT_DATA = [{"object_data": [{"name": "not valid object data", "description": "", "policies": [{}], "category": {}}]},
+ {"object_data": [{"name": "not valid object data", "description": "", "policies": [{}], "category": {"name": "test object categories"}}]},
+ {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {"name": "test model"}, "mandatory": True}], "object_data": [{"name": "one valid object data", "description": "description", "policies": [{}], "category": {"name": "test object categories"}}]},
+ {"object_data": [{"name": "valid object data", "description": "description", "policies": [{"name": "test policy"}], "category": {"name": "test object categories"}}]},
+ {"object_data": [{"name": "valid object data", "description": "new description", "policies": [{"name": "test other policy"}], "category": {"name": "test object categories"}}]}]
+
+
+ACTION_DATA = [{"action_data": [{"name": "not valid action data", "description": "", "policies": [{}], "category": {}}]},
+ {"action_data": [{"name": "not valid action data", "description": "", "policies": [{}], "category": {"name": "test action categories"}}]},
+ {"policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {"name": "test model"}, "mandatory": True}], "action_data": [{"name": "one valid action data", "description": "description", "policies": [{}], "category": {"name": "test action categories"}}]},
+ {"action_data": [{"name": "valid action data", "description": "description", "policies": [{"name": "test policy"}], "category": {"name": "test action categories"}}]},
+ {"action_data": [{"name": "valid action data", "description": "new description", "policies": [{"name": "test other policy"}], "category": {"name": "test action categories"}}]}]
+
+
+PRE_META_RULES = {"subject_categories": [{"name": "test subject categories", "description": "subject category description"}],
+ "object_categories": [{"name": "test object categories", "description": "object category description"}],
+ "action_categories": [{"name": "test action categories", "description": "object action description"}]}
+
+META_RULES = [{"meta_rules" :[{"name": "bad meta rule", "description": "not valid meta rule", "subject_categories": [{"name": "not valid category"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}]},
+ {"meta_rules": [{"name": "bad meta rule", "description": "not valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "not valid category"}], "action_categories": [{"name": "test action categories"}]}]},
+ {"meta_rules": [{"name": "bad meta rule", "description": "not valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "not valid category"}]}]},
+ {"meta_rules": [{"name": "good meta rule", "description": "valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}]}]
+
+
+PRE_ASSIGNMENTS = {"models": [{"name": "test model", "description": "", "meta_rules": [{"name": "good meta rule"}]}],
+ "policies": [{"name": "test policy", "genre": "authz", "description": "description", "model": {"name" : "test model"}, "mandatory": True}],
+ "subject_categories": [{"name": "test subject categories", "description": "subject category description"}],
+ "object_categories": [{"name": "test object categories", "description": "object category description"}],
+ "action_categories": [{"name": "test action categories", "description": "object action description"}],
+ "subjects": [{"name": "testuser", "description": "description of the subject", "extra": {}, "policies": [{"name": "test policy"}]}],
+ "objects": [{"name": "test object", "description": "description of the object", "extra": {}, "policies": [{"name": "test policy"}]}],
+ "actions": [{"name": "test action", "description": "description of the action", "extra": {}, "policies": [{"name": "test policy"}]}],
+ "meta_rules": [{"name": "good meta rule", "description": "valid meta rule", "subject_categories": [{"name": "test subject categories"}], "object_categories": [{"name": "test object categories"}], "action_categories": [{"name": "test action categories"}]}],
+ "subject_data": [{"name": "subject data", "description": "test subject data", "policies": [{"name": "test policy"}], "category": {"name": "test subject categories"}}],
+ "object_data": [{"name": "object data", "description": "test object data", "policies": [{"name": "test policy"}], "category": {"name": "test object categories"}}],
+ "action_data": [{"name": "action data", "description": "test action data", "policies": [{"name": "test policy"}], "category": {"name": "test action categories"}}]}
+
+
+SUBJECT_ASSIGNMENTS = [{"subject_assignments": [{"subject": {"name": "unknonw"}, "category" : {"name": "test subject categories"}, "assignments": [{"name": "subject data"}]}]},
+ {"subject_assignments": [{"subject": {"name": "testuser"}, "category": {"name": "unknown"}, "assignments": [{"name": "subject data"}]}]},
+ {"subject_assignments": [{"subject": {"name": "testuser"}, "category" : {"name": "test subject categories"}, "assignments": [{"name": "unknwon"}]}]},
+ {"subject_assignments": [{"subject": {"name": "testuser"}, "category": {"name": "test subject categories"}, "assignments": [{"name": "subject data"}]}]}]
+
+OBJECT_ASSIGNMENTS = [{"object_assignments": [{"object": {"name": "unknown"}, "category" : {"name": "test object categories"}, "assignments": [{"name": "object data"}]}]},
+ {"object_assignments": [{"object": {"name": "test object"}, "category" : {"name": "unknown"}, "assignments": [{"name": "object data"}]}]},
+ {"object_assignments": [{"object": {"name": "test object"}, "category" : {"name": "test object categories"}, "assignments": [{"name": "unknown"}]}]},
+ {"object_assignments": [{"object": {"name": "test object"}, "category" : {"name": "test object categories"}, "assignments": [{"name": "object data"}]}]}]
+
+ACTION_ASSIGNMENTS = [{"action_assignments": [{"action": {"name": "unknown"}, "category" : {"name": "test action categories"}, "assignments": [{"name": "action data"}]}]},
+ {"action_assignments": [{"action": {"name": "test action"}, "category" : {"name": "unknown"}, "assignments": [{"name": "action data"}]}]},
+ {"action_assignments": [{"action": {"name": "test action"}, "category" : {"name": "test action categories"}, "assignments": [{"name": "unknown"}]}]},
+ {"action_assignments": [{"action": {"name": "test action"}, "category" : {"name": "test action categories"}, "assignments": [{"name": "action data"}]}]}]
+
+RULES = [{"rules": [{"meta_rule": {"name": "unknown meta rule"}, "policy": {"name": "test policy"}, "instructions": {"decision": "grant"}, "enabled": True, "rule": {"subject_data": [{"name": "subject data"}], "object_data": [{"name": "object data"}], "action_data": [{"name": "action data"}]}}]},
+ {"rules": [{"meta_rule": {"name": "good meta rule"}, "policy": {"name": "unknown policy"}, "instructions": {"decision": "grant"}, "enabled": True, "rule": {"subject_data": [{"name": "subject data"}], "object_data": [{"name": "object data"}], "action_data": [{"name": "action data"}]}}]},
+ {"rules": [{"meta_rule": {"name": "good meta rule"}, "policy": {"name": "test policy"}, "instructions": {"decision": "grant"}, "enabled": True, "rule": {"subject_data": [{"name": "unknown subject data"}], "object_data": [{"name": "object data"}], "action_data": [{"name": "action data"}]}}]},
+ {"rules": [{"meta_rule": {"name": "good meta rule"}, "policy": {"name": "test policy"}, "instructions": {"decision": "grant"}, "enabled": True, "rule": {"subject_data": [{"name": "subject data"}], "object_data": [{"name": "unknown object data"}], "action_data": [{"name": "action data"}]}}]},
+ {"rules": [{"meta_rule": {"name": "good meta rule"}, "policy": {"name": "test policy"}, "instructions": {"decision": "grant"}, "enabled": True, "rule": {"subject_data": [{"name": "subject data"}], "object_data": [{"name": "object data"}], "action_data": [{"name": "unknown action data"}]}}]},
+ {"rules": [{"meta_rule": {"name": "good meta rule"}, "policy": {"name": "test policy"}, "instructions": {"decision": "grant"}, "enabled": True, "rule": {"subject_data": [{"name": "subject data"}], "object_data": [{"name": "object data"}], "action_data": [{"name": "action data"}]}}]}]
+
+
+def test_import_models_without_new_meta_rules():
+ client = utilities.register_client()
+ import_export_utilities.clean_all(client)
+ counter = 0
+ for models_description in MODEL_WITHOUT_META_RULES:
+ req = client.post("/import", content_type='application/json', data=json.dumps(models_description))
+ data = utilities.get_json(req.data)
+ assert data == "Import ok !"
+ req, models = test_models.get_models(client)
+ models = models["models"]
+ assert len(list(models.keys())) == 1
+ values = list(models.values())
+ assert values[0]["name"] == "test model"
+ if counter == 0:
+ assert len(values[0]["description"]) == 0
+ if counter == 1 or counter == 2:
+ assert values[0]["description"] == "new description"
+ counter = counter + 1
+ import_export_utilities.clean_all(client)
+
+
+def test_import_policies():
+ client = utilities.register_client()
+ import_export_utilities.clean_all(client)
+ counter = -1
+ for policy_description in POLICIES:
+ counter = counter + 1
+ req = client.post("/import", content_type='application/json', data=json.dumps(policy_description))
+ try:
+ data = utilities.get_json(req.data)
+ assert data == "Import ok !"
+ except Exception:
+ assert counter == 2 # this is an expected failure
+ continue
+
+ req, policies = test_policies.get_policies(client)
+ policies = policies["policies"]
+ assert len(list(policies.keys())) == 1
+ values = list(policies.values())
+ assert values[0]["name"] == "test policy"
+ if counter < 3:
+ assert values[0]["genre"] == "authz"
+ assert values[0]["description"] == "description"
+ else:
+ assert values[0]["genre"] == "not authz ?"
+ assert values[0]["description"] == "changes taken into account"
+ assert len(values[0]["model_id"]) > 0
+ import_export_utilities.clean_all(client)
+
+
+def test_import_subject_object_action():
+ client = utilities.register_client()
+ type_elements = ["object", "action"]
+
+ for type_element in type_elements:
+ import_export_utilities.clean_all(client)
+ counter = -1
+ # set the getters and the comparison values
+ if type_element == "subject":
+ elements = SUBJECTS
+ clean_method = import_export_utilities.clean_subjects
+ name = "testuser"
+ key_extra = "email"
+ value_extra = "new-email@test.com"
+ elif type_element == "object":
+ elements = OBJECTS
+ clean_method = import_export_utilities.clean_objects
+ name = "test object"
+ key_extra = "test"
+ value_extra = "test extra"
+ else:
+ elements = ACTIONS
+ clean_method = import_export_utilities.clean_actions
+ name = "test action"
+ key_extra = "test"
+ value_extra = "test extra"
+
+ for element in elements:
+ counter = counter + 1
+ if counter == 2 or counter == 4:
+ clean_method(client)
+
+
+ if counter == 3:
+ req = client.patch("/{}s/{}".format(type_element,perimeter_id), content_type='application/json',
+ data=json.dumps(
+ element["{}s".format(type_element)][0]))
+ else :
+ req = client.post("/import", content_type='application/json',
+ data=json.dumps(element))
+ if counter < 2:
+ assert req.status_code == 500
+ continue
+
+ try:
+ data = utilities.get_json(req.data)
+ except Exception as e:
+ assert False
+ #assert counter < 2 #  this is an expected failure
+ #continue
+
+ if counter != 3:
+ assert data == "Import ok !"
+ get_elements = utilities.get_json(client.get("/"+type_element + "s").data)
+ get_elements = get_elements[type_element + "s"]
+
+ perimeter_id = list(get_elements.keys())[0]
+
+ assert len(list(get_elements.keys())) == 1
+ values = list(get_elements.values())
+ assert values[0]["name"] == name
+ if counter == 2 or counter == 4:
+ assert values[0]["description"] == "description of the " + type_element
+ #assert not values[0]["extra"]
+ if counter == 3:
+ assert values[0]["description"] == "new description of the " + type_element
+ assert values[0]["extra"][key_extra] == value_extra
+
+ # assert len(values[0]["policy_list"]) == 1
+ import_export_utilities.clean_all(client)
+
+
+def test_import_subject_object_action_categories():
+ client = utilities.register_client()
+ type_elements = ["subject", "object", "action"]
+
+ for type_element in type_elements:
+ import_export_utilities.clean_all(client)
+ counter = -1
+ # set the getters and the comparison values
+ if type_element == "subject":
+ elements = SUBJECT_CATEGORIES
+ get_method = test_categories.get_subject_categories
+ elif type_element == "object":
+ elements = OBJECT_CATEGORIES
+ get_method = test_categories.get_object_categories
+ else:
+ elements = ACTION_CATEGORIES
+ get_method = test_categories.get_action_categories
+
+ for element in elements:
+ req = client.post("/import", content_type='application/json', data=json.dumps(element))
+ counter = counter + 1
+ data = utilities.get_json(req.data)
+ assert data == "Import ok !"
+ req, get_elements = get_method(client)
+ get_elements = get_elements[type_element + "_categories"]
+ assert len(list(get_elements.keys())) == 1
+ values = list(get_elements.values())
+ assert values[0]["name"] == "test " + type_element + " categories"
+ assert values[0]["description"] == type_element + " category description"
+
+
+def test_import_meta_rules():
+ client = utilities.register_client()
+ import_export_utilities.clean_all(client)
+ # import some categories
+ req = client.post("/import", content_type='application/json', data=json.dumps(PRE_META_RULES))
+ data = utilities.get_json(req.data)
+ assert data == "Import ok !"
+
+ counter = -1
+ for meta_rule in META_RULES:
+ counter = counter + 1
+ req = client.post("/import", content_type='application/json', data=json.dumps(meta_rule))
+ if counter != 3:
+ assert req.status_code == 500
+ continue
+ else:
+ data = utilities.get_json(req.data)
+ assert data == "Import ok !"
+ assert req.status_code == 200
+
+ req, meta_rules = test_meta_rules.get_meta_rules(client)
+ meta_rules = meta_rules["meta_rules"]
+ key = list(meta_rules.keys())[0]
+ assert isinstance(meta_rules,dict)
+ assert meta_rules[key]["name"] == "good meta rule"
+ assert meta_rules[key]["description"] == "valid meta rule"
+ assert len(meta_rules[key]["subject_categories"]) == 1
+ assert len(meta_rules[key]["object_categories"]) == 1
+ assert len(meta_rules[key]["action_categories"]) == 1
+
+ subject_category_key = meta_rules[key]["subject_categories"][0]
+ object_category_key = meta_rules[key]["object_categories"][0]
+ action_category_key = meta_rules[key]["action_categories"][0]
+
+ req, sub_cat = test_categories.get_subject_categories(client)
+ sub_cat = sub_cat["subject_categories"]
+ assert sub_cat[subject_category_key]["name"] == "test subject categories"
+
+ req, ob_cat = test_categories.get_object_categories(client)
+ ob_cat = ob_cat["object_categories"]
+ assert ob_cat[object_category_key]["name"] == "test object categories"
+
+ req, ac_cat = test_categories.get_action_categories(client)
+ ac_cat = ac_cat["action_categories"]
+ assert ac_cat[action_category_key]["name"] == "test action categories"
+
+ import_export_utilities.clean_all(client)
+
+
+def test_import_subject_object_action_assignments():
+ client = utilities.register_client()
+ import_export_utilities.clean_all(client)
+
+ req = client.post("/import", content_type='application/json', data=json.dumps(PRE_ASSIGNMENTS))
+ data = utilities.get_json(req.data)
+ assert data == "Import ok !"
+
+ type_elements = ["subject", "object", "action"]
+
+ for type_element in type_elements:
+ counter = -1
+ if type_element == "subject":
+ datas = SUBJECT_ASSIGNMENTS
+ get_method = test_assignments.get_subject_assignment
+ elif type_element == "object":
+ datas = OBJECT_ASSIGNMENTS
+ get_method = test_assignments.get_object_assignment
+ else:
+ datas = ACTION_ASSIGNMENTS
+ get_method = test_assignments.get_action_assignment
+
+ for assignments in datas:
+ counter = counter + 1
+ req = client.post("/import", content_type='application/json', data=json.dumps(assignments))
+ if counter != 3:
+ assert req.status_code == 500
+ continue
+ else:
+ assert data == "Import ok !"
+ assert req.status_code == 200
+ req, policies = test_policies.get_policies(client)
+ for policy_key in policies["policies"]:
+ req, get_assignments = get_method(client, policy_key)
+ get_assignments = get_assignments[type_element+"_assignments"]
+ assert len(get_assignments) == 1
+
+
+def test_import_rules():
+ client = utilities.register_client()
+ import_export_utilities.clean_all(client)
+ req = client.post("/import", content_type='application/json', data=json.dumps(PRE_ASSIGNMENTS))
+ data = utilities.get_json(req.data)
+ assert data == "Import ok !"
+
+ counter = -1
+ for rule in RULES:
+ counter = counter + 1
+ req = client.post("/import", content_type='application/json', data=json.dumps(rule))
+
+ if counter < 5:
+ assert req.status_code == 500
+ continue
+
+ assert req.status_code == 200
+
+ req, rules = test_rules.test_get_rules()
+ rules = rules["rules"]
+ rules = rules["rules"]
+ assert len(rules) == 1
+ rules = rules[0]
+ assert rules["enabled"]
+ assert rules["instructions"]["decision"] == "grant"
+
+ req, meta_rules = test_meta_rules.get_meta_rules(client)
+ assert meta_rules["meta_rules"][list(meta_rules["meta_rules"].keys())[0]]["name"] == "good meta rule"
+
+
+def test_import_subject_object_action_data():
+ client = utilities.register_client()
+ type_elements = ["subject", "object", "action"]
+
+ for type_element in type_elements:
+ import_export_utilities.clean_all(client)
+ req = client.post("/import", content_type='application/json', data=json.dumps(PRE_DATA))
+ counter = -1
+ # set the getters and the comparison values
+ if type_element == "subject":
+ elements = SUBJECT_DATA
+ get_method = test_data.get_subject_data
+ get_categories = test_categories.get_subject_categories
+ elif type_element == "object":
+ elements = OBJECT_DATA
+ get_method = test_data.get_object_data
+ get_categories = test_categories.get_object_categories
+ else:
+ elements = ACTION_DATA
+ get_method = test_data.get_action_data
+ get_categories = test_categories.get_action_categories
+
+ for element in elements:
+ req = client.post("/import", content_type='application/json', data=json.dumps(element))
+ counter = counter + 1
+ if counter == 0 or counter == 1:
+ assert req.status_code == 500
+ continue
+ assert req.status_code == 200
+ data = utilities.get_json(req.data)
+ assert data == "Import ok !"
+
+ req, policies = test_policies.get_policies(client)
+ policies = policies["policies"]
+ req, categories = get_categories(client)
+ categories = categories[type_element + "_categories"]
+ case_tested = False
+ for policy_key in policies.keys():
+ policy = policies[policy_key]
+ for category_key in categories:
+ req, get_elements = get_method(client, policy_id=policy_key, category_id=category_key)
+ if len(get_elements[type_element+"_data"]) == 0:
+ continue
+
+ # do this because the backend gives an element with empty data if the policy_key,
+ # category_key couple does not have any data...
+ get_elements = get_elements[type_element+"_data"]
+ if len(get_elements[0]["data"]) == 0:
+ continue
+
+ if policy["name"] == "test policy":
+ assert len(get_elements) == 1
+ el = get_elements[0]
+ assert isinstance(el["data"], dict)
+ if counter == 2:
+ assert len(el["data"].keys()) == 1
+ el = el["data"][list(el["data"].keys())[0]]
+ if "value" in el:
+ el = el["value"]
+ assert el["name"] == "one valid " + type_element + " data"
+ if counter == 3:
+ assert len(el["data"].keys()) == 2
+ el1 = el["data"][list(el["data"].keys())[0]]
+ el2 = el["data"][list(el["data"].keys())[1]]
+ if "value" in el1:
+ el1 = el1["value"]
+ el2 = el2["value"]
+ assert (el1["name"] == "one valid " + type_element + " data" and el2["name"] == "valid " + type_element + " data") or (el2["name"] == "one valid " + type_element + " data" and el1["name"] == "valid " + type_element + " data")
+ assert el1["description"] == "description"
+ assert el2["description"] == "description"
+
+ case_tested = True
+
+ if policy["name"] == "test other policy":
+ if counter == 4:
+ assert len(get_elements) == 1
+ el = get_elements[0]
+ assert isinstance(el["data"], dict)
+ assert len(el["data"].keys()) == 1
+ el = el["data"][list(el["data"].keys())[0]]
+ if "value" in el:
+ el = el["value"]
+ assert el["name"] == "valid " + type_element + " data"
+ assert el["description"] == "new description"
+ case_tested = True
+
+ assert case_tested is True
+
+
+def test_clean():
+ client = utilities.register_client()
+ import_export_utilities.clean_all(client)
+ #restore the database as previously
+ utilities.get_policy_id()
diff --git a/old/moon_manager/tests/unit_python/api/test_meta_data.py b/old/moon_manager/tests/unit_python/api/test_meta_data.py
new file mode 100644
index 00000000..e6cb0833
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/test_meta_data.py
@@ -0,0 +1,305 @@
+import json
+import api.utilities as utilities
+from helpers import data_builder
+from uuid import uuid4
+
+
+# subject_categories_test
+
+
+def get_subject_categories(client):
+ req = client.get("/subject_categories")
+ subject_categories = utilities.get_json(req.data)
+ return req, subject_categories
+
+
+def add_subject_categories(client, name):
+ data = {
+ "name": name,
+ "description": "description of {}".format(name)
+ }
+ req = client.post("/subject_categories", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ subject_categories = utilities.get_json(req.data)
+ return req, subject_categories
+
+
+def delete_subject_categories(client, name):
+ request, subject_categories = get_subject_categories(client)
+ for key, value in subject_categories['subject_categories'].items():
+ if value['name'] == name:
+ return client.delete("/subject_categories/{}".format(key))
+
+
+def delete_subject_categories_without_id(client):
+ req = client.delete("/subject_categories/{}".format(""))
+ return req
+
+
+def test_get_subject_categories():
+ client = utilities.register_client()
+ req, subject_categories = get_subject_categories(client)
+ assert req.status_code == 200
+ assert isinstance(subject_categories, dict)
+ assert "subject_categories" in subject_categories
+
+
+def test_add_subject_categories():
+ client = utilities.register_client()
+ req, subject_categories = add_subject_categories(client, "testuser")
+ assert req.status_code == 200
+ assert isinstance(subject_categories, dict)
+ value = list(subject_categories["subject_categories"].values())[0]
+ assert "subject_categories" in subject_categories
+ assert value['name'] == "testuser"
+ assert value['description'] == "description of {}".format("testuser")
+
+
+def test_add_subject_categories_with_existed_name():
+ client = utilities.register_client()
+ name = uuid4().hex
+ req, subject_categories = add_subject_categories(client, name)
+ assert req.status_code == 200
+ req, subject_categories = add_subject_categories(client, name)
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Subject Category Existing'
+
+
+def test_add_subject_categories_name_contain_space():
+ client = utilities.register_client()
+ req, subject_categories = add_subject_categories(client, " ")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Category Name Invalid'
+
+
+def test_add_subject_categories_with_empty_name():
+ client = utilities.register_client()
+ req, subject_categories = add_subject_categories(client, "<a>")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_add_subject_categories_with_name_contain_space():
+ client = utilities.register_client()
+ req, subject_categories = add_subject_categories(client, "test<z>user")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_delete_subject_categories():
+ client = utilities.register_client()
+ req = delete_subject_categories(client, "testuser")
+ assert req.status_code == 200
+
+
+def test_delete_subject_categories_without_id():
+ client = utilities.register_client()
+ req = delete_subject_categories_without_id(client)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Subject Category Unknown"
+
+
+# ---------------------------------------------------------------------------
+# object_categories_test
+
+def get_object_categories(client):
+ req = client.get("/object_categories")
+ object_categories = utilities.get_json(req.data)
+ return req, object_categories
+
+
+def add_object_categories(client, name):
+ data = {
+ "name": name,
+ "description": "description of {}".format(name)
+ }
+ req = client.post("/object_categories", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ object_categories = utilities.get_json(req.data)
+ return req, object_categories
+
+
+def delete_object_categories(client, name):
+ request, object_categories = get_object_categories(client)
+ for key, value in object_categories['object_categories'].items():
+ if value['name'] == name:
+ return client.delete("/object_categories/{}".format(key))
+
+
+def delete_object_categories_without_id(client):
+ req = client.delete("/object_categories/{}".format(""))
+ return req
+
+
+def test_get_object_categories():
+ client = utilities.register_client()
+ req, object_categories = get_object_categories(client)
+ assert req.status_code == 200
+ assert isinstance(object_categories, dict)
+ assert "object_categories" in object_categories
+
+
+def test_add_object_categories():
+ client = utilities.register_client()
+ req, object_categories = add_object_categories(client, "testuser")
+ assert req.status_code == 200
+ assert isinstance(object_categories, dict)
+ value = list(object_categories["object_categories"].values())[0]
+ assert "object_categories" in object_categories
+ assert value['name'] == "testuser"
+ assert value['description'] == "description of {}".format("testuser")
+
+
+def test_add_object_categories_with_existed_name():
+ client = utilities.register_client()
+ name = uuid4().hex
+ req, object_categories = add_object_categories(client, name)
+ assert req.status_code == 200
+ req, object_categories = add_object_categories(client, name)
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Object Category Existing'
+
+
+def test_add_object_categories_name_contain_space():
+ client = utilities.register_client()
+ req, subject_categories = add_object_categories(client, " ")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Category Name Invalid'
+
+
+def test_add_object_categories_with_empty_name():
+ client = utilities.register_client()
+ req, object_categories = add_object_categories(client, "<a>")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_add_object_categories_with_name_contain_space():
+ client = utilities.register_client()
+ req, object_categories = add_object_categories(client, "test<a>user")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_delete_object_categories():
+ client = utilities.register_client()
+ req = delete_object_categories(client, "testuser")
+ assert req.status_code == 200
+
+
+def test_delete_object_categories_without_id():
+ client = utilities.register_client()
+ req = delete_object_categories_without_id(client)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Object Category Unknown"
+
+
+# ---------------------------------------------------------------------------
+# action_categories_test
+
+def get_action_categories(client):
+ req = client.get("/action_categories")
+ action_categories = utilities.get_json(req.data)
+ return req, action_categories
+
+
+def add_action_categories(client, name):
+ data = {
+ "name": name,
+ "description": "description of {}".format(name)
+ }
+ req = client.post("/action_categories", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ action_categories = utilities.get_json(req.data)
+ return req, action_categories
+
+
+def delete_action_categories(client, name):
+ request, action_categories = get_action_categories(client)
+ for key, value in action_categories['action_categories'].items():
+ if value['name'] == name:
+ return client.delete("/action_categories/{}".format(key))
+
+
+def delete_action_categories_without_id(client):
+ req = client.delete("/action_categories/{}".format(""))
+ return req
+
+
+def test_get_action_categories():
+ client = utilities.register_client()
+ req, action_categories = get_action_categories(client)
+ assert req.status_code == 200
+ assert isinstance(action_categories, dict)
+ assert "action_categories" in action_categories
+
+
+def test_add_action_categories():
+ client = utilities.register_client()
+ req, action_categories = add_action_categories(client, "testuser")
+ assert req.status_code == 200
+ assert isinstance(action_categories, dict)
+ value = list(action_categories["action_categories"].values())[0]
+ assert "action_categories" in action_categories
+ assert value['name'] == "testuser"
+ assert value['description'] == "description of {}".format("testuser")
+
+
+def test_add_action_categories_with_existed_name():
+ client = utilities.register_client()
+ name = uuid4().hex
+ req, action_categories = add_action_categories(client, name)
+ assert req.status_code == 200
+ req, action_categories = add_action_categories(client, name)
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Action Category Existing'
+
+
+def test_add_action_categories_name_contain_space():
+ client = utilities.register_client()
+ req, subject_categories = add_action_categories(client, " ")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Category Name Invalid'
+
+
+def test_add_action_categories_with_empty_name():
+ client = utilities.register_client()
+ req, action_categories = add_action_categories(client, "<a>")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_add_action_categories_with_name_contain_space():
+ client = utilities.register_client()
+ req, action_categories = add_action_categories(client, "test<a>user")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_delete_action_categories():
+ client = utilities.register_client()
+ req = delete_action_categories(client, "testuser")
+ assert req.status_code == 200
+
+
+def test_delete_action_categories_without_id():
+ client = utilities.register_client()
+ req = delete_action_categories_without_id(client)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Action Category Unknown"
+
+
+def test_delete_data_categories_connected_to_meta_rule():
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule()
+ client = utilities.register_client()
+ req = client.delete("/subject_categories/{}".format(subject_category_id))
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Subject Category With Meta Rule Error'
+
+ req = client.delete("/object_categories/{}".format(object_category_id))
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Object Category With Meta Rule Error'
+
+ req = client.delete("/action_categories/{}".format(action_category_id))
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Action Category With Meta Rule Error'
diff --git a/old/moon_manager/tests/unit_python/api/test_meta_rules.py b/old/moon_manager/tests/unit_python/api/test_meta_rules.py
new file mode 100644
index 00000000..634f19da
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/test_meta_rules.py
@@ -0,0 +1,415 @@
+import json
+import api.utilities as utilities
+from helpers import category_helper
+from helpers import data_builder
+from uuid import uuid4
+
+
+def get_meta_rules(client):
+ req = client.get("/meta_rules")
+ meta_rules = utilities.get_json(req.data)
+ return req, meta_rules
+
+
+def add_meta_rules(client, name, data=None):
+ if not data:
+ subject_category = category_helper.add_subject_category(
+ value={"name": "subject category name" + uuid4().hex, "description": "description 1"})
+ subject_category_id = list(subject_category.keys())[0]
+ object_category = category_helper.add_object_category(
+ value={"name": "object category name" + uuid4().hex, "description": "description 1"})
+ object_category_id = list(object_category.keys())[0]
+ action_category = category_helper.add_action_category(
+ value={"name": "action category name" + uuid4().hex, "description": "description 1"})
+ action_category_id = list(action_category.keys())[0]
+
+ data = {
+ "name": name,
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ req = client.post("/meta_rules", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ meta_rules = utilities.get_json(req.data)
+ return req, meta_rules
+
+
+def add_meta_rules_without_category_ids(client, name):
+ data = {
+ "name": name + uuid4().hex,
+ "subject_categories": [],
+ "object_categories": [],
+ "action_categories": []
+ }
+ req = client.post("/meta_rules", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ meta_rules = utilities.get_json(req.data)
+ return req, meta_rules
+
+
+def update_meta_rules(client, name, metaRuleId, data=None):
+ if not data:
+ subject_category = category_helper.add_subject_category(
+ value={"name": "subject category name update" + uuid4().hex,
+ "description": "description 1"})
+ subject_category_id = list(subject_category.keys())[0]
+ object_category = category_helper.add_object_category(
+ value={"name": "object category name update" + uuid4().hex,
+ "description": "description 1"})
+ object_category_id = list(object_category.keys())[0]
+ action_category = category_helper.add_action_category(
+ value={"name": "action category name update" + uuid4().hex,
+ "description": "description 1"})
+ action_category_id = list(action_category.keys())[0]
+ data = {
+ "name": name,
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+
+ req = client.patch("/meta_rules/{}".format(metaRuleId), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ meta_rules = utilities.get_json(req.data)
+ return req, meta_rules
+
+
+def update_meta_rules_with_categories(client, name, data=None, meta_rule_id=None):
+ if not meta_rule_id:
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule()
+ data = {
+ "name": name,
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+
+ req = client.patch("/meta_rules/{}".format(meta_rule_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ meta_rules = utilities.get_json(req.data)
+ return req, meta_rules
+
+
+def delete_meta_rules(client, name):
+ request, meta_rules = get_meta_rules(client)
+ for key, value in meta_rules['meta_rules'].items():
+ if value['name'] == name:
+ return client.delete("/meta_rules/{}".format(key))
+
+
+def delete_meta_rules_without_id(client):
+ req = client.delete("/meta_rules/{}".format(""))
+ return req
+
+
+def test_get_meta_rules():
+ client = utilities.register_client()
+ req, meta_rules = get_meta_rules(client)
+ assert req.status_code == 200
+ assert isinstance(meta_rules, dict)
+ assert "meta_rules" in meta_rules
+
+
+def test_add_meta_rules():
+ client = utilities.register_client()
+ meta_rule_name = uuid4().hex
+ req, meta_rules = add_meta_rules(client, meta_rule_name)
+ assert req.status_code == 200
+ assert isinstance(meta_rules, dict)
+ value = list(meta_rules["meta_rules"].values())[0]
+ assert "meta_rules" in meta_rules
+ assert value['name'] == meta_rule_name
+
+
+def test_add_two_meta_rules_with_same_categories_combination():
+ client = utilities.register_client()
+ meta_rule_name = uuid4().hex
+ req, meta_rules = add_meta_rules(client, meta_rule_name)
+ assert req.status_code == 200
+ for meta_rule_id in meta_rules['meta_rules']:
+ if meta_rules['meta_rules'][meta_rule_id]['name'] == meta_rule_name:
+ data = meta_rules['meta_rules'][meta_rule_id]
+
+ data['name'] = uuid4().hex
+ req, meta_rules = add_meta_rules(client, name=data['name'], data=data)
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Meta Rule Existing'
+
+
+def test_add_three_meta_rules_with_different_combination_but_similar_items():
+ client = utilities.register_client()
+ meta_rule_name1 = uuid4().hex
+ req, meta_rules = add_meta_rules(client, meta_rule_name1)
+ assert req.status_code == 200
+ for meta_rule_id in meta_rules['meta_rules']:
+ if meta_rules['meta_rules'][meta_rule_id]['name'] == meta_rule_name1:
+ data = meta_rules['meta_rules'][meta_rule_id]
+ break
+
+ meta_rule_name2 = uuid4().hex
+
+ req, meta_rules = add_meta_rules(client, meta_rule_name2)
+
+ for meta_rule_id in meta_rules['meta_rules']:
+ if meta_rules['meta_rules'][meta_rule_id]['name'] == meta_rule_name2:
+ data['subject_categories'] += meta_rules['meta_rules'][meta_rule_id][
+ 'subject_categories']
+ data['object_categories'] += meta_rules['meta_rules'][meta_rule_id]['object_categories']
+ data['action_categories'] += meta_rules['meta_rules'][meta_rule_id]['action_categories']
+ break
+
+ data['name'] = uuid4().hex
+
+ req, meta_rules = add_meta_rules(client, name=data['name'], data=data)
+ assert req.status_code == 200
+
+
+def test_add_two_meta_rules_with_different_combination_but_similar_items():
+ client = utilities.register_client()
+ meta_rule_name1 = uuid4().hex
+ meta_rule_name2 = uuid4().hex
+
+ subject_category = category_helper.add_subject_category(
+ value={"name": "subject category name" + uuid4().hex, "description": "description 1"})
+ subject_category_id1 = list(subject_category.keys())[0]
+
+ object_category = category_helper.add_object_category(
+ value={"name": "object category name" + uuid4().hex, "description": "description 1"})
+ object_category_id1 = list(object_category.keys())[0]
+
+ action_category = category_helper.add_action_category(
+ value={"name": "action category name" + uuid4().hex, "description": "description 1"})
+ action_category_id1 = list(action_category.keys())[0]
+
+ subject_category = category_helper.add_subject_category(
+ value={"name": "subject category name" + uuid4().hex, "description": "description 1"})
+ subject_category_id2 = list(subject_category.keys())[0]
+
+ object_category = category_helper.add_object_category(
+ value={"name": "object category name" + uuid4().hex, "description": "description 1"})
+ object_category_id2 = list(object_category.keys())[0]
+
+ action_category = category_helper.add_action_category(
+ value={"name": "action category name" + uuid4().hex, "description": "description 1"})
+ action_category_id2 = list(action_category.keys())[0]
+
+ data = {
+ "name": meta_rule_name1,
+ "subject_categories": [subject_category_id1, subject_category_id2],
+ "object_categories": [object_category_id1, object_category_id2],
+ "action_categories": [action_category_id1, action_category_id2]
+ }
+ req, meta_rules = add_meta_rules(client, meta_rule_name1, data=data)
+ assert req.status_code == 200
+ data = {
+ "name": meta_rule_name2,
+ "subject_categories": [subject_category_id2],
+ "object_categories": [object_category_id1],
+ "action_categories": [action_category_id2]
+ }
+
+ req, meta_rules = add_meta_rules(client, meta_rule_name1, data=data)
+ assert req.status_code == 200
+
+
+def test_add_meta_rule_with_existing_name_error():
+ client = utilities.register_client()
+ name = uuid4().hex
+ req, meta_rules = add_meta_rules(client, name)
+ assert req.status_code == 200
+ req, meta_rules = add_meta_rules(client, name)
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Meta Rule Existing'
+
+
+def test_add_meta_rules_with_forbidden_char_in_name():
+ client = utilities.register_client()
+ req, meta_rules = add_meta_rules(client, "<a>")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_add_meta_rules_with_blank_name():
+ client = utilities.register_client()
+ req, meta_rules = add_meta_rules(client, "")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Meta Rule Error'
+
+
+def test_add_meta_rules_without_subject_categories():
+ client = utilities.register_client()
+ name_meta_rule = uuid4().hex
+ req, meta_rules = add_meta_rules_without_category_ids(client, name_meta_rule)
+ assert req.status_code == 200
+
+
+def test_delete_meta_rules():
+ client = utilities.register_client()
+ name_meta_rule = uuid4().hex
+ req, meta_rules = add_meta_rules_without_category_ids(client, name_meta_rule)
+ meta_rule_id = next(iter(meta_rules['meta_rules']))
+ req = delete_meta_rules(client, meta_rules['meta_rules'][meta_rule_id]['name'])
+ assert req.status_code == 200
+
+
+def test_delete_meta_rules_without_id():
+ client = utilities.register_client()
+ req = delete_meta_rules_without_id(client)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Meta Rule Unknown"
+
+
+def test_update_meta_rules():
+ client = utilities.register_client()
+ req = add_meta_rules(client, "testuser")
+ meta_rule_id = list(req[1]['meta_rules'])[0]
+ req_update = update_meta_rules(client, "testuser", meta_rule_id)
+ assert req_update[0].status_code == 200
+ delete_meta_rules(client, "testuser")
+ get_meta_rules(client)
+
+
+def test_update_meta_rule_with_combination_existed():
+ client = utilities.register_client()
+ meta_rule_name1 = uuid4().hex
+ req, meta_rules = add_meta_rules(client, meta_rule_name1)
+ meta_rule_id1 = next(iter(meta_rules['meta_rules']))
+ data1 = meta_rules['meta_rules'][meta_rule_id1]
+
+ meta_rule_name2 = uuid4().hex
+ req, meta_rules = add_meta_rules(client, meta_rule_name2)
+ meta_rule_id2 = next(iter(meta_rules['meta_rules']))
+ data2 = meta_rules['meta_rules'][meta_rule_id2]
+ data1['name'] = data2['name']
+ req_update = update_meta_rules(client, name=meta_rule_name2, metaRuleId=meta_rule_id2,
+ data=data1)
+ assert req_update[0].status_code == 409
+ assert req_update[1]['message']== '409: Meta Rule Existing'
+
+
+def test_update_meta_rule_with_different_combination_but_same_data():
+ client = utilities.register_client()
+ meta_rule_name1 = uuid4().hex
+ subject_category = category_helper.add_subject_category(
+ value={"name": "subject category name" + uuid4().hex, "description": "description 1"})
+ subject_category_id1 = list(subject_category.keys())[0]
+ object_category = category_helper.add_object_category(
+ value={"name": "object category name" + uuid4().hex, "description": "description 1"})
+ object_category_id1 = list(object_category.keys())[0]
+ action_category = category_helper.add_action_category(
+ value={"name": "action category name" + uuid4().hex, "description": "description 1"})
+ action_category_id1 = list(action_category.keys())[0]
+ subject_category = category_helper.add_subject_category(
+ value={"name": "subject category name" + uuid4().hex, "description": "description 1"})
+ subject_category_id2 = list(subject_category.keys())[0]
+ object_category = category_helper.add_object_category(
+ value={"name": "object category name" + uuid4().hex, "description": "description 1"})
+ object_category_id2 = list(object_category.keys())[0]
+ action_category = category_helper.add_action_category(
+ value={"name": "action category name" + uuid4().hex, "description": "description 1"})
+ action_category_id2 = list(action_category.keys())[0]
+
+ data = {
+ "name": meta_rule_name1,
+ "subject_categories": [subject_category_id1, subject_category_id2],
+ "object_categories": [object_category_id1, object_category_id2],
+ "action_categories": [action_category_id1, action_category_id2]
+ }
+ req, meta_rules = add_meta_rules(client, meta_rule_name1, data=data)
+ assert req.status_code == 200
+
+ meta_rule_name2 = uuid4().hex
+ req, meta_rules = add_meta_rules(client, meta_rule_name2)
+ meta_rule_id2 = next(iter(meta_rules['meta_rules']))
+ data2 = {
+ "name": meta_rule_name2,
+ "subject_categories": [subject_category_id1, subject_category_id2],
+ "object_categories": [object_category_id1],
+ "action_categories": [action_category_id1,action_category_id2]
+ }
+
+ req_update = update_meta_rules(client, name=meta_rule_name2, metaRuleId=meta_rule_id2,
+ data=data2)
+ assert req_update[0].status_code == 200
+
+
+def test_update_meta_rules_without_id():
+ client = utilities.register_client()
+ req_update = update_meta_rules(client, "testuser", "")
+ assert req_update[0].status_code == 400
+ assert json.loads(req_update[0].data)["message"] == "400: Meta Rule Unknown"
+
+
+def test_update_meta_rules_without_name():
+ client = utilities.register_client()
+ req_update = update_meta_rules(client, "<br/>", "1234567")
+ assert req_update[0].status_code == 400
+ assert json.loads(req_update[0].data)[
+ "message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_update_meta_rules_without_categories():
+ client = utilities.register_client()
+ req_update = update_meta_rules_with_categories(client, "testuser")
+ assert req_update[0].status_code == 200
+
+
+def test_update_meta_rules_with_empty_categories():
+ client = utilities.register_client()
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule()
+ data = {
+ "name": "testuser",
+ "subject_categories": [""],
+ "object_categories": [""],
+ "action_categories": [""]
+ }
+ req_update = update_meta_rules_with_categories(client, "testuser", data=data,
+ meta_rule_id=meta_rule_id)
+ assert req_update[0].status_code == 400
+ assert req_update[1]['message'] == '400: Subject Category Unknown'
+
+
+def test_update_meta_rules_with_empty_action_category():
+ client = utilities.register_client()
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule()
+ data = {
+ "name": "testuser",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [""]
+ }
+ req_update = update_meta_rules_with_categories(client, "testuser", data=data,
+ meta_rule_id=meta_rule_id)
+ assert req_update[0].status_code == 400
+ assert req_update[1]['message'] == '400: Action Category Unknown'
+
+
+def test_update_meta_rules_with_empty_object_category():
+ client = utilities.register_client()
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule()
+ data = {
+ "name": "testuser",
+ "subject_categories": [subject_category_id],
+ "object_categories": [""],
+ "action_categories": [action_category_id]
+ }
+ req_update = update_meta_rules_with_categories(client, "testuser", data=data,
+ meta_rule_id=meta_rule_id)
+ assert req_update[0].status_code == 400
+ assert req_update[1]['message'] == '400: Object Category Unknown'
+
+
+def test_update_meta_rules_with_categories_and_one_empty():
+ client = utilities.register_client()
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = data_builder.create_new_meta_rule()
+ data = {
+ "name": "testuser",
+ "subject_categories": [subject_category_id, ""],
+ "object_categories": [object_category_id, ""],
+ "action_categories": [action_category_id, ""]
+ }
+ req_update = update_meta_rules_with_categories(client, "testuser", data=data,
+ meta_rule_id=meta_rule_id)
+ assert req_update[0].status_code == 400
+ assert req_update[1]['message'] == '400: Subject Category Unknown'
diff --git a/old/moon_manager/tests/unit_python/api/test_pdp.py b/old/moon_manager/tests/unit_python/api/test_pdp.py
new file mode 100644
index 00000000..53a87b21
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/test_pdp.py
@@ -0,0 +1,164 @@
+import json
+import api.utilities as utilities
+from helpers import data_builder as builder
+from uuid import uuid4
+
+
+def get_pdp(client):
+ req = client.get("/pdp")
+ pdp = utilities.get_json(req.data)
+ return req, pdp
+
+
+def add_pdp(client, data):
+ req = client.post("/pdp", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ pdp = utilities.get_json(req.data)
+ return req, pdp
+
+
+def update_pdp(client, data, pdp_id):
+ req = client.patch("/pdp/{}".format(pdp_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ pdp = utilities.get_json(req.data)
+ return req, pdp
+
+
+def delete_pdp(client, key):
+ req = client.delete("/pdp/{}".format(key))
+ return req
+
+
+def delete_pdp_without_id(client):
+ req = client.delete("/pdp/{}".format(""))
+ return req
+
+
+def test_get_pdp():
+ client = utilities.register_client()
+ req, pdp = get_pdp(client)
+ assert req.status_code == 200
+ assert isinstance(pdp, dict)
+ assert "pdps" in pdp
+
+
+def test_add_pdp():
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex,
+ model_name="model1" + uuid4().hex)
+ data = {
+ "name": "testuser",
+ "security_pipeline": [policy_id],
+ "keystone_project_id": "keystone_project_id",
+ "description": "description of testuser"
+ }
+ client = utilities.register_client()
+ req, pdp = add_pdp(client, data)
+ assert req.status_code == 200
+ assert isinstance(pdp, dict)
+ value = list(pdp["pdps"].values())[0]
+ assert "pdps" in pdp
+ assert value['name'] == "testuser"
+ assert value["description"] == "description of {}".format("testuser")
+ assert value["keystone_project_id"] == "keystone_project_id"
+
+
+def test_delete_pdp():
+ client = utilities.register_client()
+ request, pdp = get_pdp(client)
+ success_req = None
+ for key, value in pdp['pdps'].items():
+ if value['name'] == "testuser":
+ success_req = delete_pdp(client, key)
+ break
+ assert success_req
+ assert success_req.status_code == 200
+
+
+def test_add_pdp_with_forbidden_char_in_user():
+ data = {
+ "name": "<a>",
+ "security_pipeline": ["policy_id_1", "policy_id_2"],
+ "keystone_project_id": "keystone_project_id",
+ "description": "description of testuser"
+ }
+ client = utilities.register_client()
+ req, models = add_pdp(client, data)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_add_pdp_with_forbidden_char_in_keystone():
+ data = {
+ "name": "testuser",
+ "security_pipeline": ["policy_id_1", "policy_id_2"],
+ "keystone_project_id": "<a>",
+ "description": "description of testuser"
+ }
+ client = utilities.register_client()
+ req, meta_rules = add_pdp(client, data)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'keystone_project_id', [Forbidden characters in string]"
+
+
+def test_update_pdp():
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy(
+ subject_category_name="subject_category1"+uuid4().hex,
+ object_category_name="object_category1"+uuid4().hex,
+ action_category_name="action_category1"+uuid4().hex,
+ meta_rule_name="meta_rule_1"+uuid4().hex,
+ model_name="model1"+uuid4().hex)
+ data_add = {
+ "name": "testuser",
+ "security_pipeline": [policy_id],
+ "keystone_project_id": "keystone_project_id",
+ "description": "description of testuser"
+ }
+
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id_update = builder.create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex,
+ model_name="model1" + uuid4().hex)
+ data_update = {
+ "name": "testuser",
+ "security_pipeline": [policy_id_update],
+ "keystone_project_id": "keystone_project_id_update",
+ "description": "description of testuser"
+ }
+ client = utilities.register_client()
+ req = add_pdp(client, data_add)
+ pdp_id = list(req[1]['pdps'])[0]
+ req_update = update_pdp(client, data_update, pdp_id)
+ assert req_update[0].status_code == 200
+ value = list(req_update[1]["pdps"].values())[0]
+ assert value["keystone_project_id"] == "keystone_project_id_update"
+ request, pdp = get_pdp(client)
+ for key, value in pdp['pdps'].items():
+ if value['name'] == "testuser":
+ delete_pdp(client, key)
+ break
+
+
+def test_update_pdp_without_id():
+ client = utilities.register_client()
+ req_update = update_pdp(client, "testuser", "")
+ assert req_update[0].status_code == 400
+ assert json.loads(req_update[0].data)["message"] == 'Invalid Key :name not found'
+
+
+def test_update_pdp_without_user():
+ data = {
+ "name": "",
+ "security_pipeline": ["policy_id_1", "policy_id_2"],
+ "keystone_project_id": "keystone_project_id",
+ "description": "description of testuser"
+ }
+ client = utilities.register_client()
+ req_update = update_pdp(client, data, "<a>")
+ assert req_update[0].status_code == 400
+ assert json.loads(req_update[0].data)["message"] == "Forbidden characters in string"
diff --git a/old/moon_manager/tests/unit_python/api/test_perimeter.py b/old/moon_manager/tests/unit_python/api/test_perimeter.py
new file mode 100644
index 00000000..ff7b09d7
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/test_perimeter.py
@@ -0,0 +1,1028 @@
+# import moon_manager
+# import moon_manager.api
+import json
+import api.utilities as utilities
+from helpers import data_builder as builder
+import helpers.policy_helper as policy_helper
+from uuid import uuid4
+
+
+def get_subjects(client):
+ req = client.get("/subjects")
+ subjects = utilities.get_json(req.data)
+ return req, subjects
+
+
+def add_subjects(client, policy_id, name, perimeter_id=None, data=None):
+ if not data:
+ name = name + uuid4().hex
+ data = {
+ "name": name,
+ "description": "description of {}".format(name),
+ "password": "password for {}".format(name),
+ "email": "{}@moon".format(name)
+ }
+ if not perimeter_id:
+ req = client.post("/policies/{}/subjects".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ else:
+ req = client.post("/policies/{}/subjects/{}".format(policy_id, perimeter_id),
+ data=json.dumps(
+ data),
+ headers={'Content-Type': 'application/json'})
+ subjects = utilities.get_json(req.data)
+ return req, subjects
+
+
+def delete_subjects_without_perimeter_id(client):
+ req = client.delete("/subjects/{}".format(""))
+ return req
+
+
+def test_perimeter_get_subject():
+ client = utilities.register_client()
+ req, subjects = get_subjects(client)
+ assert req.status_code == 200
+ assert isinstance(subjects, dict)
+ assert "subjects" in subjects
+
+
+def test_perimeter_add_subject():
+ client = utilities.register_client()
+ policies = policy_helper.add_policies()
+ policy_id = list(policies.keys())[0]
+
+ req, subjects = add_subjects(client, policy_id, "testuser")
+ value = list(subjects["subjects"].values())[0]
+ assert req.status_code == 200
+ assert value["name"]
+ assert value["email"]
+
+
+def test_perimeter_add_same_subject_perimeter_id_with_new_policy_id():
+ client = utilities.register_client()
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ name = "testuser"
+ perimeter_id = uuid4().hex
+ data = {
+ "name": name + uuid4().hex,
+ "description": "description of {}".format(name),
+ "password": "password for {}".format(name),
+ "email": "{}@moon".format(name)
+ }
+ add_subjects(client, policy_id1, data['name'], perimeter_id=perimeter_id, data=data)
+ policies2 = policy_helper.add_policies()
+ policy_id2 = list(policies2.keys())[0]
+ req, subjects = add_subjects(client, policy_id2, data['name'],
+ perimeter_id=perimeter_id, data=data)
+ value = list(subjects["subjects"].values())[0]
+ assert req.status_code == 200
+ assert value["name"]
+ assert value["email"]
+ assert len(value['policy_list']) == 2
+ assert policy_id1 in value['policy_list']
+ assert policy_id2 in value['policy_list']
+
+
+def test_perimeter_add_same_subject_perimeter_id_with_different_name():
+ client = utilities.register_client()
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ perimeter_id = uuid4().hex
+ add_subjects(client, policy_id1, "testuser", perimeter_id=perimeter_id)
+ policies2 = policy_helper.add_policies()
+ policy_id2 = list(policies2.keys())[0]
+ req, subjects = add_subjects(client, policy_id2, "testuser", perimeter_id=perimeter_id)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Perimeter content is invalid.'
+
+
+def test_perimeter_add_same_subject_name_with_new_policy_id():
+ client = utilities.register_client()
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ perimeter_id = uuid4().hex
+ name = "testuser" + uuid4().hex
+ data = {
+ "name": name,
+ "description": "description of {}".format(name),
+ "password": "password for {}".format(name),
+ "email": "{}@moon".format(name)
+ }
+ req, subjects = add_subjects(client, policy_id1, None, perimeter_id=perimeter_id,
+ data=data)
+ policies2 = policy_helper.add_policies()
+ policy_id2 = list(policies2.keys())[0]
+ value = list(subjects["subjects"].values())[0]
+ data = {
+ "name": value['name'],
+ "description": "description of {}".format(value['name']),
+ "password": "password for {}".format(value['name']),
+ "email": "{}@moon".format(value['name'])
+ }
+ req, subjects = add_subjects(client, policy_id2, None, data=data)
+ value = list(subjects["subjects"].values())[0]
+ assert req.status_code == 200
+ assert value["name"]
+ assert value["email"]
+ assert len(value['policy_list']) == 2
+ assert policy_id1 in value['policy_list']
+ assert policy_id2 in value['policy_list']
+
+
+def test_perimeter_add_same_subject_name_with_same_policy_id():
+ client = utilities.register_client()
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ perimeter_id = uuid4().hex
+ name = "testuser" + uuid4().hex
+ data = {
+ "name": name,
+ "description": "description of {}".format(name),
+ "password": "password for {}".format(name),
+ "email": "{}@moon".format(name)
+ }
+ req, subjects = add_subjects(client, policy_id1, None, perimeter_id=perimeter_id,
+ data=data)
+ value = list(subjects["subjects"].values())[0]
+ data = {
+ "name": value['name'],
+ "description": "description of {}".format(value['name']),
+ "password": "password for {}".format(value['name']),
+ "email": "{}@moon".format(value['name'])
+ }
+ req, subjects = add_subjects(client, policy_id1, None, data=data)
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Policy Already Exists'
+
+
+def test_perimeter_add_same_subject_perimeter_id_with_existed_policy_id_in_list():
+ client = utilities.register_client()
+ policies = policy_helper.add_policies()
+ policy_id = list(policies.keys())[0]
+ name = "testuser" + uuid4().hex
+ data = {
+ "name": name,
+ "description": "description of {}".format(name),
+ "password": "password for {}".format(name),
+ "email": "{}@moon".format(name)
+ }
+ req, subjects = add_subjects(client, policy_id, name, data=data)
+ perimeter_id = list(subjects["subjects"].values())[0]['id']
+ req, subjects = add_subjects(client, policy_id, name, perimeter_id=perimeter_id, data=data)
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Policy Already Exists'
+
+
+def test_perimeter_add_subject_invalid_policy_id():
+ client = utilities.register_client()
+ policies = policy_helper.add_policies()
+ policy_id = list(policies.keys())[0]
+ name = "testuser"
+ data = {
+ "name": name + uuid4().hex,
+ "description": "description of {}".format(name),
+ "password": "password for {}".format(name),
+ "email": "{}@moon".format(name)
+ }
+ req, subjects = add_subjects(client, policy_id + "0", "testuser", data)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Policy Unknown'
+
+
+def test_perimeter_add_subject_policy_id_none():
+ client = utilities.register_client()
+ name = "testuser"
+ data = {
+ "name": name + uuid4().hex,
+ "description": "description of {}".format(name),
+ "password": "password for {}".format(name),
+ "email": "{}@moon".format(name)
+ }
+ req, subjects = add_subjects(client, None, "testuser", data)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Policy Unknown'
+
+
+def test_perimeter_add_subject_with_forbidden_char_in_name():
+ client = utilities.register_client()
+ data = {
+ "name": "<a>",
+ "description": "description of {}".format(""),
+ "password": "password for {}".format(""),
+ "email": "{}@moon".format("")
+ }
+ req = client.post("/policies/{}/subjects".format("111"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_perimeter_update_subject_name():
+ client = utilities.register_client()
+ policies = policy_helper.add_policies()
+ policy_id = list(policies.keys())[0]
+ req, subjects = add_subjects(client, policy_id, "testuser")
+ value1 = list(subjects["subjects"].values())[0]
+ perimeter_id = value1['id']
+ data = {
+ 'name': value1['name'] + "update"
+ }
+ req = client.patch("/subjects/{}".format(perimeter_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ subjects = utilities.get_json(req.data)
+ value2 = list(subjects["subjects"].values())[0]
+ assert req.status_code == 200
+ assert value1['name'] + 'update' == value2['name']
+ assert value1['id'] == value2['id']
+ assert value1['description'] == value2['description']
+
+
+def test_perimeter_update_subject_description():
+ client = utilities.register_client()
+ policies = policy_helper.add_policies()
+ policy_id = list(policies.keys())[0]
+ req, subjects = add_subjects(client, policy_id, "testuser")
+ value1 = list(subjects["subjects"].values())[0]
+ perimeter_id = value1['id']
+ data = {
+ 'description': value1['description'] + "update",
+ }
+ req = client.patch("/subjects/{}".format(perimeter_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ subjects = utilities.get_json(req.data)
+ value2 = list(subjects["subjects"].values())[0]
+ assert req.status_code == 200
+ assert value1['name'] == value2['name']
+ assert value1['id'] == value2['id']
+ assert value1['description'] + 'update' == value2['description']
+
+
+def test_perimeter_update_subject_description_and_name():
+ client = utilities.register_client()
+ policies = policy_helper.add_policies()
+ policy_id = list(policies.keys())[0]
+
+ req, subjects = add_subjects(client, policy_id, "testuser")
+ value1 = list(subjects["subjects"].values())[0]
+ perimeter_id = value1['id']
+ data = {
+ 'description': value1['description'] + "update",
+ 'name': value1['name'] + "update"
+ }
+ req = client.patch("/subjects/{}".format(perimeter_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ subjects = utilities.get_json(req.data)
+ value2 = list(subjects["subjects"].values())[0]
+ assert req.status_code == 200
+ assert value1['name'] + 'update' == value2['name']
+ assert value1['id'] == value2['id']
+ assert value1['description'] + 'update' == value2['description']
+
+
+def test_perimeter_update_subject_wrong_id():
+ client = utilities.register_client()
+ name = 'testuser' + uuid4().hex
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ data = {
+ "name": name,
+ "description": "description of {}".format('testuser'),
+ }
+ req, subjects = add_subjects(client, policy_id=policy_id1, name='testuser', data=data)
+ value1 = list(subjects["subjects"].values())[0]
+ perimeter_id = value1['id']
+ data = {
+ 'name': value1['name'] + "update",
+ 'description': value1['description'] + "update"
+ }
+ req = client.patch("/subjects/{}".format(perimeter_id + "wrong"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Perimeter content is invalid.'
+
+
+def test_perimeter_update_subject_name_with_existed_one():
+ client = utilities.register_client()
+ name1 = 'testuser' + uuid4().hex
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ perimeter_id1 = uuid4().hex
+ req, subjects = add_subjects(client, policy_id=policy_id1, name=name1,
+ perimeter_id=perimeter_id1)
+ value1 = list(subjects["subjects"].values())[0]
+ perimeter_id2 = uuid4().hex
+ name2 = 'testuser' + uuid4().hex
+ req, subjects = add_subjects(client, policy_id=policy_id1, name=name2,
+ perimeter_id=perimeter_id2)
+ data = {
+ 'name': value1['name'],
+ }
+ req = client.patch("/subjects/{}".format(perimeter_id2), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 409
+
+
+def test_perimeter_delete_subject():
+ client = utilities.register_client()
+ policies = policy_helper.add_policies()
+ policy_id = list(policies.keys())[0]
+ req, subjects = add_subjects(client, policy_id, "testuser")
+ subject_id = list(subjects["subjects"].values())[0]["id"]
+ req = client.delete("/policies/{}/subjects/{}".format(policy_id, subject_id))
+ assert req.status_code == 200
+
+
+def test_perimeter_delete_subjects_without_perimeter_id():
+ client = utilities.register_client()
+ req = delete_subjects_without_perimeter_id(client)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Subject Unknown"
+
+
+def get_objects(client):
+ req = client.get("/objects")
+ objects = utilities.get_json(req.data)
+ return req, objects
+
+
+def add_objects(client, name, policyId=None, data=None, perimeter_id=None):
+ if not policyId:
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policyId = builder.create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex,
+ model_name="model1" + uuid4().hex)
+ if not data:
+ data = {
+ "name": name + uuid4().hex,
+ "description": "description of {}".format(name),
+ }
+ if not perimeter_id:
+ req = client.post("/policies/{}/objects/".format(policyId), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ else:
+ req = client.post("/policies/{}/objects/{}".format(policyId, perimeter_id),
+ data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ objects = utilities.get_json(req.data)
+ return req, objects
+
+
+def delete_objects_without_perimeter_id(client):
+ req = client.delete("/objects/{}".format(""))
+ return req
+
+
+def test_perimeter_get_object():
+ client = utilities.register_client()
+ req, objects = get_objects(client)
+ assert req.status_code == 200
+ assert isinstance(objects, dict)
+ assert "objects" in objects
+
+
+def test_perimeter_add_object():
+ client = utilities.register_client()
+ req, objects = add_objects(client, "testuser")
+ value = list(objects["objects"].values())[0]
+ assert req.status_code == 200
+ assert value['name']
+
+
+def test_perimeter_add_object_with_wrong_policy_id():
+ client = utilities.register_client()
+ req, objects = add_objects(client, "testuser", policyId='wrong')
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Policy Unknown'
+
+
+def test_perimeter_add_object_with_policy_id_none():
+ client = utilities.register_client()
+ data = {
+ "name": "testuser" + uuid4().hex,
+ "description": "description of {}".format("testuser"),
+ }
+ req = client.post("/policies/{}/objects/".format(None), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Policy Unknown'
+
+
+def test_perimeter_add_same_object_name_with_new_policy_id():
+ client = utilities.register_client()
+ req, objects = add_objects(client, "testuser")
+ value1 = list(objects["objects"].values())[0]
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ data = {
+ "name": value1['name'],
+ "description": "description of {}".format('testuser'),
+ }
+ req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data)
+ value2 = list(objects["objects"].values())[0]
+ assert req.status_code == 200
+ assert value1['id'] == value2['id']
+ assert value1['name'] == value2['name']
+
+
+def test_perimeter_add_same_object_perimeter_id_with_new_policy_id():
+ client = utilities.register_client()
+ req, objects = add_objects(client, "testuser")
+ value1 = list(objects["objects"].values())[0]
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ data = {
+ "name": value1['name'],
+ "description": "description of {}".format('testuser'),
+ }
+ req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data,
+ perimeter_id=value1['id'])
+ value2 = list(objects["objects"].values())[0]
+ assert req.status_code == 200
+ assert value1['id'] == value2['id']
+ assert value1['name'] == value2['name']
+
+
+def test_perimeter_add_same_object_perimeter_id_with_different_name():
+ client = utilities.register_client()
+ req, objects = add_objects(client, "testuser")
+ value1 = list(objects["objects"].values())[0]
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ data = {
+ "name": value1['name'] + 'different',
+ "description": "description of {}".format('testuser'),
+ }
+ req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data,
+ perimeter_id=value1['id'])
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Perimeter content is invalid.'
+
+
+def test_perimeter_add_same_object_name_with_same_policy_id():
+ client = utilities.register_client()
+ name = 'testuser' + uuid4().hex
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ data = {
+ "name": name,
+ "description": "description of {}".format('testuser'),
+ }
+ req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data)
+ value = list(objects["objects"].values())[0]
+ assert req.status_code == 200
+ req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data)
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Policy Already Exists'
+
+
+def test_perimeter_add_same_object_perimeter_id_with_existed_policy_id_in_list():
+ client = utilities.register_client()
+ name = 'testuser' + uuid4().hex
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ data = {
+ "name": name,
+ "description": "description of {}".format('testuser'),
+ }
+ req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data)
+ value = list(objects["objects"].values())[0]
+ req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data,
+ perimeter_id=value['id'])
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Policy Already Exists'
+
+
+def test_perimeter_update_object_name():
+ client = utilities.register_client()
+ name = 'testuser' + uuid4().hex
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ data = {
+ "name": name,
+ "description": "description of {}".format('testuser'),
+ }
+ req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data)
+
+ value1 = list(objects["objects"].values())[0]
+ perimeter_id = value1['id']
+ data = {
+ 'name': value1['name'] + "update"
+ }
+ req = client.patch("/objects/{}".format(perimeter_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+
+ objects = utilities.get_json(req.data)
+ value2 = list(objects["objects"].values())[0]
+ assert req.status_code == 200
+ assert value1['name'] + 'update' == value2['name']
+ assert value1['id'] == value2['id']
+ assert value1['description'] == value2['description']
+
+
+def test_perimeter_update_object_description():
+ client = utilities.register_client()
+ name = 'testuser' + uuid4().hex
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ data = {
+ "name": name,
+ "description": "description of {}".format('testuser'),
+ }
+ req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data)
+
+ value1 = list(objects["objects"].values())[0]
+ perimeter_id = value1['id']
+ data = {
+ 'description': value1['description'] + "update"
+ }
+ req = client.patch("/objects/{}".format(perimeter_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+
+ objects = utilities.get_json(req.data)
+ value2 = list(objects["objects"].values())[0]
+ assert req.status_code == 200
+ assert value1['name'] == value2['name']
+ assert value1['id'] == value2['id']
+ assert value1['description'] + 'update' == value2['description']
+
+
+def test_perimeter_update_object_description_and_name():
+ client = utilities.register_client()
+ name = 'testuser' + uuid4().hex
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ data = {
+ "name": name,
+ "description": "description of {}".format('testuser'),
+ }
+ req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data)
+
+ value1 = list(objects["objects"].values())[0]
+ perimeter_id = value1['id']
+ data = {
+ 'name': value1['name'] + "update",
+ 'description': value1['description'] + "update"
+ }
+ req = client.patch("/objects/{}".format(perimeter_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+
+ objects = utilities.get_json(req.data)
+ value2 = list(objects["objects"].values())[0]
+ assert req.status_code == 200
+ assert value1['name'] + 'update' == value2['name']
+ assert value1['id'] == value2['id']
+ assert value1['description'] + 'update' == value2['description']
+
+
+def test_perimeter_update_object_wrong_id():
+ client = utilities.register_client()
+ name = 'testuser' + uuid4().hex
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ data = {
+ "name": name,
+ "description": "description of {}".format('testuser'),
+ }
+ req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data)
+
+ value1 = list(objects["objects"].values())[0]
+ perimeter_id = value1['id']
+ data = {
+ 'name': value1['name'] + "update",
+ 'description': value1['description'] + "update"
+ }
+ req = client.patch("/objects/{}".format(perimeter_id + "wrong"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+
+
+def test_perimeter_update_object_name_with_existed_one():
+ client = utilities.register_client()
+ name = 'testuser' + uuid4().hex
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ data1 = {
+ "name": name,
+ "description": "description of {}".format('testuser'),
+ }
+ req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data1)
+ value1 = list(objects["objects"].values())[0]
+
+ name = 'testuser' + uuid4().hex
+
+ data2 = {
+ "name": name,
+ "description": "description of {}".format('testuser'),
+ }
+ req, objects = add_objects(client, 'testuser', policyId=policy_id1, data=data2)
+
+ value2 = list(objects["objects"].values())[0]
+ perimeter_id2 = value2['id']
+
+ data3 = {
+ 'name': value1['name']
+ }
+ req = client.patch("/objects/{}".format(perimeter_id2), data=json.dumps(data3),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Object Existing'
+
+
+def test_perimeter_add_object_without_name():
+ client = utilities.register_client()
+ data = {
+ "name": "<br/>",
+ "description": "description of {}".format(""),
+ }
+ req = client.post("/policies/{}/objects/".format("111"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_perimeter_add_object_with_name_contain_spaces():
+ client = utilities.register_client()
+ data = {
+ "name": "test<a>user",
+ "description": "description of {}".format("test user"),
+ }
+ req = client.post("/policies/{}/objects/".format("111"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_perimeter_delete_object():
+ client = utilities.register_client()
+ policies = policy_helper.add_policies()
+ policy_id = list(policies.keys())[0]
+ object_id = builder.create_object(policy_id)
+ req = client.delete("/policies/{}/objects/{}".format(policy_id, object_id))
+ assert req.status_code == 200
+
+
+def test_perimeter_delete_objects_without_perimeter_id():
+ client = utilities.register_client()
+ req = delete_objects_without_perimeter_id(client)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Object Unknown"
+
+
+def get_actions(client):
+ req = client.get("/actions")
+ actions = utilities.get_json(req.data)
+ return req, actions
+
+
+def add_actions(client, name, policy_id=None, data=None, perimeter_id=None):
+ if not policy_id:
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex,
+ model_name="model1" + uuid4().hex)
+
+ if not data:
+ data = {
+ "name": name + uuid4().hex,
+ "description": "description of {}".format(name),
+ }
+ if not perimeter_id:
+ req = client.post("/policies/{}/actions/".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ else:
+ req = client.post("/policies/{}/actions/{}".format(policy_id, perimeter_id),
+ data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+
+ actions = utilities.get_json(req.data)
+ return req, actions
+
+
+def delete_actions_without_perimeter_id(client):
+ req = client.delete("/actions/{}".format(""))
+ return req
+
+
+def test_perimeter_get_actions():
+ client = utilities.register_client()
+ req, actions = get_actions(client)
+ assert req.status_code == 200
+ assert isinstance(actions, dict)
+ assert "actions" in actions
+
+
+def test_perimeter_add_actions():
+ client = utilities.register_client()
+ req, actions = add_actions(client, "testuser")
+ value = list(actions["actions"].values())[0]
+ assert req.status_code == 200
+ assert value['name']
+
+
+def test_perimeter_add_action_with_wrong_policy_id():
+ client = utilities.register_client()
+ req, actions = add_actions(client, "testuser", policy_id="wrong")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Policy Unknown'
+
+
+def test_perimeter_add_action_with_policy_id_none():
+ client = utilities.register_client()
+ data = {
+ "name": "testuser" + uuid4().hex,
+ "description": "description of {}".format("testuser"),
+ }
+ req = client.post("/policies/{}/actions/".format(None), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Policy Unknown'
+
+
+def test_perimeter_add_same_action_name_with_new_policy_id():
+ client = utilities.register_client()
+ req, action = add_actions(client, "testuser")
+ value1 = list(action["actions"].values())[0]
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ data = {
+ "name": value1['name'],
+ "description": "description of {}".format('testuser'),
+ }
+ req, action = add_actions(client, 'testuser', policy_id=policy_id1, data=data)
+ value2 = list(action["actions"].values())[0]
+ assert req.status_code == 200
+ assert value1['id'] == value2['id']
+ assert value1['name'] == value2['name']
+
+
+def test_perimeter_add_same_action_perimeter_id_with_new_policy_id():
+ client = utilities.register_client()
+ req, action = add_actions(client, "testuser")
+ value1 = list(action["actions"].values())[0]
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ data = {
+ "name": value1['name'],
+ "description": "description of {}".format('testuser'),
+ }
+ req, action = add_actions(client, 'testuser', policy_id=policy_id1, data=data,
+ perimeter_id=value1['id'])
+ value2 = list(action["actions"].values())[0]
+ assert req.status_code == 200
+ assert value1['id'] == value2['id']
+ assert value1['name'] == value2['name']
+
+
+def test_perimeter_add_same_action_perimeter_id_with_different_name():
+ client = utilities.register_client()
+ req, action = add_actions(client, "testuser")
+ value1 = list(action["actions"].values())[0]
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ data = {
+ "name": value1['name'] + 'different',
+ "description": "description of {}".format('testuser'),
+ }
+ req, action = add_actions(client, 'testuser', policy_id=policy_id1, data=data,
+ perimeter_id=value1['id'])
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Perimeter content is invalid.'
+
+
+def test_perimeter_add_same_action_name_with_same_policy_id():
+ client = utilities.register_client()
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ req, action = add_actions(client, "testuser", policy_id=policy_id1)
+ value1 = list(action["actions"].values())[0]
+ data = {
+ "name": value1['name'],
+ "description": "description of {}".format('testuser'),
+ }
+ req, action = add_actions(client, 'testuser', policy_id=policy_id1, data=data)
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Policy Already Exists'
+
+
+def test_perimeter_add_same_action_perimeter_id_with_existed_policy_id_in_list():
+ client = utilities.register_client()
+ policies1 = policy_helper.add_policies()
+ policy_id1 = list(policies1.keys())[0]
+ req, action = add_actions(client, "testuser", policy_id=policy_id1)
+ value1 = list(action["actions"].values())[0]
+ data = {
+ "name": value1['name'],
+ "description": "description of {}".format('testuser'),
+ }
+ req, action = add_actions(client, 'testuser', policy_id=policy_id1, data=data,
+ perimeter_id=value1['id'])
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Policy Already Exists'
+
+
+def test_perimeter_add_actions_without_name():
+ client = utilities.register_client()
+ data = {
+ "name": "<a>",
+ "description": "description of {}".format(""),
+ }
+ req = client.post("/policies/{}/actions".format("111"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_perimeter_add_actions_with_name_contain_spaces():
+ client = utilities.register_client()
+ data = {
+ "name": "test<a>user",
+ "description": "description of {}".format("test user"),
+ }
+ req = client.post("/policies/{}/actions".format("111"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_add_subjects_without_policy_id():
+ client = utilities.register_client()
+ data = {
+ "name": "testuser",
+ "description": "description of {}".format("test user"),
+ }
+ req = client.post("/policies/{}/subjects".format("111"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Policy Unknown"
+
+
+def test_add_objects_without_policy_id():
+ client = utilities.register_client()
+ data = {
+ "name": "testuser",
+ "description": "description of {}".format("test user"),
+ }
+ req = client.post("/policies/{}/objects".format("111"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Policy Unknown"
+
+
+def test_add_action_without_policy_id():
+ client = utilities.register_client()
+ data = {
+ "name": "testuser",
+ "description": "description of {}".format("test user"),
+ }
+ req = client.post("/policies/{}/actions".format("111"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Policy Unknown"
+
+
+def test_perimeter_update_action_name():
+ client = utilities.register_client()
+ req, actions = add_actions(client, "testuser")
+ value1 = list(actions["actions"].values())[0]
+ perimeter_id = value1['id']
+ data = {
+ 'name': value1['name'] + "update"
+ }
+ req = client.patch("/actions/{}".format(perimeter_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ subjects = utilities.get_json(req.data)
+ value2 = list(subjects["actions"].values())[0]
+ assert req.status_code == 200
+ assert value1['name'] + 'update' == value2['name']
+ assert value1['id'] == value2['id']
+ assert value1['description'] == value2['description']
+
+
+def test_perimeter_update_actions_description():
+ client = utilities.register_client()
+ req, actions = add_actions(client, "testuser")
+ value1 = list(actions["actions"].values())[0]
+ perimeter_id = value1['id']
+ data = {
+ 'description': value1['description'] + "update"
+ }
+ req = client.patch("/actions/{}".format(perimeter_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ subjects = utilities.get_json(req.data)
+ value2 = list(subjects["actions"].values())[0]
+ assert req.status_code == 200
+ assert value1['name'] == value2['name']
+ assert value1['id'] == value2['id']
+ assert value1['description'] + 'update' == value2['description']
+
+
+def test_perimeter_update_actions_description_and_name():
+ client = utilities.register_client()
+ req, actions = add_actions(client, "testuser")
+ value1 = list(actions["actions"].values())[0]
+ perimeter_id = value1['id']
+ data = {
+ 'name': value1['name'] + "update",
+ 'description': value1['description'] + "update"
+ }
+ req = client.patch("/actions/{}".format(perimeter_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ subjects = utilities.get_json(req.data)
+ value2 = list(subjects["actions"].values())[0]
+ assert req.status_code == 200
+ assert value1['name'] + 'update' == value2['name']
+ assert value1['id'] == value2['id']
+ assert value1['description'] + 'update' == value2['description']
+
+
+def test_perimeter_update_action_wrong_id():
+ client = utilities.register_client()
+ req, actions = add_actions(client, "testuser")
+ value1 = list(actions["actions"].values())[0]
+ perimeter_id = value1['id']
+ data = {
+ 'name': value1['name'] + "update",
+ 'description': value1['description'] + "update"
+ }
+ req = client.patch("/actions/{}".format(perimeter_id + "wrong"), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Perimeter content is invalid.'
+
+
+def test_perimeter_update_action_name_with_existed_one():
+ client = utilities.register_client()
+ req, actions = add_actions(client, "testuser")
+ value1 = list(actions["actions"].values())[0]
+ req, actions = add_actions(client, "testuser")
+ value2 = list(actions["actions"].values())[0]
+ perimeter_id2 = value2['id']
+ data = {
+ 'name': value1['name'],
+ }
+ req = client.patch("/actions/{}".format(perimeter_id2), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Action Existing'
+
+
+def test_perimeter_delete_actions():
+ client = utilities.register_client()
+
+ policies = policy_helper.add_policies()
+ policy_id = list(policies.keys())[0]
+ action_id = builder.create_action(policy_id)
+ req = client.delete("/policies/{}/actions/{}".format(policy_id, action_id))
+ assert req.status_code == 200
+
+
+def test_delete_subject_without_policy():
+ client = utilities.register_client()
+
+ policies = policy_helper.add_policies()
+ policy_id = list(policies.keys())[0]
+
+ action_id = builder.create_action(policy_id)
+
+ req = client.delete("/subjects/{}".format(action_id))
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Policy Unknown"
+
+
+def test_delete_objects_without_policy():
+ client = utilities.register_client()
+
+ policies = policy_helper.add_policies()
+ policy_id = list(policies.keys())[0]
+
+ action_id = builder.create_action(policy_id)
+
+ req = client.delete("/objects/{}".format(action_id))
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Policy Unknown"
+
+
+def test_delete_actions_without_policy():
+ client = utilities.register_client()
+
+ policies = policy_helper.add_policies()
+ policy_id = list(policies.keys())[0]
+
+ action_id = builder.create_action(policy_id)
+
+ req = client.delete("/actions/{}".format(action_id))
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Policy Unknown"
+
+
+def test_perimeter_delete_actions_without_perimeter_id():
+ client = utilities.register_client()
+ req = delete_actions_without_perimeter_id(client)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Action Unknown"
diff --git a/old/moon_manager/tests/unit_python/api/test_policies.py b/old/moon_manager/tests/unit_python/api/test_policies.py
new file mode 100644
index 00000000..76161d53
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/test_policies.py
@@ -0,0 +1,342 @@
+# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import json
+from uuid import uuid4
+import api.utilities as utilities
+from helpers import model_helper
+from helpers import policy_helper
+from helpers import data_builder
+
+
+def get_policies(client):
+ req = client.get("/policies")
+ policies = utilities.get_json(req.data)
+ return req, policies
+
+
+def add_policies(client, name):
+ req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex)
+ model_id = list(req.keys())[0]
+ data = {
+ "name": name,
+ "description": "description of {}".format(name),
+ "model_id": model_id,
+ "genre": "genre"
+ }
+ req = client.post("/policies", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ policies = utilities.get_json(req.data)
+ return req, policies
+
+
+def delete_policies_without_id(client):
+ req = client.delete("/policies/{}".format(""))
+ return req
+
+
+def test_get_policies():
+ client = utilities.register_client()
+ req, policies = get_policies(client)
+ assert req.status_code == 200
+ assert isinstance(policies, dict)
+ assert "policies" in policies
+
+
+def test_add_policies():
+ policy_name = "testuser" + uuid4().hex
+ client = utilities.register_client()
+ req, policies = add_policies(client, policy_name)
+ assert req.status_code == 200
+ assert isinstance(policies, dict)
+ value = list(policies["policies"].values())[0]
+ assert "policies" in policies
+ assert value['name'] == policy_name
+ assert value["description"] == "description of {}".format(policy_name)
+
+
+def test_add_policies_without_model():
+ policy_name = "testuser" + uuid4().hex
+ client = utilities.register_client()
+ data = {
+ "name": policy_name,
+ "description": "description of {}".format(policy_name),
+ "model_id": "",
+ "genre": "genre"
+ }
+ req = client.post("/policies/", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+
+ assert req.status_code == 200
+
+
+def test_add_policies_with_same_name():
+ name = uuid4().hex
+ policy_name = name
+ client = utilities.register_client()
+ req, policies = add_policies(client, policy_name)
+ assert req.status_code == 200
+ assert isinstance(policies, dict)
+ value = list(policies["policies"].values())[0]
+ assert "policies" in policies
+ assert value['name'] == policy_name
+ assert value["description"] == "description of {}".format(policy_name)
+ client = utilities.register_client()
+ req, policies = add_policies(client, policy_name)
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Policy Already Exists'
+
+
+def test_add_policy_with_empty_name():
+ policy_name = ""
+ client = utilities.register_client()
+ req, policies = add_policies(client, policy_name)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Policy Content Error'
+
+
+def test_update_policies_with_model():
+ policy_name = "testuser" + uuid4().hex
+ client = utilities.register_client()
+ data = {
+ "name": policy_name,
+ "description": "description of {}".format(policy_name),
+ "model_id": "",
+ "genre": "genre"
+ }
+ req = client.post("/policies/", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ policy_id = next(iter(utilities.get_json(req.data)['policies']))
+ req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex)
+ model_id = list(req.keys())[0]
+ data = {
+ "name": policy_name + "-2",
+ "description": "description of {}".format(policy_name),
+ "model_id": model_id,
+ "genre": "genre"
+ }
+ req = client.patch("/policies/{}".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 200
+ assert json.loads(req.data)['policies'][policy_id]['name'] == policy_name + '-2'
+
+
+def test_update_policies_name_success():
+ policy_name = "testuser" + uuid4().hex
+ client = utilities.register_client()
+ req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex)
+ model_id = list(req.keys())[0]
+ data = {
+ "name": policy_name,
+ "description": "description of {}".format(policy_name),
+ "model_id": model_id,
+ "genre": "genre"
+ }
+ req = client.post("/policies/", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ policy_id = next(iter(utilities.get_json(req.data)['policies']))
+
+ data = {
+ "name": policy_name + "-2",
+ "description": "description of {}".format(policy_name),
+ "model_id": model_id,
+ "genre": "genre"
+ }
+ req = client.patch("/policies/{}".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 200
+ assert json.loads(req.data)['policies'][policy_id]['name'] == policy_name + '-2'
+
+
+def test_update_policies_model_unused():
+ policy_name = uuid4().hex
+ client = utilities.register_client()
+ req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex)
+ model_id = list(req.keys())[0]
+ data = {
+ "name": policy_name,
+ "description": "description of {}".format(policy_name),
+ "model_id": model_id,
+ "genre": "genre"
+ }
+ req = client.post("/policies/", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ policy_id = next(iter(utilities.get_json(req.data)['policies']))
+ req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex)
+ model_id = list(req.keys())[0]
+ data = {
+ "name": policy_name,
+ "description": "description of {}".format(policy_name),
+ "model_id": model_id,
+ "genre": "genre"
+ }
+ req = client.patch("/policies/{}".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 200
+
+
+def test_update_policy_name_with_existed_one():
+ policy_name1 = "testuser" + uuid4().hex
+ client = utilities.register_client()
+ req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex)
+ model_id = list(req.keys())[0]
+ data = {
+ "name": policy_name1,
+ "description": "description of {}".format(policy_name1),
+ "model_id": model_id,
+ "genre": "genre"
+ }
+ req = client.post("/policies/", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ policy_id1 = next(iter(utilities.get_json(req.data)['policies']))
+
+ policy_name2 = "testuser" + uuid4().hex
+ client = utilities.register_client()
+ req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex)
+ model_id = list(req.keys())[0]
+ data = {
+ "name": policy_name2,
+ "description": "description of {}".format(policy_name2),
+ "model_id": model_id,
+ "genre": "genre"
+ }
+ req = client.post("/policies/", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ policy_id2 = next(iter(utilities.get_json(req.data)['policies']))
+
+ data = {
+ "name": policy_name1,
+ "description": "description of {}".format(policy_name1),
+ "model_id": model_id,
+ "genre": "genre"
+ }
+ req = client.patch("/policies/{}".format(policy_id2), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Policy Already Exists'
+
+
+def test_update_policies_with_empty_name():
+ policy_name = "testuser" + uuid4().hex
+ client = utilities.register_client()
+ req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex)
+ model_id = list(req.keys())[0]
+ data = {
+ "name": policy_name,
+ "description": "description of {}".format(policy_name),
+ "model_id": model_id,
+ "genre": "genre"
+ }
+ req = client.post("/policies/", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ policy_id = next(iter(utilities.get_json(req.data)['policies']))
+
+ data = {
+ "name": "",
+ "description": "description of {}".format(policy_name),
+ "model_id": model_id,
+ "genre": "genre"
+ }
+ req = client.patch("/policies/{}".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Policy Content Error'
+
+
+def test_update_policies_with_blank_model():
+ policy_name = "testuser" + uuid4().hex
+ client = utilities.register_client()
+ req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex)
+ model_id = list(req.keys())[0]
+ data = {
+ "name": policy_name,
+ "description": "description of {}".format(policy_name),
+ "model_id": model_id,
+ "genre": "genre"
+ }
+ req = client.post("/policies/", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ policy_id = next(iter(utilities.get_json(req.data)['policies']))
+
+ data = {
+ "name": policy_name,
+ "description": "description of {}".format(policy_name),
+ "model_id": "",
+ "genre": "genre"
+ }
+
+ req = client.patch("/policies/{}".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 200
+
+
+def test_update_policies_connected_to_rules_with_blank_model():
+ client = utilities.register_client()
+ req, rules, policy_id = data_builder.add_rules(client)
+ req = client.get("/policies")
+ data = utilities.get_json(req.data)
+ for policy_obj_id in data['policies']:
+ if policy_obj_id == policy_id:
+ policy = data['policies'][policy_obj_id]
+ policy['model_id'] = ''
+ req = client.patch("/policies/{}".format(policy_id), data=json.dumps(policy),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Policy update error'
+
+
+def test_delete_policies():
+ client = utilities.register_client()
+
+ policy = policy_helper.add_policies()
+ policy_id = list(policy.keys())[0]
+
+ req = client.delete("/policies/{}".format(policy_id))
+ assert req.status_code == 200
+
+
+def test_delete_policy_with_dependencies_rule():
+ client = utilities.register_client()
+ req, rules, policy_id = data_builder.add_rules(client)
+ req = client.delete("/policies/{}".format(policy_id))
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Policy With Rule Error'
+
+
+def test_delete_policy_with_dependencies_subject_data():
+ client = utilities.register_client()
+ req, rules, policy_id = data_builder.add_rules(client)
+ req = client.delete("/policies/{}/rules/{}".format(policy_id, next(iter(rules['rules']))))
+ assert req.status_code == 200
+ req = client.delete("/policies/{}".format(policy_id))
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Policy With Data Error'
+
+
+def test_delete_policy_with_dependencies_perimeter():
+ client = utilities.register_client()
+ policy = policy_helper.add_policies()
+ policy_id = next(iter(policy))
+
+ data = {
+ "name": 'testuser'+uuid4().hex,
+ "description": "description of {}".format(uuid4().hex),
+ "password": "password for {}".format(uuid4().hex),
+ "email": "{}@moon".format(uuid4().hex)
+ }
+ req = client.post("/policies/{}/subjects".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+
+ assert req.status_code == 200
+ req = client.delete("/policies/{}".format(policy_id))
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Policy With Perimeter Error'
+
+
+def test_delete_policies_without_id():
+ client = utilities.register_client()
+ req = delete_policies_without_id(client)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Policy Unknown'
diff --git a/old/moon_manager/tests/unit_python/api/test_rules.py b/old/moon_manager/tests/unit_python/api/test_rules.py
new file mode 100644
index 00000000..a3c21839
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/test_rules.py
@@ -0,0 +1,129 @@
+import api.utilities as utilities
+import json
+from helpers import data_builder as builder
+from uuid import uuid4
+from helpers import policy_helper
+
+
+def get_rules(client, policy_id):
+ req = client.get("/policies/{}/rules".format(policy_id))
+ rules = utilities.get_json(req.data)
+ return req, rules
+
+
+def add_rules_without_policy_id(client):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = builder.create_new_meta_rule()
+ data = {
+ "meta_rule_id": meta_rule_id,
+ "rule": [subject_category_id, object_category_id, action_category_id],
+ "instructions": (
+ {"decision": "grant"},
+ ),
+ "enabled": True
+ }
+ req = client.post("/policies/{}/rules".format(None), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ rules = utilities.get_json(req.data)
+ return req, rules
+
+
+def add_rules_without_meta_rule_id(client, policy_id):
+ data = {
+ "meta_rule_id": "",
+ "rule": ["subject_data_id2", "object_data_id2", "action_data_id2"],
+ "instructions": (
+ {"decision": "grant"},
+ ),
+ "enabled": True
+ }
+ req = client.post("/policies/{}/rules".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ rules = utilities.get_json(req.data)
+ return req, rules
+
+
+def add_rules_without_rule(client, policy_id):
+ data = {
+ "meta_rule_id": "meta_rule_id1",
+ "instructions": (
+ {"decision": "grant"},
+ ),
+ "enabled": True
+ }
+ req = client.post("/policies/{}/rules".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ rules = utilities.get_json(req.data)
+ return req, rules
+
+
+def delete_rules(client, policy_id, meta_rule_id):
+ req = client.delete("/policies/{}/rules/{}".format(policy_id, meta_rule_id))
+ return req
+
+
+def test_get_rules():
+ policy_id = utilities.get_policy_id()
+ client = utilities.register_client()
+ req, rules = get_rules(client, policy_id)
+ assert req.status_code == 200
+ assert isinstance(rules, dict)
+ assert "rules" in rules
+ return req, rules
+
+
+def test_add_rules():
+ client = utilities.register_client()
+ req, rules, policy = builder.add_rules(client, )
+ assert req.status_code == 200
+
+
+def test_add_rules_without_policy_id():
+ client = utilities.register_client()
+ req, rules = add_rules_without_policy_id(client)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Policy Unknown"
+
+#
+# def test_add_rules_without_meta_rule_id():
+# policy_id = utilities.get_policy_id()
+# client = utilities.register_client()
+# req, rules = add_rules_without_meta_rule_id(client, policy_id)
+# assert req.status_code == 400
+# assert json.loads(req.data)["message"] == "Key: 'meta_rule_id', [Empty String]"
+
+
+def test_add_rules_without_rule():
+ policy_id = utilities.get_policy_id()
+ client = utilities.register_client()
+ req, rules = add_rules_without_rule(client, policy_id)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == 'Invalid Key :rule not found'
+
+
+def test_delete_rules_with_invalid_parameters():
+ client = utilities.register_client()
+ req = delete_rules(client, "", "")
+ assert req.status_code == 404
+ # assert json.loads(req.data)["message"] == 'Invalid Key :rule not found'
+
+
+def test_delete_rules_without_policy_id():
+ client = utilities.register_client()
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = builder.create_new_policy()
+ sub_data_id = builder.create_subject_data(policy_id, subject_category_id)
+ obj_data_id = builder.create_object_data(policy_id, object_category_id)
+ act_data_id = builder.create_action_data(policy_id, action_category_id)
+ data = {
+ "meta_rule_id": meta_rule_id,
+ "rule": [sub_data_id, obj_data_id, act_data_id],
+ "instructions": (
+ {"decision": "grant"},
+ ),
+ "enabled": True
+ }
+ client.post("/policies/{}/rules".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ req, added_rules = get_rules(client, policy_id)
+ id = list(added_rules["rules"]["rules"])[0]["id"]
+ rules = delete_rules(client, None, id)
+ assert rules.status_code == 200
diff --git a/old/moon_manager/tests/unit_python/api/test_unit_models.py b/old/moon_manager/tests/unit_python/api/test_unit_models.py
new file mode 100644
index 00000000..6e93ed28
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/test_unit_models.py
@@ -0,0 +1,352 @@
+# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import json
+import api.utilities as utilities
+from helpers import data_builder as builder
+from helpers import policy_helper
+from helpers import model_helper
+from uuid import uuid4
+
+
+def get_models(client):
+ req = client.get("/models")
+ models = utilities.get_json(req.data)
+ return req, models
+
+
+def add_models(client, name, data=None):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = builder.create_new_meta_rule()
+
+ if not data:
+ data = {
+ "name": name,
+ "description": "description of {}".format(name),
+ "meta_rules": [meta_rule_id]
+ }
+ req = client.post("/models", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ models = utilities.get_json(req.data)
+ return req, models
+
+
+def update_model(client, name, model_id):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = builder.create_new_meta_rule()
+
+ data = {
+ "name": name,
+ "description": "description of {}".format(name),
+ "meta_rules": [meta_rule_id]
+ }
+ req = client.patch("/models/{}".format(model_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ models = utilities.get_json(req.data)
+ return req, models
+
+
+def add_model_without_meta_rules_ids(client, name):
+ data = {
+ "name": name,
+ "description": "description of {}".format(name),
+ "meta_rules": []
+ }
+ req = client.post("/models", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ models = utilities.get_json(req.data)
+ return req, models
+
+
+def add_model_with_empty_meta_rule_id(client, name):
+ data = {
+ "name": name,
+ "description": "description of {}".format(name),
+ "meta_rules": [""]
+ }
+ req = client.post("/models", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ models = utilities.get_json(req.data)
+ return req, models
+
+
+def update_model_without_meta_rules_ids(client, model_id):
+ name = "model_id" + uuid4().hex
+ data = {
+ "name": name,
+ "description": "description of {}".format(name),
+ "meta_rules": []
+ }
+ req = client.patch("/models/{}".format(model_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ models = utilities.get_json(req.data)
+ return req, models
+
+
+def delete_models(client, name):
+ request, models = get_models(client)
+ for key, value in models['models'].items():
+ if value['name'] == name:
+ req = client.delete("/models/{}".format(key))
+ break
+ return req
+
+
+def delete_models_without_id(client):
+ req = client.delete("/models/{}".format(""))
+ return req
+
+
+def test_delete_model_assigned_to_policy():
+ policy_name = "testuser" + uuid4().hex
+ client = utilities.register_client()
+ req = model_helper.add_model(model_id="mls_model_id" + uuid4().hex)
+ model_id = list(req.keys())[0]
+ data = {
+ "name": policy_name,
+ "description": "description of {}".format(policy_name),
+ "model_id": model_id,
+ "genre": "genre"
+ }
+ req = client.post("/policies", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ req = client.delete("/models/{}".format(model_id))
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Model With Policy Error'
+
+
+def clean_models():
+ client = utilities.register_client()
+ req, models = get_models(client)
+ for key, value in models['models'].items():
+ print(key)
+ print(value)
+ client.delete("/models/{}".format(key))
+
+
+def test_get_models():
+ client = utilities.register_client()
+ req, models = get_models(client)
+ assert req.status_code == 200
+ assert isinstance(models, dict)
+ assert "models" in models
+
+
+def test_add_models():
+ clean_models()
+ client = utilities.register_client()
+ req, models = add_models(client, "testuser")
+ assert req.status_code == 200
+ assert isinstance(models, dict)
+ model_id = list(models["models"])[0]
+ assert "models" in models
+ assert models['models'][model_id]['name'] == "testuser"
+ assert models['models'][model_id]["description"] == "description of {}".format("testuser")
+
+
+def test_delete_models():
+ client = utilities.register_client()
+ req = delete_models(client, "testuser")
+ assert req.status_code == 200
+
+
+def test_update_models_with_assigned_policy():
+ client = utilities.register_client()
+
+ model = model_helper.add_model(model_id="mls_model_id" + uuid4().hex)
+ model_id = list(model.keys())[0]
+ value = {
+ "name": "test_policy" + uuid4().hex,
+ "model_id": model_id,
+ "description": "test",
+ }
+ policy = policy_helper.add_policies(value=value)
+ data = {
+ "name": "model_" + uuid4().hex,
+ "description": "description of model_2",
+ "meta_rules": []
+ }
+ req = client.patch("/models/{}".format(model_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Model With Policy Error"
+
+
+def test_update_models_with_no_assigned_policy():
+ client = utilities.register_client()
+
+ model = model_helper.add_model(model_id="mls_model_id" + uuid4().hex)
+ model_id = list(model.keys())[0]
+
+ data = {
+ "name": "model_" + uuid4().hex,
+ "description": "description of model_2",
+ "meta_rules": []
+ }
+ req = client.patch("/models/{}".format(model_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+
+ assert req.status_code == 200
+
+
+def test_add_models_with_meta_rule_key():
+ client = utilities.register_client()
+
+ model = model_helper.add_model(model_id="mls_model_id" + uuid4().hex)
+ model_id = list(model.keys())[0]
+
+ data = {
+ "name": "model_" + uuid4().hex,
+ "description": "description of model_2",
+
+ }
+ req = client.patch("/models/{}".format(model_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Invalid Key :meta_rules not found"
+
+
+def test_delete_models_without_id():
+ client = utilities.register_client()
+ req = delete_models_without_id(client)
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "400: Model Unknown"
+
+
+def test_add_model_with_empty_name():
+ clean_models()
+ client = utilities.register_client()
+ req, models = add_models(client, "<br/>")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_add_model_with_name_contain_space():
+ clean_models()
+ client = utilities.register_client()
+ req, models = add_models(client, "test<br>user")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_add_model_with_name_space():
+ clean_models()
+ client = utilities.register_client()
+ req, models = add_models(client, " ")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Model Unknown'
+
+
+def test_add_model_with_empty_meta_rule_id():
+ clean_models()
+ client = utilities.register_client()
+ req, meta_rules = add_model_with_empty_meta_rule_id(client, "testuser")
+ assert req.status_code == 400
+ assert json.loads(req.data)["message"] == '400: Meta Rule Unknown'
+
+
+def test_add_model_with_existed_name():
+ clean_models()
+ client = utilities.register_client()
+ name = uuid4().hex
+ req, models = add_models(client, name)
+ assert req.status_code == 200
+ req, models = add_models(client, name)
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Model Error'
+
+
+def test_add_model_with_existed_meta_rules_list():
+ clean_models()
+ client = utilities.register_client()
+ name = uuid4().hex
+
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = builder.create_new_meta_rule()
+ data = {
+ "name": name,
+ "description": "description of {}".format(name),
+ "meta_rules": [meta_rule_id]
+ }
+ name = uuid4().hex
+ req, models = add_models(client=client, name=name, data=data)
+ assert req.status_code == 200
+
+ data = {
+ "name": name,
+ "description": "description of {}".format(name),
+ "meta_rules": [meta_rule_id]
+ }
+ req, models = add_models(client=client, name=name, data=data)
+ assert req.status_code == 409
+ assert json.loads(req.data)["message"] == '409: Model Error'
+
+
+def test_add_model_without_meta_rules():
+ clean_models()
+ client = utilities.register_client()
+ req, meta_rules = add_model_without_meta_rules_ids(client, "testuser")
+ assert req.status_code == 200
+ # assert json.loads(req.data)["message"] == "Key: 'meta_rules', [Empty Container]"
+
+
+def test_update_model():
+ clean_models()
+ client = utilities.register_client()
+ req = add_models(client, "testuser")
+ model_id = list(req[1]['models'])[0]
+ req_update = update_model(client, "testuser", model_id)
+ assert req_update[0].status_code == 200
+ model_id = list(req_update[1]["models"])[0]
+ assert req_update[1]["models"][model_id]["meta_rules"][0] is not None
+ delete_models(client, "testuser")
+
+
+def test_update_model_name_with_space():
+ clean_models()
+ client = utilities.register_client()
+ req = add_models(client, "testuser")
+ model_id = list(req[1]['models'])[0]
+ req_update = update_model(client, " ", model_id)
+ assert req_update[0].status_code == 400
+ assert req_update[1]["message"] == '400: Model Unknown'
+
+
+def test_update_model_with_empty_name():
+ clean_models()
+ client = utilities.register_client()
+ req = add_models(client, "testuser")
+ model_id = list(req[1]['models'])[0]
+ req_update = update_model(client, "", model_id)
+ assert req_update[0].status_code == 400
+ assert req_update[1]['message'] == '400: Model Unknown'
+
+
+def test_update_meta_rules_without_id():
+ clean_models()
+ client = utilities.register_client()
+ req_update = update_model(client, "testuser", "")
+ assert req_update[0].status_code == 400
+ assert json.loads(req_update[0].data)["message"] == "400: Model Unknown"
+
+
+def test_update_meta_rules_without_name():
+ client = utilities.register_client()
+ req_update = update_model(client, "<a></a>", "1234567")
+ assert req_update[0].status_code == 400
+ assert json.loads(req_update[0].data)[
+ "message"] == "Key: 'name', [Forbidden characters in string]"
+
+
+def test_update_meta_rules_without_meta_rules():
+ value = {
+ "name": "mls_model_id" + uuid4().hex,
+ "description": "test",
+ "meta_rules": []
+ }
+ model = model_helper.add_model(value=value)
+ model_id = list(model.keys())[0]
+ client = utilities.register_client()
+ req_update = update_model_without_meta_rules_ids(client, model_id)
+ assert req_update[0].status_code == 200
diff --git a/old/moon_manager/tests/unit_python/api/utilities.py b/old/moon_manager/tests/unit_python/api/utilities.py
new file mode 100644
index 00000000..2e51fec8
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/api/utilities.py
@@ -0,0 +1,26 @@
+import json
+from uuid import uuid4
+
+def get_json(data):
+ return json.loads(data.decode("utf-8"))
+
+
+def register_client():
+ import moon_manager.server
+ server = moon_manager.server.create_server()
+ client = server.app.test_client()
+ return client
+
+
+def get_policy_id():
+ from helpers import policy_helper
+ value = {
+ "name": "test_policy"+uuid4().hex,
+ "model_id": "",
+ "genre": "authz",
+ "description": "test",
+ }
+ policy_helper.add_policies(value=value)
+ req = policy_helper.get_policies()
+ policy_id = list(req.keys())[0]
+ return policy_id
diff --git a/old/moon_manager/tests/unit_python/conftest.py b/old/moon_manager/tests/unit_python/conftest.py
new file mode 100644
index 00000000..90a27e54
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/conftest.py
@@ -0,0 +1,254 @@
+import base64
+import json
+import logging
+import pytest
+import requests_mock
+
+CONF = {
+ "openstack": {
+ "keystone": {
+ "url": "http://keystone:5000/v3",
+ "user": "admin",
+ "check_token": False,
+ "password": "p4ssw0rd",
+ "domain": "default",
+ "certificate": False,
+ "project": "admin"
+ }
+ },
+ "components": {
+ "wrapper": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_wrapper:v4.3",
+ "timeout": 5,
+ "hostname": "wrapper"
+ },
+ "manager": {
+ "bind": "0.0.0.0",
+ "port": 8082,
+ "container": "wukongsun/moon_manager:v4.3",
+ "hostname": "manager"
+ },
+ "port_start": 31001,
+ "orchestrator": {
+ "bind": "0.0.0.0",
+ "port": 8083,
+ "container": "wukongsun/moon_orchestrator:v4.3",
+ "hostname": "orchestrator"
+ },
+ "pipeline": {
+ "interface": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_interface:v4.3",
+ "hostname": "interface"
+ },
+ "authz": {
+ "bind": "0.0.0.0",
+ "port": 8081,
+ "container": "wukongsun/moon_authz:v4.3",
+ "hostname": "authz"
+ },
+ }
+ },
+ "logging": {
+ "handlers": {
+ "file": {
+ "filename": "/tmp/moon.log",
+ "class": "logging.handlers.RotatingFileHandler",
+ "level": "DEBUG",
+ "formatter": "custom",
+ "backupCount": 3,
+ "maxBytes": 1048576
+ },
+ "console": {
+ "class": "logging.StreamHandler",
+ "formatter": "brief",
+ "level": "INFO",
+ "stream": "ext://sys.stdout"
+ }
+ },
+ "formatters": {
+ "brief": {
+ "format": "%(levelname)s %(name)s %(message)-30s"
+ },
+ "custom": {
+ "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s"
+ }
+ },
+ "root": {
+ "handlers": [
+ "console"
+ ],
+ "level": "ERROR"
+ },
+ "version": 1,
+ "loggers": {
+ "moon": {
+ "handlers": [
+ "console",
+ "file"
+ ],
+ "propagate": False,
+ "level": "DEBUG"
+ }
+ }
+ },
+ "slave": {
+ "name": None,
+ "master": {
+ "url": None,
+ "login": None,
+ "password": None
+ }
+ },
+ "docker": {
+ "url": "tcp://172.88.88.1:2376",
+ "network": "moon"
+ },
+ "database": {
+ "url": "sqlite:///database.db",
+ # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon",
+ "driver": "sql"
+ },
+ "messenger": {
+ "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon"
+ },
+}
+
+COMPONENTS = (
+ "logging",
+ "openstack/keystone",
+ "database",
+ "slave",
+ "components/manager",
+ "components/orchestrator"
+)
+
+PODS = {
+ "pods": {
+ "721760dd-de5f-11e7-8001-3863bbb766f3": [
+ {
+ "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd",
+ "port": 8080,
+ "genre": "interface",
+ "name": "interface-paltry",
+ "keystone_project_id": "a64beb1cc224474fb4badd43173e7101",
+ "namespace": "moon",
+ "container": "wukongsun/moon_interface:v4.3"
+ },
+ {
+ "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd",
+ "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "port": 8081,
+ "genre": "authz",
+ "name": "authz-economic",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "keystone_project_id": "a64beb1cc224474fb4badd43173e7101",
+ "namespace": "moon",
+ "container": "wukongsun/moon_authz:v4.3"
+ }
+ ]
+ }
+}
+
+SLAVES = {
+ "slaves": [
+ {
+ "context":
+ {
+ "cluster": "kubernetes",
+ "user": "kubernetes-admin"
+ },
+ "name": "kubernetes-admin@kubernetes",
+ "configured": True,
+ "wrapper_name": "mywrapper",
+ "ip": "NC",
+ "port": 31002,
+ "internal_port": 8080
+ }
+ ]
+}
+
+
+def get_b64_conf(component=None):
+ if component in CONF:
+ return base64.b64encode(
+ json.dumps(
+ CONF[component]).encode('utf-8') + b"\n").decode('utf-8')
+ elif "/" in component:
+ key1, _, key2 = component.partition("/")
+ return base64.b64encode(
+ json.dumps(
+ CONF[key1][key2]).encode('utf-8') + b"\n").decode('utf-8')
+ else:
+ return base64.b64encode(
+ json.dumps(CONF).encode('utf-8') + b"\n").decode('utf-8')
+
+
+@pytest.fixture(autouse=True)
+def no_requests(monkeypatch):
+ """ Modify the response from Requests module
+ """
+ with requests_mock.Mocker(real_http=True) as m:
+ for component in COMPONENTS:
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/{}'.format(component),
+ json=[{'Key': component, 'Value': get_b64_conf(component)}]
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/auth/tokens',
+ headers={'X-Subject-Token': "111111111"}
+ )
+ m.register_uri(
+ 'DELETE', 'http://keystone:5000/v3/auth/tokens',
+ headers={'X-Subject-Token': "111111111"}
+ )
+
+ def match_request_text(request):
+ # request.url may be None, or '' prevents a TypeError.
+ return 'http://keystone:5000/v3/users?name=testuser' in request.url
+
+ m.register_uri(
+ requests_mock.ANY, '/v3/users',
+ additional_matcher=match_request_text,
+ json={"users": {}}
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/users/',
+ json={"users": [{"id": "1111111111111"}]}
+ )
+ m.register_uri(
+ 'POST', 'http://orchestrator:8083/pods',
+ json=PODS,
+ headers={"content-type": "application/json"}
+ )
+ m.register_uri(
+ 'GET', 'http://orchestrator:8083/pods',
+ json=PODS
+ )
+ m.register_uri(
+ 'GET', 'http://localhost/slaves',
+ json=SLAVES
+ )
+ m.register_uri(
+ 'DELETE', 'http://orchestrator:8083/pods/{}'.format(list([PODS['pods'].keys()])[0]),
+ headers={"content-type": "application/json"}
+ )
+
+ print("Start populating the DB.")
+ from python_moondb.db_manager import init_engine, main
+ engine = init_engine()
+ print("engine={}".format(engine))
+ main("upgrade", logging.getLogger("db_manager"), engine)
+ print("End populating the DB.")
+ yield m
+
+# @pytest.fixture(autouse=True, scope="session")
+# def manage_database():
+# from moon_db.db_manager import init_engine, run
+# engine = init_engine()
+# run("upgrade", logging.getLogger("db_manager"), engine)
+# yield
+# print("Will close the DB")
diff --git a/old/moon_manager/tests/unit_python/helpers/__init__.py b/old/moon_manager/tests/unit_python/helpers/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/helpers/__init__.py
diff --git a/old/moon_manager/tests/unit_python/helpers/assignment_helper.py b/old/moon_manager/tests/unit_python/helpers/assignment_helper.py
new file mode 100644
index 00000000..22a56e38
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/helpers/assignment_helper.py
@@ -0,0 +1,49 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+def get_action_assignments(policy_id, action_id=None, category_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_action_assignments("", policy_id, action_id, category_id)
+
+
+def add_action_assignment(policy_id, action_id, category_id, data_id):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_action_assignment("", policy_id, action_id, category_id, data_id)
+
+
+def delete_action_assignment(policy_id, action_id, category_id, data_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_action_assignment("", policy_id, action_id, category_id, data_id)
+
+
+def get_object_assignments(policy_id, object_id=None, category_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_object_assignments("", policy_id, object_id, category_id)
+
+
+def add_object_assignment(policy_id, object_id, category_id, data_id):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_object_assignment("", policy_id, object_id, category_id, data_id)
+
+
+def delete_object_assignment(policy_id, object_id, category_id, data_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_object_assignment("", policy_id, object_id, category_id, data_id)
+
+
+def get_subject_assignments(policy_id, subject_id=None, category_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_subject_assignments("", policy_id, subject_id, category_id)
+
+
+def add_subject_assignment(policy_id, subject_id, category_id, data_id):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_subject_assignment("", policy_id, subject_id, category_id, data_id)
+
+
+def delete_subject_assignment(policy_id, subject_id, category_id, data_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_subject_assignment("", policy_id, subject_id, category_id, data_id)
+
diff --git a/old/moon_manager/tests/unit_python/helpers/category_helper.py b/old/moon_manager/tests/unit_python/helpers/category_helper.py
new file mode 100644
index 00000000..6c419ca8
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/helpers/category_helper.py
@@ -0,0 +1,40 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+def add_subject_category(cat_id=None, value=None):
+ from python_moondb.core import ModelManager
+ category = ModelManager.add_subject_category(user_id=None, category_id=cat_id, value=value)
+ return category
+
+
+def get_subject_category(cat_id=None):
+ from python_moondb.core import ModelManager
+ category = ModelManager.get_subject_categories(user_id=None, category_id=cat_id)
+ return category
+
+
+def add_object_category(cat_id=None, value=None):
+ from python_moondb.core import ModelManager
+ category = ModelManager.add_object_category(user_id=None, category_id=cat_id, value=value)
+ return category
+
+
+def get_object_category(cat_id=None):
+ from python_moondb.core import ModelManager
+ category = ModelManager.get_object_categories(user_id=None, category_id=cat_id)
+ return category
+
+
+def add_action_category(cat_id=None, value=None):
+ from python_moondb.core import ModelManager
+ category = ModelManager.add_action_category(user_id=None, category_id=cat_id, value=value)
+ return category
+
+
+def get_action_category(cat_id=None):
+ from python_moondb.core import ModelManager
+ category = ModelManager.get_action_categories(user_id=None, category_id=cat_id)
+ return category
diff --git a/old/moon_manager/tests/unit_python/helpers/data_builder.py b/old/moon_manager/tests/unit_python/helpers/data_builder.py
new file mode 100644
index 00000000..91808cbe
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/helpers/data_builder.py
@@ -0,0 +1,260 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from .category_helper import *
+from .policy_helper import *
+from .data_helper import *
+from helpers import model_helper
+from .meta_rule_helper import *
+import api.utilities as utilities
+import json
+from uuid import uuid4
+
+
+def create_subject_category(name):
+ subject_category = add_subject_category(
+ value={"name": name + uuid4().hex, "description": "description 1"})
+ return list(subject_category.keys())[0]
+
+
+def create_object_category(name):
+ object_category = add_object_category(
+ value={"name": name + uuid4().hex, "description": "description 1"})
+ return list(object_category.keys())[0]
+
+
+def create_action_category(name):
+ action_category = add_action_category(
+ value={"name": name + uuid4().hex, "description": "description 1"})
+ return list(action_category.keys())[0]
+
+
+def create_model(meta_rule_id, model_name="test_model"):
+ value = {
+ "name": model_name + uuid4().hex,
+ "description": "test",
+ "meta_rules": [meta_rule_id]
+
+ }
+ return value
+
+
+def create_policy(model_id, policy_name="policy_1"):
+ value = {
+ "name": policy_name,
+ "model_id": model_id,
+ "genre": "authz",
+ "description": "test",
+ }
+ return value
+
+
+def create_pdp(policies_ids):
+ value = {
+ "name": "test_pdp",
+ "security_pipeline": policies_ids,
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+ return value
+
+
+def create_new_policy(subject_category_name=None, object_category_name=None,
+ action_category_name=None, model_name=None, policy_name=None,
+ meta_rule_name=None):
+ if not subject_category_name:
+ subject_category_name = "subjectCategory_" + uuid4().hex
+ if not object_category_name:
+ object_category_name = "objectCategory_" + uuid4().hex
+ if not action_category_name:
+ action_category_name = "actionCategory_" + uuid4().hex
+
+ if not meta_rule_name:
+ meta_rule_name = "meta_rule_" + uuid4().hex
+
+ if not model_name:
+ model_name = "model_name_" + uuid4().hex
+ if not policy_name:
+ policy_name = "policy_name_" + uuid4().hex
+
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = create_new_meta_rule(
+ subject_category_name=subject_category_name + uuid4().hex,
+ object_category_name=object_category_name + uuid4().hex,
+ action_category_name=action_category_name + uuid4().hex,
+ meta_rule_name=meta_rule_name + uuid4().hex
+ )
+
+ model = model_helper.add_model(value=create_model(meta_rule_id, model_name + uuid4().hex))
+ model_id = list(model.keys())[0]
+ value = create_policy(model_id, policy_name + uuid4().hex)
+ policy = add_policies(value=value)
+ assert policy
+ policy_id = list(policy.keys())[0]
+ return subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id
+
+
+def create_new_meta_rule(subject_category_name=None, object_category_name=None,
+ action_category_name=None, meta_rule_name=None):
+ if not subject_category_name:
+ subject_category_name = "subjectCategory_" + uuid4().hex
+ if not object_category_name:
+ object_category_name = "objectCategory_" + uuid4().hex
+ if not action_category_name:
+ action_category_name = "actionCategory_" + uuid4().hex
+
+ if not meta_rule_name:
+ meta_rule_name = "meta_rule_" + uuid4().hex
+
+ subject_category_id = create_subject_category(subject_category_name)
+ object_category_id = create_object_category(object_category_name)
+ action_category_id = create_action_category(action_category_name)
+ value = {"name": meta_rule_name,
+ "description": "name of the meta rule algorithm",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ meta_rule = add_meta_rule(value=value)
+ return subject_category_id, object_category_id, action_category_id, list(meta_rule.keys())[0]
+
+
+def create_subject(policy_id):
+ value = {
+ "name": "testuser" + uuid4().hex,
+ "description": "test",
+ }
+ subject = add_subject(policy_id=policy_id, value=value)
+ return list(subject.keys())[0]
+
+
+def create_object(policy_id):
+ value = {
+ "name": "testobject" + uuid4().hex,
+ "description": "test",
+ }
+ object = add_object(policy_id=policy_id, value=value)
+ return list(object.keys())[0]
+
+
+def create_action(policy_id):
+ value = {
+ "name": "testaction" + uuid4().hex,
+ "description": "test",
+ }
+ action = add_action(policy_id=policy_id, value=value)
+ return list(action.keys())[0]
+
+
+def create_subject_data(policy_id, category_id):
+ value = {
+ "name": "subject-security-level",
+ "description": {"low": "", "medium": "", "high": ""},
+ }
+ subject_data = add_subject_data(policy_id=policy_id, category_id=category_id, value=value).get(
+ 'data')
+ assert subject_data
+ return list(subject_data.keys())[0]
+
+
+def create_object_data(policy_id, category_id):
+ value = {
+ "name": "object-security-level",
+ "description": {"low": "", "medium": "", "high": ""},
+ }
+ object_data = add_object_data(policy_id=policy_id, category_id=category_id, value=value).get(
+ 'data')
+ return list(object_data.keys())[0]
+
+
+def create_action_data(policy_id, category_id):
+ value = {
+ "name": "action-type",
+ "description": {"vm-action": "", "storage-action": "", },
+ }
+ action_data = add_action_data(policy_id=policy_id, category_id=category_id, value=value).get(
+ 'data')
+ return list(action_data.keys())[0]
+
+
+def get_policy_id_with_subject_assignment():
+ client = utilities.register_client()
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex)
+ subject_id = create_subject(policy_id)
+ data_id = create_subject_data(policy_id=policy_id, category_id=subject_category_id)
+
+ data = {
+ "id": subject_id,
+ "category_id": subject_category_id,
+ "data_id": data_id
+ }
+ client.post("/policies/{}/subject_assignments".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ return policy_id
+
+
+def get_policy_id_with_object_assignment():
+ client = utilities.register_client()
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex)
+ object_id = create_object(policy_id)
+ data_id = create_object_data(policy_id=policy_id, category_id=object_category_id)
+
+ data = {
+ "id": object_id,
+ "category_id": object_category_id,
+ "data_id": data_id
+ }
+
+ client.post("/policies/{}/object_assignments".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ return policy_id
+
+
+def get_policy_id_with_action_assignment():
+ client = utilities.register_client()
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = create_new_policy(
+ subject_category_name="subject_category1" + uuid4().hex,
+ object_category_name="object_category1" + uuid4().hex,
+ action_category_name="action_category1" + uuid4().hex,
+ meta_rule_name="meta_rule_1" + uuid4().hex)
+ action_id = create_action(policy_id)
+ data_id = create_action_data(policy_id=policy_id, category_id=action_category_id)
+
+ data = {
+ "id": action_id,
+ "category_id": action_category_id,
+ "data_id": data_id
+ }
+ client.post("/policies/{}/action_assignments".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ return policy_id
+
+
+def add_rules(client):
+ sub_id, obj_id, act_id, meta_rule_id, policy_id = create_new_policy("sub_cat" + uuid4().hex,
+ "obj_cat" + uuid4().hex,
+ "act_cat" + uuid4().hex)
+ sub_data_id = create_subject_data(policy_id, sub_id)
+ obj_data_id = create_object_data(policy_id, obj_id)
+ act_data_id = create_action_data(policy_id, act_id)
+ data = {
+ "meta_rule_id": meta_rule_id,
+ "rule": [sub_data_id, obj_data_id, act_data_id],
+ "instructions": (
+ {"decision": "grant"},
+ ),
+ "enabled": True
+ }
+ req = client.post("/policies/{}/rules".format(policy_id), data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ rules = utilities.get_json(req.data)
+ return req, rules, policy_id
diff --git a/old/moon_manager/tests/unit_python/helpers/data_helper.py b/old/moon_manager/tests/unit_python/helpers/data_helper.py
new file mode 100644
index 00000000..e1c05640
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/helpers/data_helper.py
@@ -0,0 +1,99 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+def get_action_data(policy_id, data_id=None, category_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_action_data("", policy_id, data_id, category_id)
+
+
+def add_action_data(policy_id, data_id=None, category_id=None, value=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_action_data("", policy_id, data_id, category_id, value)
+
+
+def delete_action_data(policy_id, data_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_action_data("", policy_id=policy_id, data_id=data_id)
+
+
+def get_object_data(policy_id, data_id=None, category_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_object_data("", policy_id, data_id, category_id)
+
+
+def add_object_data(policy_id, data_id=None, category_id=None, value=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_object_data("", policy_id, data_id, category_id, value)
+
+
+def delete_object_data(policy_id, data_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_object_data("", policy_id=policy_id, data_id=data_id)
+
+
+def get_subject_data(policy_id, data_id=None, category_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_subject_data("", policy_id, data_id, category_id)
+
+
+def add_subject_data(policy_id, data_id=None, category_id=None, value=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.set_subject_data("", policy_id, data_id, category_id, value)
+
+
+def delete_subject_data(policy_id, data_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_subject_data("", policy_id=policy_id, data_id=data_id)
+
+
+def get_actions(policy_id, perimeter_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_actions("", policy_id, perimeter_id)
+
+
+def add_action(policy_id, perimeter_id=None, value=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_action("", policy_id, perimeter_id, value)
+
+
+def delete_action(policy_id, perimeter_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_action("", policy_id, perimeter_id)
+
+
+def get_objects(policy_id, perimeter_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_objects("", policy_id, perimeter_id)
+
+
+def add_object(policy_id, perimeter_id=None, value=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_object("", policy_id, perimeter_id, value)
+
+
+def delete_object(policy_id, perimeter_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_object("", policy_id, perimeter_id)
+
+
+def get_subjects(policy_id, perimeter_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_subjects("", policy_id, perimeter_id)
+
+
+def add_subject(policy_id, perimeter_id=None, value=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_subject("", policy_id, perimeter_id, value)
+
+
+def delete_subject(policy_id, perimeter_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_subject("", policy_id, perimeter_id)
+
+
+def get_available_metadata(policy_id):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_available_metadata("", policy_id)
diff --git a/old/moon_manager/tests/unit_python/helpers/meta_rule_helper.py b/old/moon_manager/tests/unit_python/helpers/meta_rule_helper.py
new file mode 100644
index 00000000..e882706b
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/helpers/meta_rule_helper.py
@@ -0,0 +1,49 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from helpers import data_builder as builder
+from uuid import uuid4
+
+
+def set_meta_rule(meta_rule_id, value=None):
+ from python_moondb.core import ModelManager
+ if not value:
+ action_category_id = builder.create_action_category("action_category_id1"+uuid4().hex)
+ subject_category_id = builder.create_subject_category("subject_category_id1"+uuid4().hex)
+ object_category_id = builder.create_object_category("object_category_id1"+uuid4().hex)
+ value = {
+ "name": "MLS_meta_rule",
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ return ModelManager.set_meta_rule(user_id=None, meta_rule_id=meta_rule_id, value=value)
+
+
+def add_meta_rule(meta_rule_id=None, value=None):
+ from python_moondb.core import ModelManager
+ if not value:
+ action_category_id = builder.create_action_category("action_category_id1"+uuid4().hex)
+ subject_category_id = builder.create_subject_category("subject_category_id1"+uuid4().hex)
+ object_category_id = builder.create_object_category("object_category_id1"+uuid4().hex)
+ value = {
+ "name": "MLS_meta_rule"+uuid4().hex,
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ return ModelManager.add_meta_rule(user_id=None, meta_rule_id=meta_rule_id, value=value)
+
+
+def get_meta_rules(meta_rule_id=None):
+ from python_moondb.core import ModelManager
+ return ModelManager.get_meta_rules(user_id=None, meta_rule_id=meta_rule_id)
+
+
+def delete_meta_rules(meta_rule_id=None):
+ from python_moondb.core import ModelManager
+ ModelManager.delete_meta_rule(user_id=None, meta_rule_id=meta_rule_id)
diff --git a/old/moon_manager/tests/unit_python/helpers/model_helper.py b/old/moon_manager/tests/unit_python/helpers/model_helper.py
new file mode 100644
index 00000000..73808e03
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/helpers/model_helper.py
@@ -0,0 +1,48 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from helpers import data_builder as builder
+from uuid import uuid4
+
+
+def get_models(model_id=None):
+ from python_moondb.core import ModelManager
+ return ModelManager.get_models(user_id=None, model_id=model_id)
+
+
+def add_model(model_id=None, value=None):
+ from python_moondb.core import ModelManager
+ if not value:
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = builder.create_new_meta_rule()
+ name = "MLS"+uuid4().hex if model_id is None else "MLS " + model_id
+ value = {
+ "name": name,
+ "description": "test",
+ "meta_rules": [meta_rule_id]
+ }
+ return ModelManager.add_model(user_id=None, model_id=model_id, value=value)
+
+
+def delete_models(uuid=None, name=None):
+ from python_moondb.core import ModelManager
+ if not uuid:
+ for model_id, model_value in get_models():
+ if name == model_value['name']:
+ uuid = model_id
+ break
+ ModelManager.delete_model(user_id=None, model_id=uuid)
+
+
+def delete_all_models():
+ from python_moondb.core import ModelManager
+ models_values = get_models()
+ print(models_values)
+ for model_id, model_value in models_values.items():
+ ModelManager.delete_model(user_id=None, model_id=model_id)
+
+
+def update_model(model_id=None, value=None):
+ from python_moondb.core import ModelManager
+ return ModelManager.update_model(user_id=None, model_id=model_id, value=value)
diff --git a/old/moon_manager/tests/unit_python/helpers/pdp_helper.py b/old/moon_manager/tests/unit_python/helpers/pdp_helper.py
new file mode 100644
index 00000000..3d169b06
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/helpers/pdp_helper.py
@@ -0,0 +1,23 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+def update_pdp(pdp_id, value):
+ from python_moondb.core import PDPManager
+ return PDPManager.update_pdp("", pdp_id, value)
+
+
+def delete_pdp(pdp_id):
+ from python_moondb.core import PDPManager
+ PDPManager.delete_pdp("", pdp_id)
+
+
+def add_pdp(pdp_id=None, value=None):
+ from python_moondb.core import PDPManager
+ return PDPManager.add_pdp("", pdp_id, value)
+
+
+def get_pdp(pdp_id=None):
+ from python_moondb.core import PDPManager
+ return PDPManager.get_pdp("", pdp_id)
diff --git a/old/moon_manager/tests/unit_python/helpers/policy_helper.py b/old/moon_manager/tests/unit_python/helpers/policy_helper.py
new file mode 100644
index 00000000..eddd0b8d
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/helpers/policy_helper.py
@@ -0,0 +1,63 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from uuid import uuid4
+
+def get_policies():
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_policies("admin")
+
+
+def add_policies(policy_id=None, value=None):
+ from python_moondb.core import PolicyManager
+ if not value:
+ value = {
+ "name": "test_policy"+ uuid4().hex,
+ "model_id": "",
+ "genre": "authz",
+ "description": "test",
+ }
+ return PolicyManager.add_policy("admin", policy_id=policy_id, value=value)
+
+
+def delete_policies(uuid=None, name=None):
+ from python_moondb.core import PolicyManager
+ if not uuid:
+ for policy_id, policy_value in get_policies():
+ if name == policy_value['name']:
+ uuid = policy_id
+ break
+ PolicyManager.delete_policy("admin", uuid)
+
+
+def update_policy(policy_id, value):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.update_policy("admin", policy_id, value)
+
+
+def get_policy_from_meta_rules(meta_rule_id):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_policy_from_meta_rules("admin", meta_rule_id)
+
+
+def get_rules(policy_id=None, meta_rule_id=None, rule_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_rules("", policy_id, meta_rule_id, rule_id)
+
+
+def add_rule(policy_id=None, meta_rule_id=None, value=None):
+ from python_moondb.core import PolicyManager
+ if not value:
+ value = {
+ "rule": ("high", "medium", "vm-action"),
+ "instructions": ({"decision": "grant"}),
+ "enabled": "",
+ }
+ return PolicyManager.add_rule("", policy_id, meta_rule_id, value)
+
+
+def delete_rule(policy_id=None, rule_id=None):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_rule("", policy_id, rule_id)
diff --git a/old/moon_manager/tests/unit_python/requirements.txt b/old/moon_manager/tests/unit_python/requirements.txt
new file mode 100644
index 00000000..d6f190e4
--- /dev/null
+++ b/old/moon_manager/tests/unit_python/requirements.txt
@@ -0,0 +1,5 @@
+flask
+flask_cors
+flask_restful
+python_moondb==1.2.20
+python_moonutilities==1.4.20
diff --git a/old/moon_orchestrator/Changelog b/old/moon_orchestrator/Changelog
new file mode 100644
index 00000000..c04af79c
--- /dev/null
+++ b/old/moon_orchestrator/Changelog
@@ -0,0 +1,36 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+CHANGES
+=======
+
+0.1.0
+-----
+- First version of the moon_orchestrator library.
+
+1.0.0
+-----
+- First public version of the moon_orchestrator library.
+
+1.0.1
+-----
+- add Changelog
+
+1.1.0
+-----
+- add bootstrap file to start Orchestrator with all configuration
+
+4.4.1
+-----
+- the processing of a request is now performed in a thread
+
+4.4.2
+-----
+- apply pylint rules
+
+4.4.3
+-----
+- add "internal_port" key in slave API
diff --git a/old/moon_orchestrator/Dockerfile b/old/moon_orchestrator/Dockerfile
new file mode 100644
index 00000000..7c59efb5
--- /dev/null
+++ b/old/moon_orchestrator/Dockerfile
@@ -0,0 +1,15 @@
+FROM python:3.6
+
+LABEL Name=Orchestrator
+LABEL Description="Orchestrator component for the Moon platform"
+LABEL Maintainer="Thomas Duval"
+LABEL Url="https://wiki.opnfv.org/display/moon/Moon+Project+Proposal"
+
+USER root
+
+ADD . /root
+WORKDIR /root/
+RUN pip3 install --no-cache-dir -r requirements.txt
+RUN pip3 install --no-cache-dir .
+
+CMD ["python3", "-m", "moon_orchestrator"] \ No newline at end of file
diff --git a/old/moon_orchestrator/LICENSE b/old/moon_orchestrator/LICENSE
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/old/moon_orchestrator/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/old/moon_orchestrator/MANIFEST.in b/old/moon_orchestrator/MANIFEST.in
new file mode 100644
index 00000000..8de5a391
--- /dev/null
+++ b/old/moon_orchestrator/MANIFEST.in
@@ -0,0 +1,10 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+include README.rst
+include LICENSE
+include setup.py
+include requirements.txt
+graft conf
diff --git a/old/moon_orchestrator/README.md b/old/moon_orchestrator/README.md
new file mode 100644
index 00000000..aec5cda2
--- /dev/null
+++ b/old/moon_orchestrator/README.md
@@ -0,0 +1,4 @@
+# moon_orchestrator
+
+Internal orchestrator used for the Moon framework
+
diff --git a/old/moon_orchestrator/moon_orchestrator/__init__.py b/old/moon_orchestrator/moon_orchestrator/__init__.py
new file mode 100644
index 00000000..31d40184
--- /dev/null
+++ b/old/moon_orchestrator/moon_orchestrator/__init__.py
@@ -0,0 +1,6 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+__version__ = "4.4.3"
diff --git a/old/moon_orchestrator/moon_orchestrator/__main__.py b/old/moon_orchestrator/moon_orchestrator/__main__.py
new file mode 100644
index 00000000..df051f26
--- /dev/null
+++ b/old/moon_orchestrator/moon_orchestrator/__main__.py
@@ -0,0 +1,4 @@
+from moon_orchestrator.server import create_server
+
+server = create_server()
+server.run()
diff --git a/old/moon_orchestrator/moon_orchestrator/api/__init__.py b/old/moon_orchestrator/moon_orchestrator/api/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/moon_orchestrator/moon_orchestrator/api/__init__.py
diff --git a/old/moon_orchestrator/moon_orchestrator/api/generic.py b/old/moon_orchestrator/moon_orchestrator/api/generic.py
new file mode 100644
index 00000000..9128140a
--- /dev/null
+++ b/old/moon_orchestrator/moon_orchestrator/api/generic.py
@@ -0,0 +1,99 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Those API are helping API used to manage the Moon platform.
+"""
+
+from flask_restful import Resource, request
+import logging
+import moon_orchestrator.api
+from python_moonutilities.security_functions import check_auth
+
+__version__ = "4.3.1"
+
+logger = logging.getLogger("moon.orchestrator.api." + __name__)
+
+
+class Status(Resource):
+ """
+ Endpoint for status requests
+ """
+
+ __urls__ = ("/status", "/status/", "/status/<string:component_id>")
+
+ def get(self, component_id=None):
+ """Retrieve status of all components
+
+ :return: {
+ "orchestrator": {
+ "status": "Running"
+ },
+ "security_router": {
+ "status": "Running"
+ }
+ }
+ """
+ raise NotImplemented
+
+
+class API(Resource):
+ """
+ Endpoint for API requests
+ """
+
+ __urls__ = (
+ "/api",
+ "/api/",
+ "/api/<string:group_id>",
+ "/api/<string:group_id>/",
+ "/api/<string:group_id>/<string:endpoint_id>")
+
+ @check_auth
+ def get(self, group_id="", endpoint_id="", user_id=""):
+ """Retrieve all API endpoints or a specific endpoint if endpoint_id is given
+
+ :param group_id: the name of one existing group (ie generic, ...)
+ :param endpoint_id: the name of one existing component (ie Logs, Status, ...)
+ :return: {
+ "group_name": {
+ "endpoint_name": {
+ "description": "a description",
+ "methods": {
+ "get": "description of the HTTP method"
+ },
+ "urls": ('/api', '/api/', '/api/<string:endpoint_id>')
+ }
+ }
+ """
+ __methods = ("get", "post", "put", "delete", "options", "patch")
+ api_list = filter(lambda x: "__" not in x, dir(moon_orchestrator.api))
+ api_desc = dict()
+ for api_name in api_list:
+ api_desc[api_name] = {}
+ group_api_obj = eval("moon_interface.api.{}".format(api_name))
+ api_desc[api_name]["description"] = group_api_obj.__doc__
+ if "__version__" in dir(group_api_obj):
+ api_desc[api_name]["version"] = group_api_obj.__version__
+ object_list = list(filter(lambda x: "__" not in x, dir(group_api_obj)))
+ for obj in map(lambda x: eval("moon_interface.api.{}.{}".format(api_name, x)),
+ object_list):
+ if "__urls__" in dir(obj):
+ api_desc[api_name][obj.__name__] = dict()
+ api_desc[api_name][obj.__name__]["urls"] = obj.__urls__
+ api_desc[api_name][obj.__name__]["methods"] = dict()
+ for _method in filter(lambda x: x in __methods, dir(obj)):
+ docstring = eval(
+ "moon_interface.api.{}.{}.{}.__doc__".format(api_name, obj.__name__,
+ _method))
+ api_desc[api_name][obj.__name__]["methods"][_method] = docstring
+ api_desc[api_name][obj.__name__]["description"] = str(obj.__doc__)
+ if group_id in api_desc:
+ if endpoint_id in api_desc[group_id]:
+ return {group_id: {endpoint_id: api_desc[group_id][endpoint_id]}}
+ elif len(endpoint_id) > 0:
+ logger.error("Unknown endpoint_id {}".format(endpoint_id))
+ return {"error": "Unknown endpoint_id {}".format(endpoint_id)}
+ return {group_id: api_desc[group_id]}
+ return api_desc
diff --git a/old/moon_orchestrator/moon_orchestrator/api/pods.py b/old/moon_orchestrator/moon_orchestrator/api/pods.py
new file mode 100644
index 00000000..8943e018
--- /dev/null
+++ b/old/moon_orchestrator/moon_orchestrator/api/pods.py
@@ -0,0 +1,174 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from flask import request
+from flask_restful import Resource
+from python_moonutilities.security_functions import check_auth
+from python_moonutilities import exceptions
+import logging
+
+logger = logging.getLogger("moon.orchestrator.api.pods")
+
+
+class Pods(Resource):
+ """
+ Endpoint for pdp requests
+ """
+
+ __version__ = "4.3.1"
+ POD_TYPES = ("authz", "wrapper")
+
+ __urls__ = (
+ "/pods",
+ "/pods/",
+ "/pods/<string:uuid>",
+ "/pods/<string:uuid>/",
+ )
+
+ def __init__(self, **kwargs):
+ self.driver = kwargs.get("driver")
+
+ @check_auth
+ def get(self, uuid=None, user_id=None):
+ """Retrieve all pods
+
+ :param uuid: uuid of the pod
+ :param user_id: user ID who do the request
+ :return: {
+ "pod_id1": {
+ "name": "...",
+ "replicas": "...",
+ "description": "...",
+ }
+ }
+ :internal_api: get_pdp
+ """
+ pods = {}
+ try:
+ if uuid:
+ return {"pods": self.driver.get_pods(uuid)}
+ for _pod_key, _pod_values in self.driver.get_pods().items():
+ pods[_pod_key] = []
+ for _pod_value in _pod_values:
+ if "namespace" in _pod_value and _pod_value['namespace'] != "moon":
+ continue
+ pods[_pod_key].append(_pod_value)
+ return {"pods": pods}
+ except Exception as e:
+ return {"result": False, "message": str(e)}, 500
+
+ def __validate_pod_with_keystone_pid(self, keystone_pid):
+ for pod_key, pod_values in self.driver.get_pods().items():
+ if pod_values and "keystone_project_id" in pod_values[0] \
+ and pod_values[0]['keystone_project_id'] == keystone_pid:
+ return True
+
+ def __is_slave_exist(self, slave_name):
+ for slave in self.driver.get_slaves():
+ if "name" in slave and "configured" in slave \
+ and slave_name == slave["name"] and slave["configured"]:
+ return True
+
+ def __get_slave_names(self):
+ for slave in self.driver.get_slaves():
+ if "name" in slave:
+ yield slave["name"]
+
+ @check_auth
+ def post(self, uuid=None, user_id=None):
+ """Create a new pod.
+
+ :param uuid: uuid of the pod (not used here)
+ :param user_id: user ID who do the request
+ :request body: {
+ "pdp_id": "fa2323f7055d4a88b1b85d31fe5e8369",
+ "name": "pdp_rbac3",
+ "keystone_project_id": "ceacbb5564cc48ad929dd4f00e52bf63",
+ "models": {...},
+ "policies": {...},
+ "description": "test",
+ "security_pipeline": [...],
+ "slave_name": ""
+ }
+ :return: {
+ "pdp_id1": {
+ "name": "...",
+ "replicas": "...",
+ "description": "...",
+ }
+ }
+ """
+ if "security_pipeline" in request.json:
+ if self.__validate_pod_with_keystone_pid(request.json.get("keystone_project_id")):
+ raise exceptions.PipelineConflict
+ if not request.json.get("pdp_id"):
+ raise exceptions.PdpUnknown
+ if not request.json.get("security_pipeline"):
+ raise exceptions.PolicyUnknown
+ self.driver.create_pipeline(
+ request.json.get("keystone_project_id"),
+ request.json.get("pdp_id"),
+ request.json.get("security_pipeline"),
+ manager_data=request.json,
+ slave_name=request.json.get("slave_name"))
+ else:
+ logger.info("------------------------------------")
+ logger.info(list(self.__get_slave_names()))
+ logger.info("------------------------------------")
+ if self.__is_slave_exist(request.json.get("slave_name")):
+ raise exceptions.WrapperConflict
+ if request.json.get("slave_name") not in self.__get_slave_names():
+ raise exceptions.SlaveNameUnknown
+ slave_name = request.json.get("slave_name")
+ if not slave_name:
+ slave_name = self.driver.get_slaves(active=True)
+ self.driver.create_wrappers(slave_name)
+ return {"pods": self.driver.get_pods()}
+
+ @check_auth
+ def delete(self, uuid=None, user_id=None):
+ """Delete a pod
+
+ :param uuid: uuid of the pod to delete
+ :param user_id: user ID who do the request
+ :return: {
+ "result": "True or False",
+ "message": "optional message"
+ }
+ """
+ try:
+ self.driver.delete_pipeline(uuid)
+ return {'result': True}
+ except exceptions.PipelineUnknown:
+ for slave in self.driver.get_slaves():
+ if "name" in slave and "wrapper_name" in slave:
+ if uuid in (slave['name'], slave["wrapper_name"]):
+ self.driver.delete_wrapper(name=slave["wrapper_name"])
+ else:
+ raise exceptions.SlaveNameUnknown
+ except Exception as e:
+ return {"result": False, "message": str(e)}, 500
+
+ # @check_auth
+ # def patch(self, uuid=None, user_id=None):
+ # """Update a pod
+ #
+ # :param uuid: uuid of the pdp to update
+ # :param user_id: user ID who do the request
+ # :request body: {
+ # "name": "...",
+ # "replicas": "...",
+ # "description": "...",
+ # }
+ # :return: {
+ # "pod_id1": {
+ # "name": "...",
+ # "replicas": "...",
+ # "description": "...",
+ # }
+ # }
+ # :internal_api: update_pdp
+ # """
+ # return {"pods": None}
diff --git a/old/moon_orchestrator/moon_orchestrator/api/slaves.py b/old/moon_orchestrator/moon_orchestrator/api/slaves.py
new file mode 100644
index 00000000..7453d305
--- /dev/null
+++ b/old/moon_orchestrator/moon_orchestrator/api/slaves.py
@@ -0,0 +1,46 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from flask import request
+from flask_restful import Resource
+from python_moonutilities.security_functions import check_auth
+import logging
+
+logger = logging.getLogger("moon.orchestrator.api.slaves")
+
+
+class Slaves(Resource):
+ """
+ Endpoint for slaves requests
+ """
+
+ __version__ = "4.3.1"
+
+ __urls__ = (
+ "/slaves",
+ "/slaves/",
+ "/slaves/<string:uuid>",
+ "/slaves/<string:uuid>/",
+ )
+
+ def __init__(self, **kwargs):
+ self.driver = kwargs.get("driver")
+
+ @check_auth
+ def get(self, uuid=None, user_id=None):
+ """Retrieve all pods
+
+ :param uuid: uuid of the pod
+ :param user_id: user ID who do the request
+ :return: {
+ "pod_id1": {
+ "name": "...",
+ "replicas": "...",
+ "description": "...",
+ }
+ }
+ """
+ slaves = self.driver.get_slaves()
+ return {"slaves": slaves}
diff --git a/old/moon_orchestrator/moon_orchestrator/drivers.py b/old/moon_orchestrator/moon_orchestrator/drivers.py
new file mode 100644
index 00000000..233d389e
--- /dev/null
+++ b/old/moon_orchestrator/moon_orchestrator/drivers.py
@@ -0,0 +1,487 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from kubernetes import client, config
+import logging
+import requests
+import urllib3.exceptions
+from python_moonutilities import configuration, exceptions
+from python_moonutilities.misc import get_random_name
+
+logger = logging.getLogger("moon.orchestrator.drivers")
+
+
+def get_driver():
+ try:
+ return K8S()
+ except urllib3.exceptions.MaxRetryError as e:
+ logger.exception(e)
+ return Docker()
+
+
+class Driver:
+
+ def __init__(self):
+ self.cache = {}
+ # example of cache:
+ # {
+ # "uuid_of_pod": {
+ # "ip": "",
+ # "hostname": "",
+ # "port": 30001,
+ # "pdp": "",
+ # "keystone_project_id": "",
+ # "plugin_name": "",
+ # "namespace": ""
+ # }
+ # }
+
+ def get_slaves(self):
+ raise NotImplementedError
+
+ def create_wrappers(self):
+ raise NotImplementedError
+
+ def delete_wrapper(self, name):
+ raise NotImplementedError
+
+ def create_pipeline(self, keystone_project_id,
+ pdp_id, policy_ids, manager_data=None,
+ active_context=None,
+ active_context_name=None):
+ raise NotImplementedError
+
+ def delete_pipeline(self, uuid=None, name=None, namespace="moon",
+ active_context=None,
+ active_context_name=None):
+ raise NotImplementedError
+
+
+class K8S(Driver):
+
+ def __init__(self):
+ super(K8S, self).__init__()
+ config.load_kube_config()
+ self.client = client.CoreV1Api()
+ conf = configuration.get_configuration("components/orchestrator")
+ self.orchestrator_hostname = conf["components/orchestrator"].get("hostname", "orchestrator")
+ self.orchestrator_port = conf["components/orchestrator"].get("port", 80)
+ conf = configuration.get_configuration("components/manager")
+ self.manager_hostname = conf["components/manager"].get("hostname", "manager")
+ self.manager_port = conf["components/manager"].get("port", 80)
+
+ def get_pods(self, name=None):
+ if name:
+ pods = self.client.list_pod_for_all_namespaces(watch=False)
+ for pod in pods.items:
+ logger.debug("get_pods {}".format(pod.metadata.name))
+ if name in pod.metadata.name:
+ return pod
+ else:
+ return None
+ logger.debug("get_pods cache={}".format(self.cache))
+ return self.cache
+
+ @staticmethod
+ def __create_deployment(client, data):
+ pod_manifest = {
+ 'apiVersion': 'extensions/v1beta1',
+ 'kind': 'Deployment',
+ 'metadata': {
+ 'name': data[0].get('name')
+ },
+ 'spec': {
+ 'replicas': 1,
+ 'template': {
+ 'metadata': {'labels': {'app': data[0].get('name')}},
+ 'hostname': data[0].get('name'),
+ 'spec': {
+ 'containers': []
+ }
+ },
+ }
+ }
+ for _data in data:
+ pod_manifest['spec']['template']['spec']['containers'].append(
+ {
+ 'image': _data.get('container', "busybox"),
+ 'name': _data.get('name'),
+ 'hostname': _data.get('name'),
+ 'ports': [
+ {"containerPort": _data.get('port', 80)},
+ ],
+ 'env': [
+ {'name': "UUID", "value": _data.get('name', "None")},
+ {'name': "TYPE", "value": _data.get('genre', "None")},
+ {'name': "PORT", "value": str(_data.get('port', 80))},
+ {'name': "PDP_ID", "value": _data.get('pdp_id', "None")},
+ {'name': "META_RULE_ID", "value": _data.get('meta_rule_id', "None")},
+ {'name': "KEYSTONE_PROJECT_ID",
+ "value": _data.get('keystone_project_id', "None")},
+ ]
+ }
+ )
+ resp = client.create_namespaced_deployment(body=pod_manifest,
+ namespace='moon')
+ logger.info("Pod {} created!".format(data[0].get('name')))
+ return resp
+
+ @staticmethod
+ def __create_service(client, data, expose=False):
+ service_manifest = {
+ 'apiVersion': 'v1',
+ 'kind': 'Service',
+ 'metadata': {
+ 'name': data.get('name'),
+ 'namespace': 'moon'
+ },
+ 'spec': {
+ 'ports': [{
+ 'port': data.get('port', 80),
+ 'targetPort': data.get('port', 80)
+ }],
+ 'selector': {
+ 'app': data.get('name')
+ },
+ # 'type': 'NodePort',
+ 'endpoints': [{
+ 'port': data.get('port', 80),
+ 'protocol': 'TCP',
+ }],
+ }
+ }
+ if expose:
+ service_manifest['spec']['ports'][0]['nodePort'] = \
+ configuration.increment_port()
+ service_manifest['spec']['type'] = "NodePort"
+ resp = client.create_namespaced_service(namespace="moon",
+ body=service_manifest)
+ logger.info("Service {} created!".format(data.get('name')))
+ return service_manifest
+
+ def load_deployment_and_service(self, data, api_client=None, ext_client=None, expose=False):
+ _client = api_client if api_client else self.client
+ manifest = self.__create_service(client=_client, data=data[0],
+ expose=expose)
+ data[0]["external_port"] = manifest['spec']['ports'][0].get('nodePort')
+ pod = self.__create_deployment(client=ext_client, data=data)
+ self.cache[pod.metadata.uid] = data
+
+ def delete_deployment(self, name=None, namespace="moon", ext_client=None):
+ logger.info("Deleting deployment {}".format(name))
+ body = client.V1DeleteOptions(propagation_policy='Foreground')
+ ret = ext_client.delete_namespaced_deployment(
+ name=name,
+ namespace=namespace,
+ body=body
+ )
+ logger.debug(ret)
+ _uid = None
+ for uid, value in self.cache.items():
+ if value[0]['name'] == name:
+ _uid = uid
+ break
+ if _uid:
+ self.cache.pop(_uid)
+ else:
+ raise exceptions.DockerError("Cannot find and delete pod named {}".format(name))
+
+ def delete_service(self, name, namespace="moon", api_client=None):
+ if not api_client:
+ api_client = self.client
+ ret = api_client.delete_namespaced_service(name=name, namespace=namespace)
+ logger.debug("delete_service {}".format(ret))
+
+ def get_slaves(self, active=False):
+ contexts, active_context = self.get_contexts()
+ pods = self.get_pods()
+ # logger.info("pods = {}".format(pods))
+ slaves = []
+ if active:
+ for key, value in pods.items():
+ # logger.info("ctx={}".format(active_context))
+ # logger.info("value={}".format(value))
+ if "name" in active_context and value and "name" in value[0]:
+ if active_context["name"] == value[0].get('slave_name'):
+ data = dict(active_context)
+ data["wrapper_name"] = value[0]['name']
+ data["ip"] = value[0].get("ip", "NC")
+ data["port"] = value[0].get("external_port", "NC")
+ data["internal_port"] = value[0].get("port", "NC")
+ slaves.append(data)
+ break
+ return slaves
+ for ctx in contexts:
+ data = dict(ctx)
+ data["configured"] = False
+ for key, value in pods.items():
+ # logger.info("ctx={}".format(ctx))
+ # logger.info("value={}".format(value))
+ if "name" in ctx and value and "name" in value[0]:
+ if ctx["name"] == value[0].get('slave_name'):
+ data["wrapper_name"] = value[0]['name']
+ data["ip"] = value[0].get("ip", "NC")
+ data["port"] = value[0].get("external_port", "NC")
+ data["internal_port"] = value[0].get("port", "NC")
+ data["configured"] = True
+ break
+ slaves.append(data)
+ return slaves
+
+ @staticmethod
+ def get_contexts():
+ contexts, active_context = config.list_kube_config_contexts()
+ return contexts, active_context
+
+ def create_wrappers(self, slave_name=None):
+ contexts, active_context = self.get_contexts()
+ logger.debug("contexts: {}".format(contexts))
+ logger.debug("active_context: {}".format(active_context))
+ conf = configuration.get_configuration("components/wrapper")
+ hostname = conf["components/wrapper"].get(
+ "hostname", "wrapper")
+ port = conf["components/wrapper"].get("port", 80)
+ container = conf["components/wrapper"].get(
+ "container",
+ "wukongsun/moon_wrapper:v4.3")
+ for _ctx in contexts:
+ if slave_name and slave_name != _ctx['name']:
+ continue
+ _config = config.new_client_from_config(context=_ctx['name'])
+ logger.debug("_config={}".format(_config))
+ api_client = client.CoreV1Api(_config)
+ ext_client = client.ExtensionsV1beta1Api(_config)
+ data = [{
+ "name": hostname + "-" + get_random_name(),
+ "container": container,
+ "port": port,
+ "namespace": "moon",
+ "slave_name": _ctx['name']
+ }, ]
+ self.load_deployment_and_service(data, api_client, ext_client, expose=True)
+
+ def delete_wrapper(self, uuid=None, name=None, namespace="moon",
+ active_context=None,
+ active_context_name=None):
+ name_to_delete = None
+ if uuid and uuid in self.get_pods():
+ name_to_delete = self.get_pods()[uuid][0]['name']
+ elif name:
+ for pod_key, pod_list in self.get_pods().items():
+ for pod_value in pod_list:
+ if pod_value.get("name") == name:
+ name_to_delete = pod_value.get("name")
+ break
+ if not name_to_delete:
+ raise exceptions.WrapperUnknown
+ contexts, _active_context = self.get_contexts()
+ if active_context_name:
+ for _context in contexts:
+ if _context["name"] == active_context_name:
+ active_context = _context
+ break
+ if active_context:
+ active_context = _active_context
+ _config = config.new_client_from_config(
+ context=active_context['name'])
+ logger.debug("_config={}".format(_config))
+ api_client = client.CoreV1Api(_config)
+ ext_client = client.ExtensionsV1beta1Api(_config)
+ self.delete_deployment(name=name_to_delete, namespace=namespace,
+ ext_client=ext_client)
+ self.delete_service(name=name_to_delete, api_client=api_client)
+ return
+ logger.debug("contexts={}".format(contexts))
+ for _ctx in contexts:
+ _config = config.new_client_from_config(context=_ctx['name'])
+ logger.debug("_config={}".format(_config))
+ api_client = client.CoreV1Api(_config)
+ ext_client = client.ExtensionsV1beta1Api(_config)
+ self.delete_deployment(name=name_to_delete, namespace=namespace,
+ ext_client=ext_client)
+ self.delete_service(name=name_to_delete, api_client=api_client)
+
+ def create_pipeline(self, keystone_project_id,
+ pdp_id, policy_ids, manager_data=None,
+ active_context=None,
+ slave_name=None):
+ """ Create security functions
+
+ :param keystone_project_id: the Keystone project id
+ :param pdp_id: the PDP ID mapped to this pipeline
+ :param policy_ids: the policy IDs mapped to this pipeline
+ :param manager_data: data needed to create pods
+ :param active_context: if present, add the security function in this
+ context
+ :param slave_name: if present, add the security function in
+ this context name
+ if active_context_name and active_context are not present, add the
+ security function in all context (ie, in all slaves)
+ :return: None
+ """
+ if not manager_data:
+ manager_data = dict()
+ for key, value in self.get_pods().items():
+ for _pod in value:
+ if _pod.get('keystone_project_id') == keystone_project_id:
+ logger.warning("A pod for this Keystone project {} "
+ "already exists.".format(keystone_project_id))
+ return
+
+ plugins = configuration.get_plugins()
+ conf = configuration.get_configuration("components/pipeline")
+ # i_hostname = conf["components/pipeline"].get("interface").get("hostname", "interface")
+ i_port = conf["components/pipeline"].get("interface").get("port", 80)
+ i_container = conf["components/pipeline"].get("interface").get(
+ "container",
+ "wukongsun/moon_interface:v4.3")
+ data = [
+ {
+ "name": "pipeline-" + get_random_name(),
+ "container": i_container,
+ "port": i_port,
+ 'pdp_id': pdp_id,
+ 'genre': "interface",
+ 'keystone_project_id': keystone_project_id,
+ "namespace": "moon"
+ },
+ ]
+ logger.debug("data={}".format(data))
+ # When policies and models are empty, is it right that it returns 200 ?
+ # Should it return no found policies or models ?
+ policies = manager_data.get('policies')
+ if not policies:
+ logger.info("No policy data from Manager, trying to get them")
+ policies = requests.get("http://{}:{}/policies".format(
+ self.manager_hostname, self.manager_port)).json().get(
+ "policies", dict())
+ logger.debug("policies={}".format(policies))
+ models = manager_data.get('models')
+ if not models:
+ logger.info("No models data from Manager, trying to get them")
+ models = requests.get("http://{}:{}/models".format(
+ self.manager_hostname, self.manager_port)).json().get(
+ "models", dict())
+ logger.debug("models={}".format(models))
+
+ if not policy_ids:
+ raise exceptions.PolicyUnknown
+ for policy_id in policy_ids:
+ if policy_id in policies:
+ genre = policies[policy_id].get("genre", "authz")
+ if genre in plugins:
+ for meta_rule in models[policies[policy_id]['model_id']]['meta_rules']:
+ data.append({
+ "name": genre + "-" + get_random_name(),
+ "container": plugins[genre]['container'],
+ 'pdp_id': pdp_id,
+ "port": plugins[genre].get('port', 8080),
+ 'genre': genre,
+ 'policy_id': policy_id,
+ 'meta_rule_id': meta_rule,
+ 'keystone_project_id': keystone_project_id,
+ "namespace": "moon"
+ })
+ logger.debug("data={}".format(data))
+ contexts, _active_context = self.get_contexts()
+ logger.debug("active_context_name={}".format(slave_name))
+ logger.debug("active_context={}".format(active_context))
+ if slave_name:
+ for _context in contexts:
+ if _context["name"] == slave_name:
+ active_context = _context
+ break
+ if active_context:
+ active_context = _active_context
+ _config = config.new_client_from_config(
+ context=active_context['name'])
+ logger.debug("_config={}".format(_config))
+ api_client = client.CoreV1Api(_config)
+ ext_client = client.ExtensionsV1beta1Api(_config)
+ self.load_deployment_and_service(data, api_client, ext_client, expose=False)
+ return
+ logger.debug("contexts={}".format(contexts))
+ for _ctx in contexts:
+ if slave_name and slave_name != _ctx['name']:
+ continue
+ _config = config.new_client_from_config(context=_ctx['name'])
+ logger.debug("_config={}".format(_config))
+ api_client = client.CoreV1Api(_config)
+ ext_client = client.ExtensionsV1beta1Api(_config)
+ self.load_deployment_and_service(data, api_client, ext_client, expose=False)
+
+ def delete_pipeline(self, uuid=None, name=None, namespace="moon",
+ active_context=None,
+ active_context_name=None):
+ """Delete a pipeline
+
+ :param uuid:
+ :param name:
+ :param namespace:
+ :param active_context:
+ :param active_context_name:
+ :return:
+ """
+ name_to_delete = None
+ if uuid and uuid in self.get_pods():
+ name_to_delete = self.get_pods()[uuid][0]['name']
+ elif name:
+ for pod_key, pod_list in self.get_pods().items():
+ for pod_value in pod_list:
+ if pod_value.get("name") == name:
+ name_to_delete = pod_value.get("name")
+ break
+ if not name_to_delete:
+ raise exceptions.PipelineUnknown
+ logger.info("Will delete deployment and service named {}".format(name_to_delete))
+ contexts, _active_context = self.get_contexts()
+ if active_context_name:
+ for _context in contexts:
+ if _context["name"] == active_context_name:
+ active_context = _context
+ break
+ if active_context:
+ active_context = _active_context
+ _config = config.new_client_from_config(
+ context=active_context['name'])
+ logger.debug("_config={}".format(_config))
+ api_client = client.CoreV1Api(_config)
+ ext_client = client.ExtensionsV1beta1Api(_config)
+ self.delete_deployment(name=name_to_delete, namespace=namespace,
+ ext_client=ext_client)
+ self.delete_service(name=name_to_delete, api_client=api_client)
+ return
+ logger.debug("contexts={}".format(contexts))
+ for _ctx in contexts:
+ _config = config.new_client_from_config(context=_ctx['name'])
+ logger.debug("_config={}".format(_config))
+ api_client = client.CoreV1Api(_config)
+ ext_client = client.ExtensionsV1beta1Api(_config)
+ self.delete_deployment(name=name_to_delete, namespace=namespace,
+ ext_client=ext_client)
+ self.delete_service(name=name_to_delete, api_client=api_client)
+
+
+class Docker(Driver):
+
+ def get_slaves(self):
+ raise NotImplementedError
+
+ def create_wrappers(self):
+ raise NotImplementedError
+
+ def delete_wrapper(self, name):
+ raise NotImplementedError
+
+ def create_pipeline(self, keystone_project_id,
+ pdp_id, policy_ids, manager_data=None,
+ active_context=None,
+ active_context_name=None):
+ raise NotImplementedError
+
+ def delete_pipeline(self, uuid=None, name=None, namespace="moon",
+ active_context=None,
+ active_context_name=None):
+ raise NotImplementedError
diff --git a/old/moon_orchestrator/moon_orchestrator/http_server.py b/old/moon_orchestrator/moon_orchestrator/http_server.py
new file mode 100644
index 00000000..72e12358
--- /dev/null
+++ b/old/moon_orchestrator/moon_orchestrator/http_server.py
@@ -0,0 +1,167 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from flask import Flask, jsonify
+from flask_restful import Resource, Api
+import logging
+import requests
+import time
+from moon_orchestrator import __version__
+from moon_orchestrator.api.pods import Pods
+from moon_orchestrator.api.slaves import Slaves
+from moon_orchestrator.api.generic import Status
+from moon_orchestrator.drivers import get_driver
+from python_moonutilities import configuration, exceptions
+
+logger = logging.getLogger("moon.orchestrator.http_server")
+
+__API__ = (
+ Status,
+)
+
+
+class Server:
+ """Base class for HTTP server"""
+
+ def __init__(self, host="localhost", port=80, api=None, **kwargs):
+ """Run a server
+
+ :param host: hostname of the server
+ :param port: port for the running server
+ :param kwargs: optional parameters
+ :return: a running server
+ """
+ self._host = host
+ self._port = port
+ self._api = api
+ self._extra = kwargs
+
+ @property
+ def host(self):
+ return self._host
+
+ @host.setter
+ def host(self, name):
+ self._host = name
+
+ @host.deleter
+ def host(self):
+ self._host = ""
+
+ @property
+ def port(self):
+ return self._port
+
+ @port.setter
+ def port(self, number):
+ self._port = number
+
+ @port.deleter
+ def port(self):
+ self._port = 80
+
+ def run(self):
+ raise NotImplementedError()
+
+
+class Root(Resource):
+ """
+ The root of the web service
+ """
+ __urls__ = ("/",)
+ __methods = ("get", "post", "put", "delete", "options")
+
+ def get(self):
+ tree = {"/": {"methods": ("get",), "description": "List all methods for that service."}}
+ for item in __API__:
+ tree[item.__name__] = {"urls": item.__urls__}
+ _methods = []
+ for _method in self.__methods:
+ if _method in dir(item):
+ _methods.append(_method)
+ tree[item.__name__]["methods"] = _methods
+ tree[item.__name__]["description"] = item.__doc__.strip()
+ return {
+ "version": __version__,
+ "tree": tree
+ }
+
+
+class HTTPServer(Server):
+
+ def __init__(self, host="localhost", port=80, **kwargs):
+ super(HTTPServer, self).__init__(host=host, port=port, **kwargs)
+ self.app = Flask(__name__)
+ conf = configuration.get_configuration("components/orchestrator")
+ self.orchestrator_hostname = conf["components/orchestrator"].get("hostname", "orchestrator")
+ self.orchestrator_port = conf["components/orchestrator"].get("port", 80)
+ conf = configuration.get_configuration("components/manager")
+ self.manager_hostname = conf["components/manager"].get("hostname", "manager")
+ self.manager_port = conf["components/manager"].get("port", 80)
+ # TODO : specify only few urls instead of *
+ # CORS(self.app)
+ self.api = Api(self.app)
+ self.driver = get_driver()
+ logger.info("Driver = {}".format(self.driver.__class__))
+ self.__set_route()
+ self.__hook_errors()
+ pdp = None
+ while True:
+ try:
+ pdp = requests.get(
+ "http://{}:{}/pdp".format(self.manager_hostname,
+ self.manager_port))
+ except requests.exceptions.ConnectionError:
+ logger.warning("Manager is not ready, standby...")
+ time.sleep(1)
+ except KeyError:
+ logger.warning("Manager is not ready, standby...")
+ time.sleep(1)
+ else:
+ if "pdps" in pdp.json():
+ break
+ logger.debug("pdp={}".format(pdp))
+ # self.driver.create_wrappers()
+ for _pdp_key, _pdp_value in pdp.json()['pdps'].items():
+ if _pdp_value.get('keystone_project_id'):
+ # TODO: select context to add security function
+ self.driver.create_pipeline(
+ keystone_project_id=_pdp_value.get('keystone_project_id'),
+ pdp_id=_pdp_key,
+ policy_ids=_pdp_value.get('security_pipeline', []))
+
+ def __hook_errors(self):
+
+ def get_404_json(e):
+ return jsonify({"result": False, "code": 404, "description": str(e)}), 404
+
+ self.app.register_error_handler(404, get_404_json)
+
+ def get_400_json(e):
+ return jsonify({"result": False, "code": 400, "description": str(e)}), 400
+
+ self.app.register_error_handler(400, lambda e: get_400_json)
+ self.app.register_error_handler(403, exceptions.AuthException)
+
+ def __set_route(self):
+ self.api.add_resource(Root, '/')
+
+ for api in __API__:
+ self.api.add_resource(api, *api.__urls__)
+ self.api.add_resource(Pods, *Pods.__urls__,
+ resource_class_kwargs={
+ "driver": self.driver
+ })
+ self.api.add_resource(Slaves, *Slaves.__urls__,
+ resource_class_kwargs={
+ "driver": self.driver
+ })
+
+ def run(self):
+ self.app.run(host=self._host, port=self._port, threaded=True) # nosec
+
+ @staticmethod
+ def __filter_str(data):
+ return data.replace("@", "-")
diff --git a/old/moon_orchestrator/moon_orchestrator/server.py b/old/moon_orchestrator/moon_orchestrator/server.py
new file mode 100644
index 00000000..88d56e3a
--- /dev/null
+++ b/old/moon_orchestrator/moon_orchestrator/server.py
@@ -0,0 +1,39 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import logging
+from python_moonutilities import configuration, exceptions
+from moon_orchestrator.http_server import HTTPServer
+
+logger = logging.getLogger("moon.orchestrator.server")
+
+
+def create_server():
+ configuration.init_logging()
+ try:
+ conf = configuration.get_configuration("components/orchestrator")
+ hostname = conf["components/orchestrator"].get("hostname",
+ "orchestrator")
+ port = conf["components/orchestrator"].get("port", 80)
+ bind = conf["components/orchestrator"].get("bind", "127.0.0.1")
+ except exceptions.ConsulComponentNotFound:
+ hostname = "orchestrator"
+ bind = "127.0.0.1"
+ port = 80
+ configuration.add_component(uuid="orchestrator", name=hostname,
+ port=port, bind=bind)
+ logger.info("Starting server with IP {} on port {} bind to {}".format(
+ hostname, port, bind))
+ return HTTPServer(host=bind, port=port)
+
+
+def run():
+ server = create_server()
+ server.run()
+
+
+if __name__ == '__main__':
+ server = create_server()
+ server.run()
diff --git a/old/moon_orchestrator/requirements.txt b/old/moon_orchestrator/requirements.txt
new file mode 100644
index 00000000..dbb62043
--- /dev/null
+++ b/old/moon_orchestrator/requirements.txt
@@ -0,0 +1,7 @@
+flask
+flask_restful
+flask_cors
+werkzeug
+python_moonutilities
+kubernetes
+pyaml \ No newline at end of file
diff --git a/old/moon_orchestrator/setup.py b/old/moon_orchestrator/setup.py
new file mode 100644
index 00000000..494bd131
--- /dev/null
+++ b/old/moon_orchestrator/setup.py
@@ -0,0 +1,50 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from setuptools import setup, find_packages
+import moon_orchestrator
+
+
+with open('requirements.txt') as f:
+ required = f.read().splitlines()
+
+setup(
+
+ name='moon_orchestrator',
+
+ version=moon_orchestrator.__version__,
+
+ packages=find_packages(),
+
+ author="Thomas Duval",
+
+ author_email="thomas.duval@orange.com",
+
+ description="",
+
+ long_description=open('README.md').read(),
+
+ install_requires=required,
+
+ include_package_data=True,
+
+ url='https://git.opnfv.org/cgit/moon/',
+
+ classifiers=[
+ "Programming Language :: Python",
+ "Development Status :: 1 - Planning",
+ "License :: OSI Approved",
+ "Natural Language :: French",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python :: 3",
+ ],
+
+ entry_points={
+ 'console_scripts': [
+ 'moon_orchestrator = moon_orchestrator.server:run',
+ ],
+ }
+
+)
diff --git a/old/moon_orchestrator/tests/unit_python/conftest.py b/old/moon_orchestrator/tests/unit_python/conftest.py
new file mode 100644
index 00000000..044489e6
--- /dev/null
+++ b/old/moon_orchestrator/tests/unit_python/conftest.py
@@ -0,0 +1,18 @@
+import pytest
+import requests_mock
+import mock_pods
+from utilities import CONTEXT
+
+
+@pytest.fixture
+def context():
+ return CONTEXT
+
+
+@pytest.fixture(autouse=True)
+def no_requests(monkeypatch):
+ """ Modify the response from Requests module
+ """
+ with requests_mock.Mocker(real_http=True) as m:
+ mock_pods.register_pods(m)
+ yield m \ No newline at end of file
diff --git a/old/moon_orchestrator/tests/unit_python/mock_pods.py b/old/moon_orchestrator/tests/unit_python/mock_pods.py
new file mode 100644
index 00000000..59e1b3c0
--- /dev/null
+++ b/old/moon_orchestrator/tests/unit_python/mock_pods.py
@@ -0,0 +1,417 @@
+from kubernetes import client, config
+from utilities import CONF, get_b64_conf, COMPONENTS
+
+pdp_mock = {
+ "pdp_id1": {
+ "name": "...",
+ "security_pipeline": ["policy_id_1", "policy_id_2"],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ },
+ "pdp_id12": {
+ "name": "...",
+ "security_pipeline": ["policy_id_1", "policy_id_2"],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+}
+
+meta_rules_mock = {
+ "meta_rule_id1": {
+ "name": "meta_rule1",
+ "algorithm": "name of the meta rule algorithm",
+ "subject_categories": ["subject_category_id1",
+ "subject_category_id2"],
+ "object_categories": ["object_category_id1"],
+ "action_categories": ["action_category_id1"]
+ },
+ "meta_rule_id2": {
+ "name": "name of the meta rules2",
+ "algorithm": "name of the meta rule algorithm",
+ "subject_categories": ["subject_category_id1",
+ "subject_category_id2"],
+ "object_categories": ["object_category_id1"],
+ "action_categories": ["action_category_id1"]
+ }
+}
+
+policies_mock = {
+ "policy_id_1": {
+ "name": "test_policy1",
+ "model_id": "model_id_1",
+ "genre": "authz",
+ "description": "test",
+ },
+ "policy_id_2": {
+ "name": "test_policy2",
+ "model_id": "model_id_2",
+ "genre": "authz",
+ "description": "test",
+ }
+}
+
+subject_mock = {
+ "policy_id_1": {
+ "subject_id": {
+ "name": "subject_name",
+ "keystone_id": "keystone_project_id1",
+ "description": "a description"
+ }
+ },
+ "policy_id_2": {
+ "subject_id": {
+ "name": "subject_name",
+ "keystone_id": "keystone_project_id1",
+ "description": "a description"
+ }
+ }
+}
+
+subject_assignment_mock = {
+ "subject_id": {
+ "policy_id": "ID of the policy",
+ "subject_id": "ID of the subject",
+ "category_id": "ID of the category",
+ "assignments": [],
+ }
+}
+
+object_mock = {
+ "policy_id_1": {
+ "object_id": {
+ "name": "object_name",
+ "description": "a description"
+ }
+ },
+ "policy_id_2": {
+ "object_id": {
+ "name": "object_name",
+ "description": "a description"
+ }
+ }
+}
+
+object_assignment_mock = {
+ "object_id": {
+ "policy_id": "ID of the policy",
+ "object_id": "ID of the object",
+ "category_id": "ID of the category",
+ "assignments": [],
+ }
+}
+
+action_mock = {
+ "policy_id_1": {
+ "action_id": {
+ "name": "action_name",
+ "description": "a description"
+ }
+ },
+ "policy_id_2": {
+ "action_id": {
+ "name": "action_name",
+ "description": "a description"
+ }
+ }
+}
+
+action_assignment_mock = {
+ "action_id": {
+ "policy_id": "ID of the policy",
+ "action_id": "ID of the action",
+ "category_id": "ID of the category",
+ "assignments": [],
+ }
+}
+
+models_mock = {
+ "model_id_1": {
+ "name": "test_model",
+ "description": "test",
+ "meta_rules": ["meta_rule_id1"]
+ },
+ "model_id_2": {
+ "name": "test_model",
+ "description": "test",
+ "meta_rules": ["meta_rule_id2"]
+ },
+}
+
+rules_mock = {
+ "rules": {
+ "meta_rule_id": "meta_rule_id1",
+ "rule_id1": {
+ "rule": ["subject_data_id1",
+ "object_data_id1",
+ "action_data_id1"],
+ "instructions": (
+ {"decision": "grant"},
+ # "grant" to immediately exit,
+ # "continue" to wait for the result of next policy
+ # "deny" to deny the request
+ )
+ },
+ "rule_id2": {
+ "rule": ["subject_data_id2",
+ "object_data_id2",
+ "action_data_id2"],
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ # operations may be "add" or "delete"
+ "target": "rbac:role:admin"
+ # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}}
+ # chain with the policy named rbac
+ )
+ }
+ }
+}
+
+
+def patch_k8s(monkeypatch):
+ def _load_kube_config_mockreturn(*args, **kwargs):
+ return
+ monkeypatch.setattr(config, 'load_kube_config',
+ _load_kube_config_mockreturn)
+
+ def list_kube_config_contexts_mockreturn(*args, **kwargs):
+ return [{"name": "active_context"}], {"name": "active_context"}
+ monkeypatch.setattr(config, 'list_kube_config_contexts',
+ list_kube_config_contexts_mockreturn)
+
+ def new_client_from_config_mockreturn(*args, **kwargs):
+ return {"client": True}
+ monkeypatch.setattr(config, 'new_client_from_config',
+ new_client_from_config_mockreturn)
+
+ def list_pod_for_all_namespaces_mockreturn(*args, **kwargs):
+ class pods:
+ items = []
+ return pods
+ monkeypatch.setattr(client.CoreV1Api, 'list_pod_for_all_namespaces',
+ list_pod_for_all_namespaces_mockreturn)
+
+ def create_namespaced_deployment_mockreturn(*args, **kwargs):
+
+ class metadata:
+ uid = "123456789"
+
+ class pod:
+ def __init__(self):
+ self.metadata = metadata()
+ return pod()
+ monkeypatch.setattr(client.ExtensionsV1beta1Api,
+ 'create_namespaced_deployment',
+ create_namespaced_deployment_mockreturn)
+
+ def delete_namespaced_deployment_mockreturn(*args, **kwargs):
+ return None
+
+ monkeypatch.setattr(client.ExtensionsV1beta1Api,
+ 'delete_namespaced_deployment',
+ delete_namespaced_deployment_mockreturn)
+
+ def create_namespaced_service_mockreturn(*args, **kwargs):
+ return {}
+ monkeypatch.setattr(client.CoreV1Api,
+ 'create_namespaced_service',
+ create_namespaced_service_mockreturn)
+
+ def delete_namespaced_service_mockreturn(*args, **kwargs):
+ return {}
+ monkeypatch.setattr(client.CoreV1Api,
+ 'delete_namespaced_service',
+ delete_namespaced_service_mockreturn)
+
+
+def register_pods(m):
+ """ Modify the response from Requests module
+ """
+ register_consul(m)
+ register_pdp(m)
+ # register_meta_rules(m)
+ register_policies(m)
+ register_models(m)
+ # register_policy_subject(m, "policy_id_1")
+ # register_policy_subject(m, "policy_id_2")
+ # register_policy_object(m, "policy_id_1")
+ # register_policy_object(m, "policy_id_2")
+ # register_policy_action(m, "policy_id_1")
+ # register_policy_action(m, "policy_id_2")
+ # register_policy_subject_assignment(m, "policy_id_1", "subject_id")
+ # register_policy_subject_assignment_list(m1, "policy_id_1")
+ # register_policy_subject_assignment(m, "policy_id_2", "subject_id")
+ # register_policy_subject_assignment_list(m1, "policy_id_2")
+ # register_policy_object_assignment(m, "policy_id_1", "object_id")
+ # register_policy_object_assignment_list(m1, "policy_id_1")
+ # register_policy_object_assignment(m, "policy_id_2", "object_id")
+ # register_policy_object_assignment_list(m1, "policy_id_2")
+ # register_policy_action_assignment(m, "policy_id_1", "action_id")
+ # register_policy_action_assignment_list(m1, "policy_id_1")
+ # register_policy_action_assignment(m, "policy_id_2", "action_id")
+ # register_policy_action_assignment_list(m1, "policy_id_2")
+ # register_rules(m, "policy_id1")
+
+
+def register_consul(m):
+ for component in COMPONENTS:
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/{}'.format(component),
+ json=[{'Key': component, 'Value': get_b64_conf(component)}]
+ )
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/components/port_start',
+ json=[
+ {
+ "LockIndex": 0,
+ "Key": "components/port_start",
+ "Flags": 0,
+ "Value": "MzEwMDE=",
+ "CreateIndex": 9,
+ "ModifyIndex": 9
+ }
+ ],
+ )
+ m.register_uri(
+ 'PUT', 'http://consul:8500/v1/kv/components/port_start',
+ json=[],
+ )
+ # m.register_uri(
+ # 'GET', 'http://consul:8500/v1/kv/plugins?recurse=true',
+ # json=[
+ # {
+ # "LockIndex": 0,
+ # "Key": "plugins/authz",
+ # "Flags": 0,
+ # "Value": "eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0=",
+ # "CreateIndex": 14,
+ # "ModifyIndex": 656
+ # }
+ # ],
+ # )
+
+
+def register_pdp(m):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'pdp'),
+ json={'pdps': pdp_mock}
+ )
+
+
+def register_meta_rules(m):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'meta_rules'),
+ json={'meta_rules': meta_rules_mock}
+ )
+
+
+def register_policies(m):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies'),
+ json={'policies': policies_mock}
+ )
+
+
+def register_models(m):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'models'),
+ json={'models': models_mock}
+ )
+
+
+def register_policy_subject(m, policy_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/subjects'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies', policy_id),
+ json={'subjects': subject_mock[policy_id]}
+ )
+
+
+def register_policy_object(m, policy_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/objects'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies', policy_id),
+ json={'objects': object_mock[policy_id]}
+ )
+
+
+def register_policy_action(m, policy_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/actions'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies', policy_id),
+ json={'actions': action_mock[policy_id]}
+ )
+
+
+def register_policy_subject_assignment(m, policy_id, subj_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/subject_assignments/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies',
+ policy_id,
+ subj_id),
+ json={'subject_assignments': subject_assignment_mock}
+ )
+
+
+def register_policy_subject_assignment_list(m, policy_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/subject_assignments'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies',
+ policy_id),
+ json={'subject_assignments': subject_assignment_mock}
+ )
+
+
+def register_policy_object_assignment(m, policy_id, obj_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/object_assignments/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies',
+ policy_id,
+ obj_id),
+ json={'object_assignments': object_assignment_mock}
+ )
+
+
+def register_policy_object_assignment_list(m, policy_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/object_assignments'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies',
+ policy_id),
+ json={'object_assignments': object_assignment_mock}
+ )
+
+
+def register_policy_action_assignment(m, policy_id, action_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/action_assignments/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies',
+ policy_id,
+ action_id),
+ json={'action_assignments': action_assignment_mock}
+ )
+
+
+def register_policy_action_assignment_list(m, policy_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/action_assignments'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies',
+ policy_id),
+ json={'action_assignments': action_assignment_mock}
+ )
+
+
+def register_rules(m, policy_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/{}'.format(CONF['components']['manager']['hostname'],
+ CONF['components']['manager']['port'], 'policies',
+ policy_id, 'rules'),
+ json={'rules': rules_mock}
+ ) \ No newline at end of file
diff --git a/old/moon_orchestrator/tests/unit_python/requirements.txt b/old/moon_orchestrator/tests/unit_python/requirements.txt
new file mode 100644
index 00000000..21975ce3
--- /dev/null
+++ b/old/moon_orchestrator/tests/unit_python/requirements.txt
@@ -0,0 +1,5 @@
+flask
+flask_cors
+flask_restful
+python_moondb
+python_moonutilities \ No newline at end of file
diff --git a/old/moon_orchestrator/tests/unit_python/test_pods.py b/old/moon_orchestrator/tests/unit_python/test_pods.py
new file mode 100644
index 00000000..5e1b3767
--- /dev/null
+++ b/old/moon_orchestrator/tests/unit_python/test_pods.py
@@ -0,0 +1,287 @@
+import json
+from mock_pods import patch_k8s
+from utilities import get_json
+
+
+def test_get_pods(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ req = _client.get("/pods")
+ assert req.status_code == 200
+ assert req.data
+ data = get_json(req.data)
+ assert isinstance(data, dict)
+ assert "pods" in data
+ assert data["pods"]
+
+
+def test_get_pods_failure(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ req = _client.get("/pods/invalid")
+ assert req.status_code == 200
+ assert req.data
+ data = get_json(req.data)
+ assert isinstance(data, dict)
+ assert not data["pods"]
+
+############################ /post ############################
+
+def test_add_pods_with_pipeline(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ data = {
+ "keystone_project_id": context.get('project_id'),
+ "pdp_id": context.get('pdp_id'),
+ "security_pipeline": context.get('security_pipeline'),
+ }
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 200
+ assert req.data
+ data = get_json(req.data)
+ assert isinstance(data, dict)
+ assert "pods" in data
+ assert data["pods"]
+
+
+def test_add_pods_without_pipeline_with_bad_slave_name_failure(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ data = {
+ "slave_name": "test",
+ }
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert req.data
+ data = get_json(req.data)
+ assert isinstance(data, dict)
+ assert 'The slave is unknown.' in data['message']
+
+
+def test_add_pods_without_pipeline_with_good_slave_name(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ data = {
+ "slave_name": "active_context",
+ }
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 200
+ assert req.data
+ data = get_json(req.data)
+ assert isinstance(data, dict)
+ assert "pods" in data
+ assert data["pods"]
+
+
+def test_add_pods_without_pipeline_without_slave_name_failure(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ data = {
+ }
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert req.data
+ data = get_json(req.data)
+ assert isinstance(data, dict)
+ assert 'The slave is unknown.' in data['message']
+
+
+def test_add_pods_with_no_data_failure(context, monkeypatch):
+ patch_k8s(monkeypatch)
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ req = _client.post("/pods", data=json.dumps({}),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert req.data
+ data = get_json(req.data)
+ assert 'The slave is unknown.' in data['message']
+
+
+def test_add_pods_with_no_policies_no_models(context, monkeypatch, no_requests):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ no_requests.get("http://manager:8082/policies",
+ json={'policies': {}})
+
+ no_requests.get("http://manager:8082/models",
+ json={'models': {}})
+ data = {
+ "keystone_project_id": context.get('project_id'),
+ "pdp_id": context.get('pdp_id'),
+ "security_pipeline": context.get('security_pipeline'),
+ }
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 200
+
+
+def test_add_pods_with_empty_pdp_id_and_keystone_project_id_failure(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ data = {
+ "keystone_project_id": "",
+ "pdp_id": "",
+ "security_pipeline": context.get('security_pipeline'),
+ }
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert req.data
+ data = get_json(req.data)
+ assert "The pdp is unknown." in data['message']
+
+
+def test_add_pods_with_empty_security_pipeline_failure(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ data = {
+ "keystone_project_id": context.get('project_id'),
+ "pdp_id": context.get('pdp_id'),
+ "security_pipeline": "",
+ }
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 400
+ assert req.data
+ data = get_json(req.data)
+ assert 'The policy is unknown.' in data['message']
+
+
+def test_add_different_pods_with_same_pdp_id(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ data = {
+ "keystone_project_id": context.get('project_id'),
+ "pdp_id": context.get('pdp_id'),
+ "security_pipeline": context.get('security_pipeline'),
+ }
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ data["keystone_project_id"] = data["keystone_project_id"] + "x"
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 200
+
+
+def test_add_different_pods_with_same_keystone_project_id_failure(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ data = {
+ "keystone_project_id": context.get('project_id'),
+ "pdp_id": context.get('pdp_id'),
+ "security_pipeline": context.get('security_pipeline'),
+ }
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ data["pdp_id"] = data["pdp_id"] + "xyz"
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 409
+ data = get_json(req.data)
+ assert isinstance(data, dict)
+ assert 'A Pipeline already exist for the specified slave.' in data['message']
+
+
+def test_add_pod_with_slave_more_than_once_failure(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ data = {
+ "slave_name": "active_context",
+ }
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 409
+ assert req.data
+ data = get_json(req.data)
+ assert isinstance(data, dict)
+ assert 'A Wrapper already exist for the specified slave.' in data['message']
+
+############################ /delete ############################
+
+def test_delete_pod_valid_uuid(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ data = {
+ "keystone_project_id": context.get('project_id'),
+ "pdp_id": context.get('pdp_id'),
+ "security_pipeline": context.get('security_pipeline'),
+ }
+ req = _client.post("/pods", data=json.dumps(data),
+ headers={'Content-Type': 'application/json'})
+ assert req.status_code == 200
+ assert req.data
+ data = get_json(req.data)
+ for key in data["pods"]:
+ req = _client.delete("/pods/{}".format(key))
+ assert req.status_code == 200
+
+def test_delete_pod_Invalid_uuid_failure(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+
+ req = _client.delete("/pods/invalid")
+ assert req.status_code == 400
+ data = get_json(req.data)
+ assert 'The slave is unknown.' in data['message']
+
+def test_delete_pod_without_uuid_failure(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+
+ req = _client.delete("/pods/")
+ assert req.status_code == 400
+ data = get_json(req.data)
+ assert 'The slave is unknown.' in data['message'] \ No newline at end of file
diff --git a/old/moon_orchestrator/tests/unit_python/test_slaves.py b/old/moon_orchestrator/tests/unit_python/test_slaves.py
new file mode 100644
index 00000000..88ff7e55
--- /dev/null
+++ b/old/moon_orchestrator/tests/unit_python/test_slaves.py
@@ -0,0 +1,17 @@
+import json
+from mock_pods import patch_k8s
+from utilities import get_json
+
+
+def test_get_slaves(context, monkeypatch):
+ patch_k8s(monkeypatch)
+
+ import moon_orchestrator.server
+ server = moon_orchestrator.server.create_server()
+ _client = server.app.test_client()
+ req = _client.get("/slaves")
+ assert req.status_code == 200
+ assert req.data
+ data = get_json(req.data)
+ assert isinstance(data, dict)
+ assert "slaves" in data
diff --git a/old/moon_orchestrator/tests/unit_python/utilities.py b/old/moon_orchestrator/tests/unit_python/utilities.py
new file mode 100644
index 00000000..bc4aebcc
--- /dev/null
+++ b/old/moon_orchestrator/tests/unit_python/utilities.py
@@ -0,0 +1,171 @@
+import base64
+import json
+import pytest
+from uuid import uuid4
+
+
+CONF = {
+ "openstack": {
+ "keystone": {
+ "url": "http://keystone:5000/v3",
+ "user": "admin",
+ "check_token": False,
+ "password": "p4ssw0rd",
+ "domain": "default",
+ "certificate": False,
+ "project": "admin"
+ }
+ },
+ "components": {
+ "wrapper": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_wrapper:v4.3",
+ "timeout": 5,
+ "hostname": "wrapper"
+ },
+ "manager": {
+ "bind": "0.0.0.0",
+ "port": 8082,
+ "container": "wukongsun/moon_manager:v4.3",
+ "hostname": "manager"
+ },
+ "port_start": 31001,
+ "orchestrator": {
+ "bind": "0.0.0.0",
+ "port": 8083,
+ "container": "wukongsun/moon_orchestrator:v4.3",
+ "hostname": "interface"
+ },
+ "pipeline": {
+ "interface": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_interface:v4.3",
+ "hostname": "interface"
+ },
+ "authz": {
+ "bind": "0.0.0.0",
+ "port": 8081,
+ "container": "wukongsun/moon_authz:v4.3",
+ "hostname": "authz"
+ },
+ }
+ },
+ "logging": {
+ "handlers": {
+ "file": {
+ "filename": "/tmp/moon.log",
+ "class": "logging.handlers.RotatingFileHandler",
+ "level": "DEBUG",
+ "formatter": "custom",
+ "backupCount": 3,
+ "maxBytes": 1048576
+ },
+ "console": {
+ "class": "logging.StreamHandler",
+ "formatter": "brief",
+ "level": "INFO",
+ "stream": "ext://sys.stdout"
+ }
+ },
+ "formatters": {
+ "brief": {
+ "format": "%(levelname)s %(name)s %(message)-30s"
+ },
+ "custom": {
+ "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s"
+ }
+ },
+ "root": {
+ "handlers": [
+ "console"
+ ],
+ "level": "ERROR"
+ },
+ "version": 1,
+ "loggers": {
+ "moon": {
+ "handlers": [
+ "console",
+ "file"
+ ],
+ "propagate": False,
+ "level": "DEBUG"
+ }
+ }
+ },
+ "slave": {
+ "name": None,
+ "master": {
+ "url": None,
+ "login": None,
+ "password": None
+ }
+ },
+ "docker": {
+ "url": "tcp://172.88.88.1:2376",
+ "network": "moon"
+ },
+ "database": {
+ "url": "sqlite:///database.db",
+ # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon",
+ "driver": "sql"
+ },
+ "messenger": {
+ "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon"
+ }
+}
+
+
+CONTEXT = {
+ "project_id": "a64beb1cc224474fb4badd43173e7101",
+ "subject_name": "testuser",
+ "object_name": "vm1",
+ "action_name": "boot",
+ "request_id": uuid4().hex,
+ "interface_name": "interface",
+ "manager_url": "http://{}:{}".format(
+ CONF["components"]["manager"]["hostname"],
+ CONF["components"]["manager"]["port"]
+ ),
+ "cookie": uuid4().hex,
+ "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd",
+ "security_pipeline": ["f8f49a779ceb47b3ac810f01ef71b4e0"]
+ }
+
+
+COMPONENTS = (
+ "logging",
+ "openstack/keystone",
+ "database",
+ "slave",
+ "components/manager",
+ "components/orchestrator",
+ "components/pipeline",
+ "components/wrapper",
+)
+
+
+def get_b64_conf(component=None):
+ if component == "components":
+ return base64.b64encode(
+ json.dumps(CONF["components"]).encode('utf-8')+b"\n").decode('utf-8')
+ elif component in CONF:
+ return base64.b64encode(
+ json.dumps(
+ CONF[component]).encode('utf-8')+b"\n").decode('utf-8')
+ elif not component:
+ return base64.b64encode(
+ json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8')
+ elif "/" in component:
+ key1, _, key2 = component.partition("/")
+ return base64.b64encode(
+ json.dumps(
+ CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8')
+
+
+def get_json(data):
+ return json.loads(data.decode("utf-8"))
+
+
diff --git a/old/moon_pythonfunctest/Dockerfile b/old/moon_pythonfunctest/Dockerfile
new file mode 100644
index 00000000..8ae093b8
--- /dev/null
+++ b/old/moon_pythonfunctest/Dockerfile
@@ -0,0 +1,9 @@
+FROM python:3
+
+WORKDIR /usr/src/app
+RUN pip install --no-cache-dir --upgrade requests pytest pyyaml python_moonutilities python_moondb python_moonclient
+
+ADD . /root
+WORKDIR /root
+
+CMD /bin/bash /root/run_func_test.sh
diff --git a/old/moon_pythonfunctest/README.md b/old/moon_pythonfunctest/README.md
new file mode 100644
index 00000000..e2a4d14b
--- /dev/null
+++ b/old/moon_pythonfunctest/README.md
@@ -0,0 +1,8 @@
+# Python Functional Test Docker
+
+## Build
+- `docker image build -t wukongsun/moon_python_func_test .`
+
+## Push to DockerHub
+- `docker login --username=wukongsun`
+- `docker image push wukongsun/moon_python_func_test`
diff --git a/old/moon_pythonfunctest/run_func_test.sh b/old/moon_pythonfunctest/run_func_test.sh
new file mode 100755
index 00000000..acd0e1e9
--- /dev/null
+++ b/old/moon_pythonfunctest/run_func_test.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+echo "Running functional tests :"
+
+#ls -l /data
+ls -l /data/tests
+
+if [ -f /data/tests/functional_pod/run_functional_tests.sh ];
+then
+ echo "running script..."
+ bash /data/tests/functional_pod/run_functional_tests.sh;
+fi
+
+echo "<END OF JOB>"
+
diff --git a/old/moon_pythonunittest/Dockerfile b/old/moon_pythonunittest/Dockerfile
new file mode 100644
index 00000000..b8fb5151
--- /dev/null
+++ b/old/moon_pythonunittest/Dockerfile
@@ -0,0 +1,8 @@
+FROM python:3
+
+RUN pip install pytest requests_mock requests --upgrade
+ADD requirements.txt /root
+RUN pip install -r /root/requirements.txt --upgrade
+
+ADD run_tests.sh /root
+CMD ["sh", "/root/run_tests.sh"] \ No newline at end of file
diff --git a/old/moon_pythonunittest/README.md b/old/moon_pythonunittest/README.md
new file mode 100644
index 00000000..45d3a988
--- /dev/null
+++ b/old/moon_pythonunittest/README.md
@@ -0,0 +1,8 @@
+# Python Unit Test Docker
+
+## Build
+- `docker image build -t wukongsun/moon_python_unit_test .`
+
+## Push to DockerHub
+- `docker login --username=wukongsun`
+- `docker image push wukongsun/moon_python_unit_test` \ No newline at end of file
diff --git a/old/moon_pythonunittest/requirements.txt b/old/moon_pythonunittest/requirements.txt
new file mode 100644
index 00000000..fe107293
--- /dev/null
+++ b/old/moon_pythonunittest/requirements.txt
@@ -0,0 +1,11 @@
+kombu !=4.0.1,!=4.0.0
+oslo.messaging
+oslo.config
+oslo.log
+vine
+werkzeug
+flask
+requests
+pytest
+pytest-cov
+requests_mock
diff --git a/old/moon_pythonunittest/run_tests.sh b/old/moon_pythonunittest/run_tests.sh
new file mode 100644
index 00000000..285bd856
--- /dev/null
+++ b/old/moon_pythonunittest/run_tests.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+cd /data
+pip3 install -r tests/unit_python/requirements.txt --upgrade
+pip3 install .
+
+if [ -d /data/dist ];
+then
+ pip install /data/dist/*.tar.gz --upgrade
+ pip install /data/dist/*.whl --upgrade
+fi
+
+if [ -f /data/tests/unit_python/run_tests.sh ];
+then
+ bash /data/tests/unit_python/run_tests.sh;
+fi
+
+cd /data/tests/unit_python
+pytest --cov --cov-report term --cov-report html --cov-report xml .
diff --git a/old/moon_wrapper/Changelog b/old/moon_wrapper/Changelog
new file mode 100644
index 00000000..b2d62657
--- /dev/null
+++ b/old/moon_wrapper/Changelog
@@ -0,0 +1,47 @@
+# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+CHANGES
+=======
+
+1.0.0
+-----
+- First version of the manager
+
+2.0.0
+-----
+- Version built inside the Keystone component
+
+3.0.0
+-----
+- Version built outside the Keystone component
+
+4.0.0
+-----
+- First micro-architecture version
+
+4.5.1
+-----
+- use the threading capability of Flask app
+
+4.5.2
+-----
+- apply pylint rules
+
+4.5.3
+-----
+- Fix bug when OpenStack requests Moon
+ - bug on Keystone project ID
+ - bug when filtering the pipeline container name
+
+4.5.4
+-----
+- Fix a bug in retrieval of object from OpenStack
+- Fix a bug in rule element
+
+4.6.0
+-----
+- Add the Update API
diff --git a/old/moon_wrapper/Dockerfile b/old/moon_wrapper/Dockerfile
new file mode 100644
index 00000000..e3ad9020
--- /dev/null
+++ b/old/moon_wrapper/Dockerfile
@@ -0,0 +1,15 @@
+FROM python:3
+
+LABEL Name=Wrapper
+LABEL Description="Wrapper component for the Moon platform"
+LABEL Maintainer="Thomas Duval"
+LABEL Url="https://wiki.opnfv.org/display/moon/Moon+Project+Proposal"
+
+USER root
+
+ADD . /root
+WORKDIR /root/
+RUN pip3 install --no-cache-dir -r requirements.txt
+RUN pip3 install --no-cache-dir .
+
+CMD ["python3", "-m", "moon_wrapper"]
diff --git a/old/moon_wrapper/LICENSE b/old/moon_wrapper/LICENSE
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/old/moon_wrapper/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/old/moon_wrapper/MANIFEST.in b/old/moon_wrapper/MANIFEST.in
new file mode 100644
index 00000000..cf4d2e4e
--- /dev/null
+++ b/old/moon_wrapper/MANIFEST.in
@@ -0,0 +1,9 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+include README.md
+include LICENSE
+include setup.py
+include requirements.txt
diff --git a/old/moon_wrapper/README.md b/old/moon_wrapper/README.md
new file mode 100644
index 00000000..cdd043a9
--- /dev/null
+++ b/old/moon_wrapper/README.md
@@ -0,0 +1,8 @@
+# moon_wrapper
+
+This package contains the core module for the Moon project
+It is designed to provide authorization features to all OpenStack components.
+
+For any other information, refer to the parent project:
+
+ https://git.opnfv.org/moon
diff --git a/old/moon_wrapper/moon_wrapper/__init__.py b/old/moon_wrapper/moon_wrapper/__init__.py
new file mode 100644
index 00000000..f0887748
--- /dev/null
+++ b/old/moon_wrapper/moon_wrapper/__init__.py
@@ -0,0 +1,6 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+__version__ = "4.6.0"
diff --git a/old/moon_wrapper/moon_wrapper/__main__.py b/old/moon_wrapper/moon_wrapper/__main__.py
new file mode 100644
index 00000000..3a403293
--- /dev/null
+++ b/old/moon_wrapper/moon_wrapper/__main__.py
@@ -0,0 +1,4 @@
+from moon_wrapper.server import main
+
+SERVER = main()
+SERVER.run()
diff --git a/old/moon_wrapper/moon_wrapper/api/__init__.py b/old/moon_wrapper/moon_wrapper/api/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/moon_wrapper/moon_wrapper/api/__init__.py
diff --git a/old/moon_wrapper/moon_wrapper/api/generic.py b/old/moon_wrapper/moon_wrapper/api/generic.py
new file mode 100644
index 00000000..e492b327
--- /dev/null
+++ b/old/moon_wrapper/moon_wrapper/api/generic.py
@@ -0,0 +1,134 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Those API are helping API used to manage the Moon platform.
+"""
+
+import logging
+from flask_restful import Resource, request
+import moon_wrapper.api
+from python_moonutilities.security_functions import check_auth
+
+__version__ = "0.1.0"
+
+LOGGER = logging.getLogger("moon.manager.api." + __name__)
+
+
+class Status(Resource):
+ """
+ Endpoint for status requests
+ """
+
+ __urls__ = ("/status", "/status/", "/status/<string:component_id>")
+
+ def get(self, component_id=None):
+ """Retrieve status of all components
+
+ :return: {
+ "orchestrator": {
+ "status": "Running"
+ },
+ "security_router": {
+ "status": "Running"
+ }
+ }
+ """
+ raise NotImplementedError
+
+
+class Logs(Resource):
+ """
+ Endpoint for logs requests
+ """
+
+ __urls__ = ("/logs", "/logs/", "/logs/<string:component_id>")
+
+ def get(self, component_id=None):
+ """Get logs from the Moon platform
+
+ :param component_id: the ID of the component your are looking for (optional)
+ :return: [
+ "2015-04-15-13:45:20
+ "2015-04-15-13:45:21
+ "2015-04-15-13:45:22
+ "2015-04-15-13:45:23
+ ]
+ """
+ filter_str = request.args.get('filter', '')
+ from_str = request.args.get('from', '')
+ to_str = request.args.get('to', '')
+ event_number = request.args.get('event_number', '')
+ try:
+ event_number = int(event_number)
+ except ValueError:
+ event_number = None
+ args = dict()
+ args["filter"] = filter_str
+ args["from"] = from_str
+ args["to"] = to_str
+ args["event_number"] = event_number
+
+ raise NotImplementedError
+
+
+class API(Resource):
+ """
+ Endpoint for API requests
+ """
+
+ __urls__ = (
+ "/api",
+ "/api/",
+ "/api/<string:group_id>",
+ "/api/<string:group_id>/",
+ "/api/<string:group_id>/<string:endpoint_id>")
+
+ @check_auth
+ def get(self, group_id="", endpoint_id="", user_id=""):
+ """Retrieve all API endpoints or a specific endpoint if endpoint_id is given
+
+ :param group_id: the name of one existing group (ie generic, ...)
+ :param endpoint_id: the name of one existing component (ie Logs, Status, ...)
+ :return: {
+ "group_name": {
+ "endpoint_name": {
+ "description": "a description",
+ "methods": {
+ "get": "description of the HTTP method"
+ },
+ "urls": ('/api', '/api/', '/api/<string:endpoint_id>')
+ }
+ }
+ """
+ __methods = ("get", "post", "put", "delete", "options", "patch")
+ api_list = filter(lambda x: "__" not in x, dir(moon_wrapper.api))
+ api_desc = dict()
+ for api_name in api_list:
+ api_desc[api_name] = {}
+ group_api_obj = eval("moon_interface.api.{}".format(api_name))
+ api_desc[api_name]["description"] = group_api_obj.__doc__
+ if "__version__" in dir(group_api_obj):
+ api_desc[api_name]["version"] = group_api_obj.__version__
+ object_list = list(filter(lambda x: "__" not in x, dir(group_api_obj)))
+ for obj in map(lambda x: eval("moon_interface.api.{}.{}".format(api_name, x)),
+ object_list):
+ if "__urls__" in dir(obj):
+ api_desc[api_name][obj.__name__] = dict()
+ api_desc[api_name][obj.__name__]["urls"] = obj.__urls__
+ api_desc[api_name][obj.__name__]["methods"] = dict()
+ for _method in filter(lambda x: x in __methods, dir(obj)):
+ docstring = eval(
+ "moon_interface.api.{}.{}.{}.__doc__".format(api_name, obj.__name__,
+ _method))
+ api_desc[api_name][obj.__name__]["methods"][_method] = docstring
+ api_desc[api_name][obj.__name__]["description"] = str(obj.__doc__)
+ if group_id in api_desc:
+ if endpoint_id in api_desc[group_id]:
+ return {group_id: {endpoint_id: api_desc[group_id][endpoint_id]}}
+ elif len(endpoint_id) > 0:
+ LOGGER.error("Unknown endpoint_id {}".format(endpoint_id))
+ return {"error": "Unknown endpoint_id {}".format(endpoint_id)}
+ return {group_id: api_desc[group_id]}
+ return api_desc
diff --git a/old/moon_wrapper/moon_wrapper/api/oslowrapper.py b/old/moon_wrapper/moon_wrapper/api/oslowrapper.py
new file mode 100644
index 00000000..39128621
--- /dev/null
+++ b/old/moon_wrapper/moon_wrapper/api/oslowrapper.py
@@ -0,0 +1,127 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Authz is the endpoint to get authorization response
+"""
+
+import logging
+import json
+import flask
+from flask import request
+from flask_restful import Resource
+import requests
+from python_moonutilities import exceptions
+
+__version__ = "0.1.0"
+
+LOGGER = logging.getLogger("moon.wrapper.api." + __name__)
+
+
+class OsloWrapper(Resource):
+ """
+ Endpoint for authz requests
+ """
+
+ __urls__ = (
+ "/authz/oslo",
+ "/authz/oslo/",
+ )
+
+ def __init__(self, **kwargs):
+ self.port = kwargs.get("port")
+ self.CACHE = kwargs.get("cache", {})
+ self.TIMEOUT = 5
+
+ def post(self):
+ LOGGER.debug("POST {}".format(request.form))
+ response = flask.make_response("False")
+ try:
+ if self.manage_data():
+ response = flask.make_response("True")
+ except exceptions.AuthzException as exception:
+ LOGGER.error(exception, exc_info=True)
+ except Exception as exception:
+ LOGGER.error(exception, exc_info=True)
+
+ response.headers['content-type'] = 'application/octet-stream'
+ return response
+
+ @staticmethod
+ def __get_subject(target, credentials):
+ _subject = target.get("user_id", "")
+ if not _subject:
+ _subject = credentials.get("user_id", "none")
+ return _subject
+
+ @staticmethod
+ def __get_object(target, credentials):
+ try:
+ # note: case of Glance
+ return target['target']['name']
+ except KeyError:
+ pass
+
+ # note: default case
+ return "none"
+
+ @staticmethod
+ def __get_project_id(target, credentials):
+ project_id = target.get("project_id", None)
+ if not project_id:
+ project_id = credentials.get("project_id", None)
+ return project_id
+
+ def get_interface_url(self, project_id):
+ LOGGER.debug("project_id {}".format(project_id))
+ for containers in self.CACHE.containers.values():
+ LOGGER.info("containers {}".format(containers))
+ for container in containers:
+ if container.get("keystone_project_id") == project_id:
+ if "pipeline" in container['name']:
+ return "http://{}:{}".format(
+ container['name'],
+ container['port'])
+ self.CACHE.update()
+ # Note (asteroide): test an other time after the update
+ for containers in self.CACHE.containers.values():
+ for container in containers:
+ if container.get("keystone_project_id") == project_id:
+ if "pipeline" in container['name']:
+ return "http://{}:{}".format(
+ container['name'],
+ container['port'])
+ raise exceptions.AuthzException("Keystone Project "
+ "ID ({}) is unknown or not mapped "
+ "to a PDP.".format(project_id))
+
+ def manage_data(self):
+ data = request.form
+ if not dict(request.form):
+ data = json.loads(request.data.decode("utf-8"))
+ target = json.loads(data.get('target', {}))
+ credentials = json.loads(data.get('credentials', {}))
+ rule = data.get('rule', "").strip('"').strip("'")
+ _subject = self.__get_subject(target, credentials)
+ _object = self.__get_object(target, credentials)
+ _action = rule
+ LOGGER.info("authz {} {} {}".format(_subject, _object, _action))
+ _project_id = self.__get_project_id(target, credentials)
+ _pdp_id = self.CACHE.get_pdp_from_keystone_project(_project_id)
+ interface_url = self.get_interface_url(_project_id)
+ LOGGER.debug("interface_url={}".format(interface_url))
+ req = requests.get("{}/authz/{}/{}/{}/{}".format(
+ interface_url,
+ _pdp_id,
+ _subject,
+ _object,
+ _action
+ ))
+
+ LOGGER.debug("Get interface {}".format(req.text))
+ if req.status_code == 200:
+ if req.json().get("result", False):
+ return True
+
+ raise exceptions.AuthzException("error in authz request")
diff --git a/old/moon_wrapper/moon_wrapper/api/slaveupdate.py b/old/moon_wrapper/moon_wrapper/api/slaveupdate.py
new file mode 100644
index 00000000..b2ce22f0
--- /dev/null
+++ b/old/moon_wrapper/moon_wrapper/api/slaveupdate.py
@@ -0,0 +1,87 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+Authz is the endpoint to get authorization response
+"""
+
+import logging
+import json
+import flask
+from flask import request
+from flask_restful import Resource
+import requests
+from python_moonutilities import exceptions
+
+__version__ = "0.1.0"
+
+LOGGER = logging.getLogger("moon.wrapper.api." + __name__)
+
+
+class SlaveUpdate(Resource):
+ """
+ Endpoint for authz requests
+ """
+
+ __urls__ = (
+ "/update",
+ "/update/",
+ )
+
+ def __init__(self, **kwargs):
+ self.port = kwargs.get("port")
+ self.CACHE = kwargs.get("cache", {})
+ self.TIMEOUT = 5
+
+ def put(self):
+ LOGGER.warning("PUT {}".format(request.form))
+ response = flask.make_response("False")
+ try:
+ if self.update_slave():
+ response = flask.make_response("True")
+ except Exception as exception:
+ LOGGER.error(exception, exc_info=True)
+
+ response.headers['content-type'] = 'application/octet-stream'
+ return response
+
+ def get_interface_url(self, pdp_id):
+ LOGGER.debug("pdp_id {}".format(pdp_id))
+ for containers in self.CACHE.containers.values():
+ LOGGER.info("containers0 {}".format(containers))
+ for container in containers:
+ if container.get("pdp_id") == pdp_id:
+ if "pipeline" in container['name']:
+ yield "http://{}:{}".format(
+ container['name'],
+ container['port'])
+ self.CACHE.update()
+ # Note (asteroide): test an other time after the update
+ for containers in self.CACHE.containers.values():
+ LOGGER.info("containers1 {}".format(containers))
+ for container in containers:
+ if container.get("pdp_id") == pdp_id:
+ if "pipeline" in container['name']:
+ yield "http://{}:{}".format(
+ container['name'],
+ container['port'])
+
+ def update_slave(self):
+ result = {}
+ result_list = []
+ for _pdp_id in self.CACHE.pdp:
+ result[_pdp_id] = {}
+ for interface_url in self.get_interface_url(_pdp_id):
+
+ req = requests.put("{}/update".format(interface_url), request.form)
+
+ if req.status_code == 200:
+ if req.json().get("result", False):
+ result[_pdp_id][interface_url] = True
+ result_list.append(True)
+ continue
+ LOGGER.warning("Error in {} {}: {}".format(_pdp_id, interface_url, req.text))
+ result[_pdp_id][interface_url] = False
+ result_list.append(False)
+ return all(result_list)
diff --git a/old/moon_wrapper/moon_wrapper/http_server.py b/old/moon_wrapper/moon_wrapper/http_server.py
new file mode 100644
index 00000000..015bb285
--- /dev/null
+++ b/old/moon_wrapper/moon_wrapper/http_server.py
@@ -0,0 +1,144 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import flask
+from flask import Flask, jsonify
+from flask_restful import Resource, Api
+import logging
+from moon_wrapper import __version__
+from moon_wrapper.api.generic import Status, Logs, API
+from moon_wrapper.api.oslowrapper import OsloWrapper
+from moon_wrapper.api.slaveupdate import SlaveUpdate
+from python_moonutilities.cache import Cache
+from python_moonutilities import configuration, exceptions
+
+LOGGER = logging.getLogger("moon.wrapper.http_server")
+
+CACHE = Cache()
+
+__API__ = (
+ Status, Logs, API
+)
+
+
+class Server:
+ """Base class for HTTP server"""
+
+ def __init__(self, host="localhost", port=80, api=None, **kwargs):
+ """Run a server
+
+ :param host: hostname of the server
+ :param port: port for the running server
+ :param kwargs: optional parameters
+ :return: a running server
+ """
+ self._host = host
+ self._port = port
+ self._api = api
+ self._extra = kwargs
+
+ @property
+ def host(self):
+ return self._host
+
+ @host.setter
+ def host(self, name):
+ self._host = name
+
+ @host.deleter
+ def host(self):
+ self._host = ""
+
+ @property
+ def port(self):
+ return self._port
+
+ @port.setter
+ def port(self, number):
+ self._port = number
+
+ @port.deleter
+ def port(self):
+ self._port = 80
+
+ def run(self):
+ raise NotImplementedError()
+
+
+class Root(Resource):
+ """
+ The root of the web service
+ """
+ __urls__ = ("/",)
+ __methods = ("get", "post", "put", "delete", "options")
+
+ def get(self):
+ tree = {"/": {"methods": ("get",),
+ "description": "List all methods for that service."}}
+ for item in __API__:
+ tree[item.__name__] = {"urls": item.__urls__}
+ _methods = []
+ for _method in self.__methods:
+ if _method in dir(item):
+ _methods.append(_method)
+ tree[item.__name__]["methods"] = _methods
+ tree[item.__name__]["description"] = item.__doc__.strip()
+ return {
+ "version": __version__,
+ "tree": tree
+ }
+
+
+class HTTPServer(Server):
+
+ def __init__(self, host="localhost", port=80, **kwargs):
+ super(HTTPServer, self).__init__(host=host, port=port, **kwargs)
+ self.app = Flask(__name__)
+ self.port = port
+ conf = configuration.get_configuration("components/orchestrator")
+ _hostname = conf["components/orchestrator"].get("hostname",
+ "orchestrator")
+ _port = conf["components/orchestrator"].get("port", 80)
+ _protocol = conf["components/orchestrator"].get("protocol", "http")
+ self.orchestrator_url = "{}://{}:{}".format(
+ _protocol, _hostname, _port)
+ # Todo : specify only few urls instead of *
+ # CORS(self.app)
+ self.api = Api(self.app)
+ self.__set_route()
+ self.__hook_errors()
+
+ def __hook_errors(self):
+ def get_404_json(e):
+ return flask.make_response("False")
+
+ self.app.register_error_handler(404, get_404_json)
+
+ def get_400_json(e):
+ return flask.make_response("False")
+
+ self.app.register_error_handler(400, lambda e: get_400_json)
+ self.app.register_error_handler(403, exceptions.AuthException)
+
+ def __set_route(self):
+ self.api.add_resource(Root, '/')
+
+ for api in __API__:
+ self.api.add_resource(api, *api.__urls__)
+ self.api.add_resource(OsloWrapper, *OsloWrapper.__urls__,
+ resource_class_kwargs={
+ "orchestrator_url": self.orchestrator_url,
+ "cache": CACHE,
+ }
+ )
+ self.api.add_resource(SlaveUpdate, *SlaveUpdate.__urls__,
+ resource_class_kwargs={
+ "orchestrator_url": self.orchestrator_url,
+ "cache": CACHE,
+ }
+ )
+
+ def run(self):
+ self.app.run(host=self._host, port=self._port, threaded=True) # nosec
diff --git a/old/moon_wrapper/moon_wrapper/server.py b/old/moon_wrapper/moon_wrapper/server.py
new file mode 100644
index 00000000..77def174
--- /dev/null
+++ b/old/moon_wrapper/moon_wrapper/server.py
@@ -0,0 +1,32 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import logging
+from python_moonutilities import configuration, exceptions
+from moon_wrapper.http_server import HTTPServer
+
+LOG = logging.getLogger("moon.wrapper.server")
+
+
+def main():
+ configuration.init_logging()
+ try:
+ conf = configuration.get_configuration("components/wrapper")
+ LOG.debug("wrapper.conf={}".format(conf))
+ hostname = conf["components/wrapper"].get("hostname", "wrapper")
+ port = conf["components/wrapper"].get("port", 80)
+ bind = conf["components/wrapper"].get("bind", "127.0.0.1")
+ except exceptions.ConsulComponentNotFound:
+ hostname = "wrapper"
+ bind = "127.0.0.1"
+ port = 80
+ configuration.add_component(uuid="wrapper", name=hostname, port=port, bind=bind)
+ LOG.info("Starting server with IP {} on port {} bind to {}".format(hostname, port, bind))
+ return HTTPServer(host=bind, port=port)
+
+
+if __name__ == '__main__':
+ SERVER = main()
+ SERVER.run()
diff --git a/old/moon_wrapper/requirements.txt b/old/moon_wrapper/requirements.txt
new file mode 100644
index 00000000..c1bd9a2f
--- /dev/null
+++ b/old/moon_wrapper/requirements.txt
@@ -0,0 +1,5 @@
+flask
+flask_restful
+flask_cors
+werkzeug
+python_moonutilities \ No newline at end of file
diff --git a/old/moon_wrapper/setup.py b/old/moon_wrapper/setup.py
new file mode 100644
index 00000000..b6190c80
--- /dev/null
+++ b/old/moon_wrapper/setup.py
@@ -0,0 +1,47 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from setuptools import setup, find_packages
+import moon_wrapper
+
+
+setup(
+
+ name='moon_wrapper',
+
+ version=moon_wrapper.__version__,
+
+ packages=find_packages(),
+
+ author="Thomas Duval",
+
+ author_email="thomas.duval@orange.com",
+
+ description="",
+
+ long_description=open('README.md').read(),
+
+ # install_requires= ,
+
+ include_package_data=True,
+
+ url='https://git.opnfv.org/cgit/moon',
+
+ classifiers=[
+ "Programming Language :: Python",
+ "Development Status :: 1 - Planning",
+ "License :: OSI Approved",
+ "Natural Language :: French",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python :: 3",
+ ],
+
+ entry_points={
+ 'console_scripts': [
+ 'moon_wrapper = moon_wrapper.server:run',
+ ],
+ }
+
+)
diff --git a/old/moon_wrapper/tests/README.md b/old/moon_wrapper/tests/README.md
new file mode 100644
index 00000000..73a9fcd2
--- /dev/null
+++ b/old/moon_wrapper/tests/README.md
@@ -0,0 +1,35 @@
+# Tests
+
+## Python Unit Test for moon_db
+
+- launch Docker for Python unit tests
+
+
+ cd ${MOON_HOME}/moonv4/moon_db/
+ docker run -ti --volume ${PWD}:/data asteroide/moon_tests
+
+
+## Build and upload python packages
+
+- build python packages
+
+
+ python setup.py sdist bdist_wheel
+
+
+- upload moon_db to PIP
+
+
+ python setup.py upload
+
+
+or
+
+
+ gpg --detach-sign -u "${GPG_ID}" -a dist/moon_db-X.Y.Z-py3-none-any.whl
+ gpg --detach-sign -u "${GPG_ID}" -a dist/moon_db-X.Y.Z.tar.gz
+ twine upload dist/moon_db-X.Y.Z-py3-none-any.whl dist/moon_db-X.Y.Z-py3-none-any.whl.asc
+ twine upload dist/moon_db-X.Y.Z.tar.gz dist/moon_db-X.Y.Z.tar.gz.asc
+
+
+
diff --git a/old/moon_wrapper/tests/unit_python/api/__init__.py b/old/moon_wrapper/tests/unit_python/api/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/moon_wrapper/tests/unit_python/api/__init__.py
diff --git a/old/moon_wrapper/tests/unit_python/api/test_wrapper.py b/old/moon_wrapper/tests/unit_python/api/test_wrapper.py
new file mode 100644
index 00000000..bd6baf32
--- /dev/null
+++ b/old/moon_wrapper/tests/unit_python/api/test_wrapper.py
@@ -0,0 +1,72 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import json
+
+
+def get_json(data):
+ return json.loads(data.decode("utf-8"))
+
+
+def test_authz_true(context):
+ import moon_wrapper.server
+ server = moon_wrapper.server.main()
+ client = server.app.test_client()
+ _target = {
+ 'target': {
+ "name": context.get('object_name'),
+ },
+ "project_id": context.get('project_id'),
+ "user_id": context.get('subject_name')
+ }
+ authz_data = {
+ 'rule': context.get('action_name'),
+ 'target': json.dumps(_target),
+ 'credentials': 'null'}
+ req = client.post("/authz/oslo", data=json.dumps(authz_data))
+ assert req.status_code is 200
+ assert req.data
+ assert isinstance(req.data, bytes)
+ assert req.data == b"True"
+
+def test_authz_error_response_code(context):
+ import moon_wrapper.server
+ server = moon_wrapper.server.main()
+ client = server.app.test_client()
+ _target = {
+ 'target': {
+ "name": context.get('object_name'),
+ },
+ "project_id": context.get('invalid_project_id'),
+ "user_id": context.get('subject_name')
+ }
+ authz_data = {
+ 'rule': context.get('action_name'),
+ 'target': json.dumps(_target),
+ 'credentials': 'null'}
+ req = client.post("/authz/oslo", data=json.dumps(authz_data))
+ assert req.status_code is 200
+ assert req.data
+ assert isinstance(req.data, bytes)
+ assert req.data == b"False"
+
+def test_authz_error_no_interface_key(context):
+ import moon_wrapper.server
+ server = moon_wrapper.server.main()
+ client = server.app.test_client()
+ _target = {
+ 'target': {
+ "name": context.get('object_name'),
+ },
+ "project_id": context.get('project_with_no_interface_key'),
+ "user_id": context.get('subject_name')
+ }
+ authz_data = {
+ 'rule': context.get('action_name'),
+ 'target': json.dumps(_target),
+ 'credentials': 'null'}
+ req = client.post("/authz/oslo", data=json.dumps(authz_data))
+
+ assert req.data == b"False" \ No newline at end of file
diff --git a/old/moon_wrapper/tests/unit_python/conftest.py b/old/moon_wrapper/tests/unit_python/conftest.py
new file mode 100644
index 00000000..a6677849
--- /dev/null
+++ b/old/moon_wrapper/tests/unit_python/conftest.py
@@ -0,0 +1,722 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import base64
+import json
+import os
+import pickle
+import pytest
+import requests_mock
+from uuid import uuid4
+
+CONF = {
+ "openstack": {
+ "keystone": {
+ "url": "http://keystone:5000/v3",
+ "user": "admin",
+ "check_token": False,
+ "password": "p4ssw0rd", # nosec
+ "domain": "default",
+ "certificate": False,
+ "project": "admin"
+ }
+ },
+ "components": {
+ "wrapper": {
+ "bind": "0.0.0.0", # nosec
+ "port": 8080,
+ "container": "wukongsun/moon_wrapper:v4.3",
+ "timeout": 5,
+ "hostname": "wrapper"
+ },
+ "manager": {
+ "bind": "0.0.0.0", # nosec
+ "port": 8082,
+ "container": "wukongsun/moon_manager:v4.3",
+ "hostname": "manager"
+ },
+ "port_start": 31001,
+ "orchestrator": {
+ "bind": "0.0.0.0", # nosec
+ "port": 8083,
+ "container": "wukongsun/moon_orchestrator:v4.3",
+ "hostname": "orchestrator"
+ },
+ "interface": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_interface:v4.3",
+ "hostname": "interface"
+ }
+ },
+ "plugins": {
+ "session": {
+ "port": 8082,
+ "container": "asteroide/session:latest"
+ },
+ "authz": {
+ "port": 8081,
+ "container": "wukongsun/moon_authz:v4.3"
+ }
+ },
+ "logging": {
+ "handlers": {
+ "file": {
+ "filename": "/tmp/moon.log", # nosec
+ "class": "logging.handlers.RotatingFileHandler",
+ "level": "DEBUG",
+ "formatter": "custom",
+ "backupCount": 3,
+ "maxBytes": 1048576
+ },
+ "console": {
+ "class": "logging.StreamHandler",
+ "formatter": "brief",
+ "level": "INFO",
+ "stream": "ext://sys.stdout"
+ }
+ },
+ "formatters": {
+ "brief": {
+ "format": "%(levelname)s %(name)s %(message)-30s"
+ },
+ "custom": {
+ "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s"
+ }
+ },
+ "root": {
+ "handlers": [
+ "console"
+ ],
+ "level": "ERROR"
+ },
+ "version": 1,
+ "loggers": {
+ "moon": {
+ "handlers": [
+ "console",
+ "file"
+ ],
+ "propagate": False,
+ "level": "DEBUG"
+ }
+ }
+ },
+ "slave": {
+ "name": None,
+ "master": {
+ "url": None,
+ "login": None,
+ "password": None # nosec
+ }
+ },
+ "docker": {
+ "url": "tcp://172.88.88.1:2376",
+ "network": "moon"
+ },
+ "database": {
+ "url": "sqlite:///database.db",
+ # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon",
+ "driver": "sql"
+ },
+ "messenger": {
+ "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon"
+ }
+}
+
+COMPONENTS = (
+ "logging",
+ "openstack/keystone",
+ "database",
+ "slave",
+ "components/manager",
+ "components/orchestrator",
+ "components/interface",
+ "components/wrapper",
+)
+
+CONTEXT = {
+ "project_id": "a64beb1cc224474fb4badd43173e7101",
+ "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd",
+ "invalid_project_id" : "invalid_project_id",
+ "invalid_pdp_id": "invalid_pdp_id",
+ "project_with_no_interface_key" : "232399a4-de5f-11e7-8001-3863bbb766f3",
+ "subject_name": "testuser",
+ "object_name": "vm1",
+ "action_name": "boot",
+ "request_id": uuid4().hex,
+ "interface_name": "interface",
+ "manager_url": "http://{}:{}".format(
+ CONF["components"]["manager"]["hostname"],
+ CONF["components"]["manager"]["port"]
+ ),
+ "cookie": uuid4().hex
+ }
+
+
+def get_b64_conf(component=None):
+ if component == "components":
+ return base64.b64encode(
+ json.dumps(CONF["components"]).encode('utf-8')+b"\n").decode('utf-8')
+ elif component in CONF:
+ return base64.b64encode(
+ json.dumps(
+ CONF[component]).encode('utf-8')+b"\n").decode('utf-8')
+ elif not component:
+ return base64.b64encode(
+ json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8')
+ elif "/" in component:
+ key1, _, key2 = component.partition("/")
+ return base64.b64encode(
+ json.dumps(
+ CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8')
+
+
+MOCK_URLS = [
+ ('GET', 'http://consul:8500/v1/kv/components?recurse=true',
+ {'json': {"Key": key, "Value": get_b64_conf(key)}
+ for key in COMPONENTS}
+ ),
+ ('POST', 'http://keystone:5000/v3/auth/tokens',
+ {'headers': {'X-Subject-Token': "111111111"}}),
+ ('DELETE', 'http://keystone:5000/v3/auth/tokens',
+ {'headers': {'X-Subject-Token': "111111111"}}),
+ ('POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default',
+ {'json': {"users": {}}}),
+ ('GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default',
+ {'json': {"users": {}}}),
+ ('POST', 'http://keystone:5000/v3/users/',
+ {'json': {"users": [{
+ "id": "1111111111111"
+ }]}}),
+]
+
+
+@pytest.fixture
+def db():
+ return CONF['database']
+
+
+@pytest.fixture
+def context():
+ return CONTEXT
+
+
+def set_env_variables():
+ os.environ['UUID'] = "1111111111"
+ os.environ['TYPE'] = "authz"
+ os.environ['PORT'] = "8081"
+ os.environ['PDP_ID'] = "b3d3e18abf3340e8b635fd49e6634ccd"
+ os.environ['META_RULE_ID'] = "f8f49a779ceb47b3ac810f01ef71b4e0"
+ os.environ['KEYSTONE_PROJECT_ID'] = CONTEXT['project_id']
+
+
+def get_pickled_context():
+ from python_moonutilities.context import Context
+ from python_moonutilities.cache import Cache
+ CACHE = Cache()
+ CACHE.update()
+ _context = Context(context(), CACHE)
+ _context.increment_index()
+ _context.pdp_set['effect'] = 'grant'
+ _context.pdp_set[os.environ['META_RULE_ID']]['effect'] = 'grant'
+ return pickle.dumps(_context)
+
+
+@pytest.fixture(autouse=True)
+def set_consul_and_db(monkeypatch):
+ """ Modify the response from Requests module
+ """
+ set_env_variables()
+ with requests_mock.Mocker(real_http=True) as m:
+ for component in COMPONENTS:
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/{}'.format(component),
+ json=[{'Key': component, 'Value': get_b64_conf(component)}]
+ )
+ # for _data in MOCK_URLS:
+ # m.register_uri(_data[0], _data[1], **_data[2])
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/components?recurse=true',
+ json=[
+ {"Key": key, "Value": get_b64_conf(key)} for key in COMPONENTS
+ ],
+ )
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/plugins/authz',
+ json=[
+ {
+ "LockIndex": 0,
+ "Key": "plugins/authz",
+ "Flags": 0,
+ "Value": "eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0=",
+ "CreateIndex": 14,
+ "ModifyIndex": 656
+ }
+ ],
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/auth/tokens',
+ headers={'X-Subject-Token': "111111111"}
+ )
+ m.register_uri(
+ 'DELETE', 'http://keystone:5000/v3/auth/tokens',
+ headers={'X-Subject-Token': "111111111"}
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default',
+ json={"users": {}}
+ )
+ m.register_uri(
+ 'GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default',
+ json={"users": {}}
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/users/',
+ json={"users": [{
+ "id": "1111111111111"
+ }]}
+ )
+ m.register_uri(
+ 'GET', 'http://orchestrator:8083/pods',
+ json={
+ "pods": {
+ "721760dd-de5f-11e7-8001-3863bbb766f3": [
+ {
+ "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd",
+ "port": 8080,
+ "genre": "interface",
+ "name": "pipeline-paltry",
+ "keystone_project_id": "a64beb1cc224474fb4badd43173e7101",
+ "namespace": "moon",
+ "container": "wukongsun/moon_pipeline:v4.3"
+ },
+ {
+ "pdp_id": "b3d3e18abf3340e8b635fd49e6634ccd",
+ "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "port": 8081,
+ "genre": "authz",
+ "name": "authz-economic",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "keystone_project_id": "a64beb1cc224474fb4badd43173e7101",
+ "namespace": "moon",
+ "container": "wukongsun/moon_authz:v4.3"
+ },
+ {
+ "pdp_id": "invalid_pdp_id",
+ "port": 8080,
+ "genre": "interface",
+ "name": "pipeline-paltry",
+ "keystone_project_id": "invalid_project_id",
+ "namespace": "moon",
+ "container": "wukongsun/moon_authz:v4.3"
+ }
+ ],
+ "232399a4-de5f-11e7-8001-3863bbb766f3": [
+ {
+ "port": 8080,
+ "namespace": "moon",
+ "name": "wrapper-paltry",
+ "container": "wukongsun/moon_wrapper:v4.3.1"
+ }
+ ]
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://orchestrator:8083/pods/authz-economic',
+ json={
+ "pods": None
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/pdp',
+ json={
+ "pdps": {
+ "b3d3e18abf3340e8b635fd49e6634ccd": {
+ "description": "test",
+ "security_pipeline": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0"
+ ],
+ "name": "pdp_rbac",
+ "keystone_project_id": "a64beb1cc224474fb4badd43173e7101"
+ },
+ "invalid_pdp_id":{
+
+ "description": "test",
+ "security_pipeline": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0"
+ ],
+ "name": "pdp_rbac",
+ "keystone_project_id": "invalid_project_id"
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies',
+ json={
+ "policies": {
+ "f8f49a779ceb47b3ac810f01ef71b4e0": {
+ "name": "RBAC policy example",
+ "model_id": "cd923d8633ff4978ab0e99938f5153d6",
+ "description": "test",
+ "genre": "authz"
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/models',
+ json={
+ "models": {
+ "cd923d8633ff4978ab0e99938f5153d6": {
+ "name": "RBAC",
+ "meta_rules": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0"
+ ],
+ "description": "test"
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/meta_rules',
+ json={
+ "meta_rules": {
+ "f8f49a779ceb47b3ac810f01ef71b4e0": {
+ "subject_categories": [
+ "14e6ae0ba34d458b876c791b73aa17bd"
+ ],
+ "action_categories": [
+ "241a2a791554421a91c9f1bc564aa94d"
+ ],
+ "description": "",
+ "name": "rbac",
+ "object_categories": [
+ "6d48500f639d4c2cab2b1f33ef93a1e8"
+ ]
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/subjects',
+ json={
+ "subjects": {
+ "89ba91c18dd54abfbfde7a66936c51a6": {
+ "description": "test",
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ],
+ "name": "testuser",
+ "email": "mail",
+ "id": "89ba91c18dd54abfbfde7a66936c51a6",
+ "extra": {}
+ },
+ "31fd15ad14784a9696fcc887dddbfaf9": {
+ "description": "test",
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ],
+ "name": "adminuser",
+ "email": "mail",
+ "id": "31fd15ad14784a9696fcc887dddbfaf9",
+ "extra": {}
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/objects',
+ json={
+ "objects": {
+ "67b8008a3f8d4f8e847eb628f0f7ca0e": {
+ "name": "vm1",
+ "description": "test",
+ "id": "67b8008a3f8d4f8e847eb628f0f7ca0e",
+ "extra": {},
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ]
+ },
+ "9089b3d2ce5b4e929ffc7e35b55eba1a": {
+ "name": "vm0",
+ "description": "test",
+ "id": "9089b3d2ce5b4e929ffc7e35b55eba1a",
+ "extra": {},
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ]
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/actions',
+ json={
+ "actions": {
+ "cdb3df220dc05a6ea3334b994827b068": {
+ "name": "boot",
+ "description": "test",
+ "id": "cdb3df220dc04a6ea3334b994827b068",
+ "extra": {},
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ]
+ },
+ "cdb3df220dc04a6ea3334b994827b068": {
+ "name": "stop",
+ "description": "test",
+ "id": "cdb3df220dc04a6ea3334b994827b068",
+ "extra": {},
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ]
+ },
+ "9f5112afe9b34a6c894eb87246ccb7aa": {
+ "name": "start",
+ "description": "test",
+ "id": "9f5112afe9b34a6c894eb87246ccb7aa",
+ "extra": {},
+ "policy_list": [
+ "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "636cd473324f4c0bbd9102cb5b62a16d"
+ ]
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/subject_assignments',
+ json={
+ "subject_assignments": {
+ "826c1156d0284fc9b4b2ddb279f63c52": {
+ "category_id": "14e6ae0ba34d458b876c791b73aa17bd",
+ "assignments": [
+ "24ea95256c5f4c888c1bb30a187788df",
+ "6b227b77184c48b6a5e2f3ed1de0c02a",
+ "31928b17ec90438ba5a2e50ae7650e63",
+ "4e60f554dd3147af87595fb6b37dcb13",
+ "7a5541b63a024fa88170a6b59f99ccd7",
+ "dd2af27812f742029d289df9687d6126"
+ ],
+ "id": "826c1156d0284fc9b4b2ddb279f63c52",
+ "subject_id": "89ba91c18dd54abfbfde7a66936c51a6",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ },
+ "7407ffc1232944279b0cbcb0847c86f7": {
+ "category_id": "315072d40d774c43a89ff33937ed24eb",
+ "assignments": [
+ "6b227b77184c48b6a5e2f3ed1de0c02a",
+ "31928b17ec90438ba5a2e50ae7650e63",
+ "7a5541b63a024fa88170a6b59f99ccd7",
+ "dd2af27812f742029d289df9687d6126"
+ ],
+ "id": "7407ffc1232944279b0cbcb0847c86f7",
+ "subject_id": "89ba91c18dd54abfbfde7a66936c51a6",
+ "policy_id": "3e65256389b448cb9897917ea235f0bb"
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/object_assignments',
+ json={
+ "object_assignments": {
+ "201ad05fd3f940948b769ab9214fe295": {
+ "object_id": "9089b3d2ce5b4e929ffc7e35b55eba1a",
+ "assignments": [
+ "030fbb34002e4236a7b74eeb5fd71e35",
+ "06bcb8655b9d46a9b90e67ef7c825b50",
+ "34eb45d7f46d4fb6bc4965349b8e4b83",
+ "4b7793dbae434c31a77da9d92de9fa8c"
+ ],
+ "id": "201ad05fd3f940948b769ab9214fe295",
+ "category_id": "6d48500f639d4c2cab2b1f33ef93a1e8",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ },
+ "90c5e86f8be34c0298fbd1973e4fb043": {
+ "object_id": "67b8008a3f8d4f8e847eb628f0f7ca0e",
+ "assignments": [
+ "a098918e915b4b12bccb89f9a3f3b4e4",
+ "06bcb8655b9d46a9b90e67ef7c825b50",
+ "7dc76c6142af47c88b60cc2b0df650ba",
+ "4b7793dbae434c31a77da9d92de9fa8c"
+ ],
+ "id": "90c5e86f8be34c0298fbd1973e4fb043",
+ "category_id": "33aece52d45b4474a20dc48a76800daf",
+ "policy_id": "3e65256389b448cb9897917ea235f0bb"
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/action_assignments',
+ json={
+ "action_assignments": {
+ "2128e3ffbd1c4ef5be515d625745c2d4": {
+ "category_id": "241a2a791554421a91c9f1bc564aa94d",
+ "action_id": "cdb3df220dc05a6ea3334b994827b068",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "id": "2128e3ffbd1c4ef5be515d625745c2d4",
+ "assignments": [
+ "570c036781e540dc9395b83098c40ba7",
+ "7fe17d7a2e3542719f8349c3f2273182",
+ "015ca6f40338422ba3f692260377d638",
+ "23d44c17bf88480f83e8d57d2aa1ea79"
+ ]
+ },
+ "cffb98852f3a4110af7a0ddfc4e19201": {
+ "category_id": "4a2c5abaeaf644fcaf3ca8df64000d53",
+ "action_id": "cdb3df220dc04a6ea3334b994827b068",
+ "policy_id": "3e65256389b448cb9897917ea235f0bb",
+ "id": "cffb98852f3a4110af7a0ddfc4e19201",
+ "assignments": [
+ "570c036781e540dc9395b83098c40ba7",
+ "7fe17d7a2e3542719f8349c3f2273182",
+ "015ca6f40338422ba3f692260377d638",
+ "23d44c17bf88480f83e8d57d2aa1ea79"
+ ]
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/subject_assignments/89ba91c18dd54abfbfde7a66936c51a6',
+ json={
+ "subject_assignments": {
+ "826c1156d0284fc9b4b2ddb279f63c52": {
+ "category_id": "14e6ae0ba34d458b876c791b73aa17bd",
+ "assignments": [
+ "24ea95256c5f4c888c1bb30a187788df",
+ "6b227b77184c48b6a5e2f3ed1de0c02a",
+ "31928b17ec90438ba5a2e50ae7650e63",
+ "4e60f554dd3147af87595fb6b37dcb13",
+ "7a5541b63a024fa88170a6b59f99ccd7",
+ "dd2af27812f742029d289df9687d6126"
+ ],
+ "id": "826c1156d0284fc9b4b2ddb279f63c52",
+ "subject_id": "89ba91c18dd54abfbfde7a66936c51a6",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/object_assignments/67b8008a3f8d4f8e847eb628f0f7ca0e',
+ json={
+ "object_assignments": {
+ "201ad05fd3f940948b769ab9214fe295": {
+ "object_id": "67b8008a3f8d4f8e847eb628f0f7ca0e",
+ "assignments": [
+ "030fbb34002e4236a7b74eeb5fd71e35",
+ "06bcb8655b9d46a9b90e67ef7c825b50",
+ "34eb45d7f46d4fb6bc4965349b8e4b83",
+ "4b7793dbae434c31a77da9d92de9fa8c"
+ ],
+ "id": "201ad05fd3f940948b769ab9214fe295",
+ "category_id": "6d48500f639d4c2cab2b1f33ef93a1e8",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/action_assignments/cdb3df220dc05a6ea3334b994827b068',
+ json={
+ "action_assignments": {
+ "2128e3ffbd1c4ef5be515d625745c2d4": {
+ "category_id": "241a2a791554421a91c9f1bc564aa94d",
+ "action_id": "cdb3df220dc05a6ea3334b994827b068",
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "id": "2128e3ffbd1c4ef5be515d625745c2d4",
+ "assignments": [
+ "570c036781e540dc9395b83098c40ba7",
+ "7fe17d7a2e3542719f8349c3f2273182",
+ "015ca6f40338422ba3f692260377d638",
+ "23d44c17bf88480f83e8d57d2aa1ea79"
+ ]
+ }
+ }
+ }
+ )
+ m.register_uri(
+ 'GET', 'http://manager:8082/policies/f8f49a779ceb47b3ac810f01ef71b4e0/rules',
+ json={
+ "rules": {
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "rules": [
+ {
+ "policy_id": "f8f49a779ceb47b3ac810f01ef71b4e0",
+ "rule": [
+ "24ea95256c5f4c888c1bb30a187788df",
+ "030fbb34002e4236a7b74eeb5fd71e35",
+ "570c036781e540dc9395b83098c40ba7"
+ ],
+ "enabled": True,
+ "id": "0201a2bcf56943c1904dbac016289b71",
+ "instructions": [
+ {
+ "decision": "grant"
+ }
+ ],
+ "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ },
+ {
+ "policy_id": "ecc2451c494e47b5bca7250cd324a360",
+ "rule": [
+ "54f574cd2043468da5d65e4f6ed6e3c9",
+ "6559686961a3490a978f246ac9f85fbf",
+ "ac0d1f600bf447e8bd2f37b7cc47f2dc"
+ ],
+ "enabled": True,
+ "id": "a83fed666af8436192dfd8b3c83a6fde",
+ "instructions": [
+ {
+ "decision": "grant"
+ }
+ ],
+ "meta_rule_id": "f8f49a779ceb47b3ac810f01ef71b4e0"
+ }
+ ]
+ }
+ }
+ )
+ m.register_uri(
+ 'POST', 'http://127.0.0.1:8081/authz',
+ content=get_pickled_context()
+ )
+ m.register_uri(
+ 'GET', 'http://pipeline-paltry:8080/authz/{}/{}/{}/{}'.format(
+ CONTEXT.get("pdp_id"),
+ CONTEXT.get("subject_name"),
+ CONTEXT.get("object_name"),
+ CONTEXT.get("action_name"),
+ ),
+ json={"result": True, "message": "================"}
+ )
+ m.register_uri(
+ 'GET', 'http://pipeline-paltry:8080/authz/{}/{}/{}/{}'.format(
+ CONTEXT.get("invalid_pdp_id"),
+ CONTEXT.get("subject_name"),
+ CONTEXT.get("object_name"),
+ CONTEXT.get("action_name"),
+ ),
+ status_code=500
+ )
+ # from moon_db.db_manager import init_engine, run
+ # engine = init_engine()
+ # run("upgrade", logging.getLogger("db_manager"), engine)
+ yield m
+ # os.unlink(CONF['database']['url'].replace("sqlite:///", ""))
+
+
diff --git a/old/moon_wrapper/tests/unit_python/requirements.txt b/old/moon_wrapper/tests/unit_python/requirements.txt
new file mode 100644
index 00000000..21975ce3
--- /dev/null
+++ b/old/moon_wrapper/tests/unit_python/requirements.txt
@@ -0,0 +1,5 @@
+flask
+flask_cors
+flask_restful
+python_moondb
+python_moonutilities \ No newline at end of file
diff --git a/old/python_moonclient/.gitignore b/old/python_moonclient/.gitignore
new file mode 100644
index 00000000..9c29724f
--- /dev/null
+++ b/old/python_moonclient/.gitignore
@@ -0,0 +1,106 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+
+/tests/unit_python/database.db
diff --git a/old/python_moonclient/Changelog b/old/python_moonclient/Changelog
new file mode 100644
index 00000000..7cd14340
--- /dev/null
+++ b/old/python_moonclient/Changelog
@@ -0,0 +1,78 @@
+# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+CHANGES
+=======
+
+0.1.0
+-----
+- First version of the python-moonclient
+
+1.0.0
+-----
+- First public version of the python-moonclient
+
+1.0.1
+-----
+- Fix a bug in configuration
+
+1.1.0
+-----
+- Add some commands:
+ - moon_get_pdp
+ - moon_delete_pdp
+ - moon_delete_policy
+ - moon_map_pdp_to_project
+- Update some commands:
+ - moon_create_pdp
+ - moon_send_authz_to_wrapper
+- Fix a bug in pdp library
+
+1.2.0
+-----
+- Add some commands:
+ - moon_get_slaves
+ - moon_set_slave
+ - moon_delete_slave
+
+1.3.0
+-----
+- Base the cli on cliff library
+- Commands are:
+ - moon authz send
+ - moon pdp create
+ - moon pdp delete
+ - moon pdp list
+ - moon pdp map
+ - moon policy delete
+ - moon policy list
+ - moon project list
+ - moon slave delete
+ - moon slave list
+ - moon slave set
+
+1.4.0
+-----
+- Add some commands:
+ - moon import
+ - moon export
+ - moon subject category create
+ - moon subject category list
+ - moon object category list
+ - moon action category list
+ - moon subject data create
+ - moon subject data list
+ - moon object data list
+ - moon action data list
+ - moon metarule list
+
+1.4.1
+-----
+- Update exception during configuration
+
+1.4.2
+-----
+- apply PyLint rules \ No newline at end of file
diff --git a/old/python_moonclient/LICENSE b/old/python_moonclient/LICENSE
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/old/python_moonclient/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/old/python_moonclient/MANIFEST.in b/old/python_moonclient/MANIFEST.in
new file mode 100644
index 00000000..2a5ac509
--- /dev/null
+++ b/old/python_moonclient/MANIFEST.in
@@ -0,0 +1,10 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+include README.md
+include LICENSE
+include Changelog
+include setup.py
+include requirements.txt
diff --git a/old/python_moonclient/README.md b/old/python_moonclient/README.md
new file mode 100644
index 00000000..1a9731e7
--- /dev/null
+++ b/old/python_moonclient/README.md
@@ -0,0 +1,33 @@
+# python-moonclient
+This package contains the core module for the Moon project.
+It is designed to provide authorization feature to all OpenStack components.
+
+For any other information, refer to the parent project:
+
+ https://git.opnfv.org/moon
+
+python_moonutilities is a common Python lib for other Moon Python packages
+
+## Build
+### Build Python Package
+```bash
+cd ${MOON_HOME}/python_moonclient
+python3 setup.py sdist bdist_wheel
+```
+
+### Push Python Package to PIP
+```bash
+cd ${MOON_HOME}/python_moonclient
+gpg --detach-sign -u "${GPG_ID}" -a dist/python_moonclient-X.Y.Z-py3-none-any.whl
+gpg --detach-sign -u "${GPG_ID}" -a dist/python_moonclient-X.Y.Z.tar.gz
+twine upload dist/python_moonclient-X.Y.Z-py3-none-any.whl dist/python_moonclient-X.Y.Z-py3-none-any.whl.asc
+twine upload dist/python_moonclient-X.Y.Z.tar.gz dist/python_moonclient-X.Y.Z.tar.gz.asc
+```
+
+## Test
+### Python Unit Test
+launch Docker for Python unit tests
+```bash
+cd ${MOON_HOME}/python_moonclient
+docker run --rm --volume $(pwd):/data wukongsun/moon_python_unit_test:latest
+```
diff --git a/old/python_moonclient/python_moonclient/__init__.py b/old/python_moonclient/python_moonclient/__init__.py
new file mode 100644
index 00000000..bbd31082
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/__init__.py
@@ -0,0 +1,6 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+__version__ = "1.4.2"
diff --git a/old/python_moonclient/python_moonclient/cli/__init__.py b/old/python_moonclient/python_moonclient/cli/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/cli/__init__.py
diff --git a/old/python_moonclient/python_moonclient/cli/authz.py b/old/python_moonclient/python_moonclient/cli/authz.py
new file mode 100644
index 00000000..4edc307f
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/cli/authz.py
@@ -0,0 +1,55 @@
+import logging
+
+from importlib.machinery import SourceFileLoader
+from cliff.command import Command
+
+from python_moonclient.core import models, policies, pdp, authz
+from python_moonclient.cli.parser import Parser
+from python_moonclient.cli.projects import ProjectsUtils
+
+LOGGER = logging.getLogger("moonclient.cli.authz")
+
+
+class SendAuthz(Command):
+ """send authorizations to wrapper"""
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ Parser.add_filename_argument(parser)
+ Parser.add_id_or_name_project_argument(parser)
+ Parser.add_authz_arguments(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ if parsed_args.filename:
+ LOGGER.info("Loading: {}".format(parsed_args.filename))
+ m = SourceFileLoader("scenario", parsed_args.filename)
+ scenario = m.load_module()
+
+ keystone_project_id = ProjectsUtils.get_project_id(pdp, parsed_args.id_project,
+ parsed_args.name_project)
+ if keystone_project_id is None:
+ LOGGER.error("Project not found !")
+
+ keystone_project_id = pdp.get_keystone_id(keystone_project_id)
+ time_data = authz.send_requests(
+ scenario,
+ parsed_args.authz_host,
+ parsed_args.authz_port,
+ keystone_project_id,
+ request_second=parsed_args.request_second,
+ limit=parsed_args.limit,
+ dry_run=parsed_args.dry_run,
+ stress_test=parsed_args.stress_test,
+ destination=parsed_args.destination
+ )
+ if not parsed_args.dry_run:
+ authz.save_data(parsed_args.write, time_data)
diff --git a/old/python_moonclient/python_moonclient/cli/export.py b/old/python_moonclient/python_moonclient/cli/export.py
new file mode 100644
index 00000000..4ea5cf4f
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/cli/export.py
@@ -0,0 +1,32 @@
+import json
+
+from python_moonclient.core import models, policies, pdp, json_export
+from python_moonclient.cli.parser import Parser
+
+from cliff.command import Command
+
+
+class Export(Command):
+ """dump the complete moon database into a json file"""
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_filename_argument(parser)
+ Parser.add_common_options(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+ json_export.init(consul_host, consul_port)
+ res = json_export.export_to_json()
+ if "content" in res:
+ json_file = open(parsed_args.filename, "w")
+ json.dump(res["content"], json_file)
+ return "Export ok!"
+
+ return "Unexpected results : the returned json does not have the correct syntax"
diff --git a/old/python_moonclient/python_moonclient/cli/import.py b/old/python_moonclient/python_moonclient/cli/import.py
new file mode 100644
index 00000000..efefc304
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/cli/import.py
@@ -0,0 +1,28 @@
+from python_moonclient.core import models, policies, pdp, json_import
+from python_moonclient.cli.parser import Parser
+from python_moonclient.cli.projects import ProjectsUtils
+
+from cliff.command import Command
+
+
+class Import(Command):
+ """import a json file describing pdps """
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ Parser.add_filename_argument(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+ json_import.init(consul_host, consul_port)
+ res = json_import.import_json(parsed_args.filename)
+ if "message" in res:
+ return res["message"]
+ return res
diff --git a/old/python_moonclient/python_moonclient/cli/models.py b/old/python_moonclient/python_moonclient/cli/models.py
new file mode 100644
index 00000000..369d9027
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/cli/models.py
@@ -0,0 +1,159 @@
+import logging
+from importlib.machinery import SourceFileLoader
+from cliff.lister import Lister
+from cliff.command import Command
+from python_moonclient.core import models, policies, pdp
+from python_moonclient.cli.parser import Parser
+from python_moonclient.cli.projects import ProjectsUtils
+
+LOGGER = logging.getLogger("moonclient.cli.pdps")
+
+
+class ModelUtils:
+ def __init__(self):
+ pass
+
+ @staticmethod
+ def get_model_id(model, parsed_id, parsed_name):
+ modelz = models.check_model()
+ for _model_key, _model_value in modelz["models"].items():
+ if _model_key == parsed_id or _model_value['name'] == parsed_name:
+ # LOGGER.info(
+ # "Found pdp : [key='{}' , name='{}']".format(_pdp_key, _pdp_value['name']))
+ return _model_key
+ return None
+
+ @staticmethod
+ def get_model_name(pdp, parsed_id, parsed_name):
+ modelz = models.check_model()
+ for _model_key, _model_value in modelz["models"].items():
+ if _model_key == parsed_id or _model_value['name'] == parsed_name:
+ # LOGGER.info(
+ # "Found pdp : [key='{}' , name='{}']".format(_pdp_key, _pdp_value['name']))
+ return _model_value['name']
+ return None
+
+
+class Models(Lister):
+ """show the list of existing pdps """
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ modelz = models.check_model()
+
+ return (('Key', 'Name'),
+ ((_model_key, _model_value['name']) for _model_key, _model_value in
+ modelz["models"].items())
+ )
+
+
+class SubjectCategories(Lister):
+ """show the list of existing categories """
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ subject_categories = models.check_subject_category()
+ print(subject_categories)
+ return (('Key', 'Name'),
+ ((_model_key, _model_value['name']) for _model_key, _model_value in
+ subject_categories["subject_categories"].items())
+ )
+
+
+class ObjectCategories(Lister):
+ """show the list of existing categories """
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ object_categories = models.check_object_category()
+ print(object_categories)
+ return (('Key', 'Name'),
+ ((_model_key, _model_value['name']) for _model_key, _model_value in
+ object_categories["object_categories"].items())
+ )
+
+
+class ActionCategories(Lister):
+ """show the list of existing categories """
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ action_categories = models.check_action_category()
+ print(action_categories)
+ return (('Key', 'Name'),
+ ((_model_key, _model_value['name']) for _model_key, _model_value in
+ action_categories["action_categories"].items())
+ )
+
+
+class SubjectCategoryAdd(Command):
+ """show the list of existing categories """
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ Parser.add_name_argument(parser)
+
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ subject_category_id = models.add_subject_category(parsed_args.name)
+ if subject_category_id is not None:
+ print("Subject category created with id {}".format(subject_category_id))
+ else:
+ print("Error while creating subject category")
+ # subject_categories = models.check_subject_category(subject_category_id)
diff --git a/old/python_moonclient/python_moonclient/cli/parser.py b/old/python_moonclient/python_moonclient/cli/parser.py
new file mode 100644
index 00000000..e71cd6c9
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/cli/parser.py
@@ -0,0 +1,98 @@
+class Parser:
+
+ @staticmethod
+ def add_common_options(parser):
+ parser.add_argument('--consul-host',
+ help='Set the name of the consul server (default: 127.0.0.1)',
+ default="127.0.0.1")
+ parser.add_argument('--consul-port',
+ help='Set the port of the consult server (default: 30005)',
+ default="30005")
+ parser.add_argument("--verbose", "-v", action='store_true', help="verbose mode")
+ parser.add_argument("--debug", "-d", action='store_true', help="debug mode")
+
+ @staticmethod
+ def add_filename_argument(parser):
+ parser.add_argument('filename', help='configuration filename in json format')
+
+ @staticmethod
+ def add_name_argument(parser):
+ Parser._add_name_argument(parser)
+
+ @staticmethod
+ def add_policy_argument(parser):
+ group = parser.add_mutually_exclusive_group(required=True)
+ group.add_argument('--policy-name', help='name of the policy')
+ group.add_argument('--policy-id', help='id of the policy')
+
+ @staticmethod
+ def add_category_argument(parser):
+ group = parser.add_mutually_exclusive_group(required=True)
+ group.add_argument('--category-name', help='name of the category')
+ group.add_argument('--category-id', help='id of the category')
+
+ @staticmethod
+ def add_id_or_name_argument(parser):
+ group = parser.add_mutually_exclusive_group(required=True)
+ Parser._add_id_argument(group)
+ Parser._add_name_argument(group)
+
+ @staticmethod
+ def _add_id_argument(parser):
+ parser.add_argument('--id', help='id of the element')
+
+ @staticmethod
+ def _add_name_argument(parser):
+ parser.add_argument('--name', help='name of the element')
+
+ @staticmethod
+ def add_id_or_name_pdp_argument(parser):
+ group = parser.add_mutually_exclusive_group(required=True)
+ Parser._add_id_pdp_argument(group)
+ Parser._add_name_pdp_argument(group)
+
+ @staticmethod
+ def _add_id_pdp_argument(parser):
+ parser.add_argument('--id-pdp', help='id of the pdp')
+
+ @staticmethod
+ def _add_name_pdp_argument(parser):
+ parser.add_argument('--name-pdp', help='name of the pdp')
+
+ @staticmethod
+ def add_id_or_name_project_argument(parser):
+ group = parser.add_mutually_exclusive_group(required=True)
+ Parser._add_id_project_argument(group)
+ Parser._add_name_project_argument(group)
+
+ @staticmethod
+ def _add_id_project_argument(parser):
+ parser.add_argument('--id-project', help='id of the project')
+
+ @staticmethod
+ def _add_name_project_argument(parser):
+ parser.add_argument('--name-project', help='name of the project')
+
+ @staticmethod
+ def add_authz_arguments(parser):
+ parser.add_argument("--dry-run", "-n", action='store_true',
+ help="Dry run", dest="dry_run")
+ parser.add_argument("--destination",
+ help="Set the type of output needed "
+ "(default: wrapper, other possible type: "
+ "interface).",
+ default="wrapper")
+ parser.add_argument("--authz-host",
+ help="Set the name of the authz server to test"
+ "(default: 127.0.0.1).",
+ default="127.0.0.1")
+ parser.add_argument("--authz-port",
+ help="Set the port of the authz server to test"
+ "(default: 31002).",
+ default="31002")
+ parser.add_argument("--stress-test", "-s", action='store_true',
+ dest='stress_test',
+ help="Execute stressing tests (warning delta measures "
+ "will be false, implies -t)")
+ parser.add_argument("--write", "-w", help="Write test data to a JSON file",
+ default="/tmp/data.json")
diff --git a/old/python_moonclient/python_moonclient/cli/pdps.py b/old/python_moonclient/python_moonclient/cli/pdps.py
new file mode 100644
index 00000000..a4f7bba0
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/cli/pdps.py
@@ -0,0 +1,190 @@
+import logging
+from importlib.machinery import SourceFileLoader
+from cliff.lister import Lister
+from cliff.command import Command
+
+from python_moonclient.core import models, policies, pdp
+from python_moonclient.cli.parser import Parser
+from python_moonclient.cli.projects import ProjectsUtils
+
+LOGGER = logging.getLogger("moonclient.cli.pdps")
+
+
+class PdpUtils:
+ def __init__(self):
+ pass
+
+ @staticmethod
+ def get_pdp_id(pdp, parsed_id, parsed_name):
+ pdps = pdp.check_pdp()
+ for _pdp_key, _pdp_value in pdps["pdps"].items():
+ if _pdp_key == parsed_id or _pdp_value['name'] == parsed_name:
+ # LOGGER.info(
+ # "Found pdp : [key='{}' , name='{}']".format(_pdp_key, _pdp_value['name']))
+ return _pdp_key
+ return None
+
+ @staticmethod
+ def get_pdp_name(pdp, parsed_id, parsed_name):
+ pdps = pdp.check_pdp()
+ for _pdp_key, _pdp_value in pdps["pdps"].items():
+ if _pdp_key == parsed_id or _pdp_value['name'] == parsed_name:
+ # LOGGER.info(
+ # "Found pdp : [key='{}' , name='{}']".format(_pdp_key, _pdp_value['name']))
+ return _pdp_value['name']
+ return None
+
+
+class Pdps(Lister):
+ """show the list of existing pdps """
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ pdps = pdp.check_pdp()
+
+ return (('Key', 'Name', 'Project id'),
+ ((_pdp_key, _pdp_value['name'], _pdp_value['keystone_project_id']) for
+ _pdp_key, _pdp_value in pdps["pdps"].items())
+ )
+
+
+class CreatePdp(Command):
+ """create a new pdp from a json file and returns the newly created pdp id"""
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ Parser.add_filename_argument(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+
+ requests_log = logging.getLogger("requests.packages.urllib3")
+ requests_log.setLevel(logging.WARNING)
+ requests_log.propagate = True
+
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+ # project_id = args.keystone_pid
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ if parsed_args.filename:
+ LOGGER.info("Loading: {}".format(parsed_args.filename))
+ m = SourceFileLoader("scenario", parsed_args.filename)
+ scenario = m.load_module()
+
+ _models = models.check_model()
+ for _model_id, _model_value in _models['models'].items():
+ if _model_value['name'] == scenario.model_name:
+ model_id = _model_id
+ meta_rule_list = _model_value['meta_rules']
+ models.create_model(scenario, model_id)
+ break
+ else:
+ model_id, meta_rule_list = models.create_model(scenario)
+ policy_id = policies.create_policy(scenario, model_id, meta_rule_list)
+ pdp_id = pdp.create_pdp(scenario, policy_id=policy_id)
+ pdp_name = PdpUtils.get_pdp_name(pdp, pdp_id, None)
+ LOGGER.info("Pdp created : [id='{}', name='{}']".format(pdp_id, pdp_name))
+
+
+class DeletePdp(Command):
+ """delete an existing pdp"""
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ Parser.add_id_or_name_argument(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ _search = PdpUtils.get_pdp_id(pdp, parsed_args.id, parsed_args.name)
+ _pdp_key = _search
+ if _pdp_key is None:
+ LOGGER.error("Error pdp not found ")
+ return
+
+ # if parsed_args.id:
+ # logger.info("Deleting: {}".format(parsed_args.id))
+ # _search = parsed_args.id
+ # if parsed_args.name:
+ # logger.info("Deleting: {}".format(parsed_args.name))
+ # _search = parsed_args.name
+
+ # pdps = pdp.check_pdp()
+ # for _pdp_key, _pdp_value in pdps["pdps"].items():
+ # if _pdp_key == _search or _pdp_value['name'] == _search:
+ LOGGER.info("Found {}".format(_pdp_key))
+ pdp.delete_pdp(_pdp_key)
+
+ pdps = pdp.check_pdp()
+ LOGGER.info("Listing all PDP:")
+ for _pdp_key, _pdp_value in pdps["pdps"].items():
+ if _pdp_key == _search: # or _pdp_value['name'] == _search:
+ LOGGER.error("Error in deleting {}".format(_search))
+
+ return (('Key', 'Name', 'Project id'),
+ ((_pdp_key, _pdp_value['name'], _pdp_value['keystone_project_id']) for
+ _pdp_key, _pdp_value in
+ pdps["pdps"].items())
+ )
+
+
+class MapPdp(Command):
+ """map an existing pdp to a keystone project"""
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ Parser.add_id_or_name_pdp_argument(parser)
+ Parser.add_id_or_name_project_argument(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ # _pdp_key = PdpUtils.get_pdp_id(pdp, parsed_args.id_pdp, parsed_args.name_pdp)
+ _pdp_name = PdpUtils.get_pdp_name(pdp, parsed_args.id_pdp, parsed_args.name_pdp)
+ if _pdp_name is None:
+ LOGGER.error("Error pdp not found ")
+ return
+
+ # _project_key = ProjectsUtils.get_project_id(
+ # pdp, parsed_args.id_project, parsed_args.name_project)
+ _project_name = ProjectsUtils.get_project_name(pdp, parsed_args.id_project,
+ parsed_args.name_project)
+ if _project_name is None:
+ LOGGER.error("Error project not found ")
+ return
+
+ LOGGER.info("Mapping: {}=>{}".format(_pdp_name, _project_name))
+
+ # pdp.map_to_keystone(pdp_id=parsed_args.id_pdp, keystone_project_id=parsed_args.id_project)
+ pdp.map_to_keystone(pdp_id=_pdp_name, keystone_project_id=_project_name)
diff --git a/old/python_moonclient/python_moonclient/cli/policies.py b/old/python_moonclient/python_moonclient/cli/policies.py
new file mode 100644
index 00000000..af8e959b
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/cli/policies.py
@@ -0,0 +1,264 @@
+import logging
+from cliff.command import Command
+from cliff.lister import Lister
+
+from python_moonclient.cli.parser import Parser
+
+from python_moonclient.core import models, policies, pdp
+
+LOGGER = logging.getLogger("moonclient.cli.pdps")
+
+
+class PoliciesUtils:
+ def __init__(self):
+ pass
+
+ @staticmethod
+ def get_policy_id(policies, parsed_id, parsed_name):
+ _policies = policies.check_policy()
+ for _policy_key, _policy_value in _policies["policies"].items():
+ if _policy_key == parsed_id or _policy_value['name'] == parsed_name:
+ # logger.info("Found {}".format(_policy_key))
+ return _policy_key
+ return None
+
+ @staticmethod
+ def get_policy_name(policies, parsed_id, parsed_name):
+ _policies = policies.check_policy()
+ for _policy_key, _policy_value in _policies["policies"].items():
+ if _policy_key == parsed_id or _policy_value['name'] == parsed_name:
+ # logger.info("Found {}".format(_policy_key))
+ return _policy_value['name']
+ return None
+
+
+class Policies(Lister):
+ """show the list of existing policies"""
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+ _policies = policies.check_policy()
+
+ return (('Key', 'Name'),
+ ((_policy_key, _policy_value['name']) for _policy_key, _policy_value in
+ _policies["policies"].items())
+ )
+
+
+class Subjects(Lister):
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ Parser.add_id_or_name_argument(parser)
+ Parser.add_policy_argument(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ _policies = policies.check_subject(parsed_args.id, parsed_args.policy_id)
+
+ return (('Key', 'Name'),
+ ((_policy_key, _policy_value['name']) for _policy_key, _policy_value in
+ _policies["policies"].items())
+ )
+
+
+class DeletePolicy(Command):
+ """delete an existing policy"""
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ Parser.add_id_or_name_argument(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ policy_id = PoliciesUtils.get_policy_id(policies, parsed_args.id, parsed_args.name)
+ policy_name = PoliciesUtils.get_policy_name(policies, parsed_args.id, parsed_args.name)
+
+ LOGGER.info("Deleting: {}".format(policy_name))
+ pdp.delete_pdp(policy_id)
+
+ _policies = policies.check_policy()
+ # logger.info("Listing all Policies:")
+ for _policy_key, _policy_value in _policies["policies"].items():
+ # print(" {} {}".format(_policy_key, _policy_value['name']))
+ if _policy_key == policy_id:
+ LOGGER.error("Error in deleting {}".format(policy_id))
+
+ return (('Key', 'Value'),
+ ((_policy_key, _policy_value) for _policy_key, _policy_value in
+ _policies["policies"].items())
+ )
+
+
+class SubjectDatas(Lister):
+ """list the subject data """
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ Parser.add_policy_argument(parser)
+ Parser.add_category_argument(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ subject_data = policies.check_subject_data(parsed_args.policy_id, None,
+ parsed_args.category_id)
+ if len(subject_data["subject_data"]) == 0:
+ return (('Key', 'Name'), ())
+
+ return (('Key', 'Name'),
+ ((_subject_key, subject_data["subject_data"][0]["data"][_subject_key]['name']) for
+ _subject_key in subject_data["subject_data"][0]["data"].keys())
+ )
+
+
+class ObjectDatas(Lister):
+ """list the object data"""
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ Parser.add_policy_argument(parser)
+ Parser.add_category_argument(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ object_datas = policies.check_object_data(parsed_args.policy_id, None,
+ parsed_args.category_id)
+
+ if len(object_datas["object_data"]) == 0:
+ return (('Key', 'Name'), ())
+ object_data = object_datas["object_data"][0]["data"]
+ res = (('Key', 'Name'),
+ ((_object_key, object_data[_object_key]["value"]['name']) for _object_key in
+ list(object_data))
+ )
+ return res
+
+
+class ActionDatas(Lister):
+ """list the action data"""
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ Parser.add_policy_argument(parser)
+ Parser.add_category_argument(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ action_datas = policies.check_action_data(parsed_args.policy_id, None,
+ parsed_args.category_id)
+
+ if len(action_datas["action_data"]) == 0:
+ return (('Key', 'Name'), ())
+ action_data = action_datas["action_data"][0]["data"]
+ res = (('Key', 'Name'),
+ ((_action_key, action_data[_action_key]["value"]['name']) for _action_key in
+ list(action_data))
+ )
+ return res
+
+
+class MetaRules(Lister):
+ """list the meta rules"""
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ metarule_datas = policies.check_meta_rule()
+
+ if len(metarule_datas["meta_rules"]) == 0:
+ return (('Key', 'Name'), ())
+
+ metarule_data = metarule_datas["meta_rules"]
+ res = (('Key', 'Name'),
+ ((_key, metarule_data[_key]['name']) for _key in list(metarule_data))
+ )
+ return res
+
+
+class CreateSubjectData(Command):
+ """create a subject data according to a policy and a category"""
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ Parser.add_policy_argument(parser)
+ Parser.add_category_argument(parser)
+ Parser.add_name_argument(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ subject_data_id = policies.add_subject_data(parsed_args.policy_id, parsed_args.category_id,
+ parsed_args.name)
+ if subject_data_id is not None:
+ print("Subject category created with id {}".format(subject_data_id))
+ else:
+ print("Error while creating subject category")
+ subject_data = policies.check_subject_data(parsed_args.policy_id, None,
+ parsed_args.category_id)
+ # subject_categories = models.check_subject_category(subject_category_id)
diff --git a/old/python_moonclient/python_moonclient/cli/projects.py b/old/python_moonclient/python_moonclient/cli/projects.py
new file mode 100644
index 00000000..1caa0ace
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/cli/projects.py
@@ -0,0 +1,54 @@
+import logging
+from python_moonclient.core import models, policies, pdp
+from python_moonclient.cli.parser import Parser
+from cliff.lister import Lister
+
+LOGGER = logging.getLogger("moonclient.cli.projects")
+
+
+class ProjectsUtils:
+ def __init__(self):
+ pass
+
+ @staticmethod
+ def get_project_id(pdp, parsed_id, parsed_name):
+ projects = pdp.get_keystone_projects()
+ for _project_value in projects['projects']:
+ if _project_value['id'] == parsed_id or _project_value['name'] == parsed_name:
+ # LOGGER.info(
+ # "Found project : [key='{}' , name='{}']".format(_project_value['id'], _project_value['name']))
+ return _project_value['id']
+ return None
+
+ @staticmethod
+ def get_project_name(pdp, parsed_id, parsed_name):
+ projects = pdp.get_keystone_projects()
+ for _project_value in projects['projects']:
+ if _project_value['id'] == parsed_id or _project_value['name'] == parsed_name:
+ # LOGGER.info(
+ # "Found project : [key='{}' , name='{}']".format(_project_value['id'], _project_value['name']))
+ return _project_value['name']
+ return None
+
+
+class Projects(Lister):
+ """show the list of projects"""
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+
+ projects = pdp.get_keystone_projects()
+
+ return (('Id', 'Name'),
+ ((_project['id'], _project['name']) for _project in projects['projects'])
+ )
diff --git a/old/python_moonclient/python_moonclient/cli/slaves.py b/old/python_moonclient/python_moonclient/cli/slaves.py
new file mode 100644
index 00000000..587e9033
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/cli/slaves.py
@@ -0,0 +1,120 @@
+import logging
+from cliff.lister import Lister
+from cliff.command import Command
+
+from python_moonclient.core import models, policies, pdp, slaves
+from python_moonclient.cli.parser import Parser
+
+LOGGER = logging.getLogger("moonclient.cli.slaves")
+
+
+class SlavesUtils:
+ def __init__(self):
+ pass
+
+ @staticmethod
+ def get_slave_name(slaves, parsed_name):
+ _slaves = slaves.get_slaves()
+ for _slave_value in _slaves['slaves']:
+ if _slave_value['name'] == parsed_name:
+ LOGGER.info("Found {}".format(_slave_value['name']))
+ return _slave_value['name']
+ return None
+
+
+class Slaves(Lister):
+ """show the list of slaves"""
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ requests_log = logging.getLogger("requests.packages.urllib3")
+ requests_log.setLevel(logging.WARNING)
+ requests_log.propagate = True
+
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+ slaves.init(consul_host, consul_port)
+
+ return (('Name', 'Configured'),
+ ((value['name'], value['configured']) for value in
+ slaves.get_slaves().get('slaves', dict()))
+ )
+
+
+class SetSlave(Command):
+ """update an existing slave to a configured state"""
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ Parser.add_name_argument(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ requests_log = logging.getLogger("requests.packages.urllib3")
+ requests_log.setLevel(logging.WARNING)
+ requests_log.propagate = True
+
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+ slaves.init(consul_host, consul_port)
+
+ slave_input_name = parsed_args.name
+ if parsed_args.name is None:
+ slave_input_name = "kubernetes-admin@kubernetes"
+ slaves.set_slave(slave_input_name)
+
+ # if slave_name is None:
+ # slave_name = "kubernetes-admin@kubernetes"
+
+ # if parsed_args.name:
+ # slave_name = parsed_args.name
+ print(" {} (configured=True)".format(slave_input_name))
+
+ # for value in slaves.set_slave(slave_name).get('slaves', dict()):
+ # if value['configured']:
+ # print(" {} (configured)".format(value['name']))
+ # else:
+ # print(" {} (not configured)".format(value['name']))#
+
+
+class DeleteSlave(Command):
+ """update an existing slave to a unconfigured state"""
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+ Parser.add_common_options(parser)
+ Parser.add_name_argument(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ requests_log = logging.getLogger("requests.packages.urllib3")
+ requests_log.setLevel(logging.WARNING)
+ requests_log.propagate = True
+
+ consul_host = parsed_args.consul_host
+ consul_port = parsed_args.consul_port
+
+ models.init(consul_host, consul_port)
+ policies.init(consul_host, consul_port)
+ pdp.init(consul_host, consul_port)
+ slaves.init(consul_host, consul_port)
+
+ slave_input_name = parsed_args.name
+ if parsed_args.name is None:
+ slave_input_name = "kubernetes-admin@kubernetes"
+
+ slaves.delete_slave(slave_input_name)
+ print(" {} (configured=False)".format(slave_input_name))
diff --git a/old/python_moonclient/python_moonclient/core/__init__.py b/old/python_moonclient/python_moonclient/core/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/core/__init__.py
diff --git a/old/python_moonclient/python_moonclient/core/authz.py b/old/python_moonclient/python_moonclient/core/authz.py
new file mode 100644
index 00000000..d331004c
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/core/authz.py
@@ -0,0 +1,180 @@
+from uuid import uuid4
+import copy
+import logging
+import threading
+import time
+import json
+import random
+import requests
+
+HOST_MANAGER = None
+PORT_MANAGER = None
+HOST_KEYSTONE = None
+PORT_KEYSTONE = None
+
+LOCK = threading.Lock()
+LOGGER = logging.getLogger("moonclient.core.authz")
+
+
+def _construct_payload(creds, current_rule, enforcer, target):
+ # Convert instances of object() in target temporarily to
+ # empty dict to avoid circular reference detection
+ # errors in jsonutils.dumps().
+ temp_target = copy.deepcopy(target)
+ for key in target.keys():
+ element = target.get(key)
+ if type(element) is object:
+ temp_target[key] = {}
+ _data = _json = None
+ if enforcer:
+ _data = {'rule': current_rule,
+ 'target': json.dumps(temp_target),
+ 'credentials': json.dumps(creds)}
+ else:
+ _json = {'rule': current_rule,
+ 'target': temp_target,
+ 'credentials': creds}
+ return _data, _json
+
+
+def _send(url, data=None, stress_test=False):
+ current_request = dict()
+ current_request['url'] = url
+ try:
+ if stress_test:
+ current_request['start'] = time.time()
+ # with LOCK:
+ res = requests.get(url)
+ current_request['end'] = time.time()
+ current_request['delta'] = current_request["end"] - current_request["start"]
+ else:
+ with LOCK:
+ current_request['start'] = time.time()
+ if data:
+ data, _ = _construct_payload(data['credentials'], data['rule'], True,
+ data['target'])
+ res = requests.post(url, json=data,
+ headers={'content-type': "application/x-www-form-urlencode"}
+ )
+ else:
+ res = requests.get(url)
+ current_request['end'] = time.time()
+ current_request['delta'] = current_request["end"] - current_request["start"]
+ except requests.exceptions.ConnectionError:
+ LOGGER.warning("Unable to connect to server")
+ return {}
+ if not stress_test:
+ try:
+ j = res.json()
+ if res.status_code == 200:
+ LOGGER.warning("\033[1m{}\033[m \033[32mGrant\033[m".format(url))
+ elif res.status_code == 401:
+ LOGGER.warning("\033[1m{}\033[m \033[31mDeny\033[m".format(url))
+ else:
+ LOGGER.error("\033[1m{}\033[m {} {}".format(url, res.status_code, res.text))
+ except Exception as e:
+ if res.text == "True":
+ LOGGER.warning("\033[1m{}\033[m \033[32mGrant\033[m".format(url))
+ elif res.text == "False":
+ LOGGER.warning("\033[1m{}\033[m \033[31mDeny\033[m".format(url))
+ else:
+ LOGGER.error("\033[1m{}\033[m {} {}".format(url, res.status_code, res.text))
+ LOGGER.exception(e)
+ LOGGER.error(res.text)
+ else:
+ if j.get("result"):
+ # logger.warning("{} \033[32m{}\033[m".format(url, j.get("result")))
+ LOGGER.debug("{}".format(j.get("error", "")))
+ current_request['result'] = "Grant"
+ else:
+ # logger.warning("{} \033[31m{}\033[m".format(url, "Deny"))
+ LOGGER.debug("{}".format(j))
+ current_request['result'] = "Deny"
+ return current_request
+
+
+class AsyncGet(threading.Thread):
+
+ def __init__(self, url, semaphore=None, **kwargs):
+ threading.Thread.__init__(self)
+ self.url = url
+ self.kwargs = kwargs
+ self.sema = semaphore
+ self.result = dict()
+ self.uuid = uuid4().hex
+ self.index = kwargs.get("index", 0)
+
+ def run(self):
+ self.result = _send(self.url,
+ data=self.kwargs.get("data"),
+ stress_test=self.kwargs.get("stress_test", False))
+ self.result['index'] = self.index
+
+
+def send_requests(scenario, authz_host, authz_port, keystone_project_id, request_second=1,
+ limit=500,
+ dry_run=None, stress_test=False, destination="wrapper"):
+ backgrounds = []
+ time_data = list()
+ start_timing = time.time()
+ request_cpt = 0
+ subjects = tuple(scenario.subjects.keys())
+ objects = tuple(scenario.objects.keys())
+ actions = tuple(scenario.actions.keys())
+ while request_cpt < limit:
+ rule = (random.choice(subjects), random.choice(objects), random.choice(actions))
+ if destination.lower() == "wrapper":
+ url = "http://{}:{}/authz/oslo".format(authz_host, authz_port)
+ data = {
+ 'target': {
+ "user_id": random.choice(subjects),
+ "target": {
+ "name": random.choice(objects)
+ },
+ "project_id": keystone_project_id
+ },
+ 'credentials': None,
+ 'rule': random.choice(actions)
+ }
+ else:
+ url = "http://{}:{}/authz/{}/{}".format(authz_host, authz_port, keystone_project_id,
+ "/".join(rule))
+ data = None
+ if dry_run:
+ LOGGER.info(url)
+ continue
+ request_cpt += 1
+ if stress_test:
+ time_data.append(copy.deepcopy(_send(url, stress_test=stress_test)))
+ else:
+ background = AsyncGet(url, stress_test=stress_test, data=data,
+ index=request_cpt)
+ backgrounds.append(background)
+ background.start()
+ if request_second > 0:
+ if request_cpt % request_second == 0:
+ if time.time() - start_timing < 1:
+ while True:
+ if time.time() - start_timing > 1:
+ break
+ start_timing = time.time()
+ if not stress_test:
+ for background in backgrounds:
+ background.join()
+ if background.result:
+ time_data.append(copy.deepcopy(background.result))
+ return time_data
+
+
+def save_data(filename, time_data):
+ json.dump(time_data, open(filename, "w"))
+
+
+def get_delta(time_data):
+ time_delta = list()
+ time_delta_sum1 = 0
+ for item in time_data:
+ time_delta.append(item['delta'])
+ time_delta_sum1 += item['delta']
+ time_delta_average1 = time_delta_sum1 / len(time_data)
+ return time_delta, time_delta_average1
diff --git a/old/python_moonclient/python_moonclient/core/check_tools.py b/old/python_moonclient/python_moonclient/core/check_tools.py
new file mode 100644
index 00000000..381e92c7
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/core/check_tools.py
@@ -0,0 +1,458 @@
+from python_moonclient.core.cli_exceptions import MoonCliException
+
+
+def check_optionnal_result(result):
+ if type(result) is not dict:
+ raise MoonCliException("Unexpected request result. It should be a dictionnary")
+ if "result" in result:
+ check_result(result)
+
+
+def check_result(result):
+ if type(result) is not dict or "result" not in result:
+ raise MoonCliException(
+ "Unexpected request result. It should be a dictionnary with a 'result' entry")
+ if result["result"] is None:
+ raise MoonCliException("Unexpected request result. The 'result' entry shall not be null")
+
+
+def _check_generic_in_result(field, result, check_not_null=False):
+ if type(field) is not str or type(result) is not dict or field not in result:
+ raise MoonCliException(
+ "Unexpected request result. It should be a dictionnary with a '{}' entry".format(field))
+ if check_not_null is True and result[field] is None:
+ raise MoonCliException(
+ "Unexpected request result. The '{}' entry shall not be null".format(field))
+
+
+def check_slaves_in_result(result):
+ _check_generic_in_result("slaves", result)
+
+
+def check_pdp_in_result(result):
+ _check_generic_in_result("pdps", result)
+
+
+def check_model_in_result(result, check_not_null=False):
+ _check_generic_in_result("models", result)
+ if check_not_null is True and result["models"] is None:
+ raise MoonCliException("Unexpected request result. The 'models' entry shall not be null")
+
+
+def check_meta_rule_in_result(result):
+ _check_generic_in_result("meta_rules", result)
+
+
+def check_rule_in_result(result):
+ _check_generic_in_result("rules", result)
+
+
+def check_subject_in_result(result):
+ _check_generic_in_result("subjects", result)
+
+
+def check_subject_category_in_result(result):
+ _check_generic_in_result("subject_categories", result)
+
+
+def check_object_category_in_result(result):
+ _check_generic_in_result("object_categories", result)
+
+
+def check_action_category_in_result(result):
+ _check_generic_in_result("action_categories", result)
+
+
+def check_policy_in_result(result):
+ _check_generic_in_result("policies", result)
+
+
+def check_object_in_result(result):
+ _check_generic_in_result("objects", result)
+
+
+def check_action_in_result(result):
+ _check_generic_in_result("actions", result)
+
+
+def check_subject_assignment_in_result(result):
+ _check_generic_in_result("subject_assignments", result, True)
+
+
+def check_object_assignment_in_result(result):
+ _check_generic_in_result("object_assignments", result, True)
+
+
+def check_action_assignment_in_result(result):
+ _check_generic_in_result("action_assignments", result, True)
+
+
+def check_pdp_id(pdp_id, result):
+ check_pdp_in_result(result)
+ if pdp_id not in result['pdps']:
+ raise MoonCliException("Unexpected request result. Unknown pdp id")
+
+
+def _check_generic_name(field, name, field_elt_id, result, do_check_name=True):
+ if type(field) is str:
+ if result[field] is None:
+ raise MoonCliException(
+ "Unexpected request result : {} shall not be empty".format(field))
+ if field_elt_id not in result[field]:
+ raise MoonCliException("Unexpected request result. Unknown {} id".format(field))
+ if "name" not in result[field][field_elt_id]:
+ raise MoonCliException(
+ "Unexpected request result : {} with id {} has no name".format(field, field_elt_id))
+ if do_check_name and name != result[field][field_elt_id]["name"]:
+ raise MoonCliException(
+ "Unexpected request result : {} with id {} has a bad name. Expected {}".format(
+ field, field_elt_id, name))
+
+
+def check_model_name(name, model_id, result, do_check_name):
+ _check_generic_name("models", name, model_id, result, do_check_name)
+
+
+def check_pdp_name(name, pdp_id, result):
+ _check_generic_name("pdps", name, pdp_id, result)
+
+
+def check_subject_categories_name(name, category_id, result):
+ _check_generic_name("subject_categories", name, category_id, result)
+
+
+def check_object_categories_name(name, category_id, result):
+ _check_generic_name("object_categories", name, category_id, result)
+
+
+def check_action_categories_name(name, category_id, result):
+ _check_generic_name("action_categories", name, category_id, result)
+
+
+def check_meta_rules_name(name, meta_rule_id, result):
+ _check_generic_name("meta_rules", name, meta_rule_id, result, False)
+
+
+def check_policy_name(name, policy_id, result):
+ _check_generic_name("policies", name, policy_id, result)
+
+
+def check_subject_name(name, subject_id, result):
+ _check_generic_name("subjects", name, subject_id, result)
+
+
+def check_object_name(name, object_id, result):
+ _check_generic_name("objects", name, object_id, result)
+
+
+def check_action_name(name, action_id, result):
+ _check_generic_name("actions", name, action_id, result)
+
+
+def check_scat_id_in_dict(scat_id, in_dict):
+ if scat_id not in in_dict:
+ raise MoonCliException("Unexpected request result. Subject category not in result")
+
+
+def check_ocat_id_in_dict(ocat_id, in_dict):
+ if ocat_id not in in_dict:
+ raise MoonCliException("Unexpected request result. Object category not in result")
+
+
+def check_acat_id_in_dict(acat_id, in_dict):
+ if acat_id not in in_dict:
+ raise MoonCliException("Unexpected request result. Action category not in result")
+
+
+def check_policy_id_in_pipeline(policy_id, pipeline):
+ if policy_id not in pipeline:
+ raise MoonCliException(
+ "Unexpected request result. The policy id {} shall be in the pipeline".format(
+ policy_id))
+
+
+def _check_generic_policy_in_dict(field, policy_id, in_dict):
+ if type(field) is str:
+ if policy_id is not None:
+ if "policy_list" not in in_dict:
+ raise MoonCliException(
+ "Unexpected request result. The policy list of the {} shall not be empty".format(
+ field))
+ if policy_id not in in_dict["policy_list"]:
+ raise MoonCliException(
+ "Unexpected request result. The policy with id {} shall be in the {}".format(
+ policy_id, field))
+
+
+def check_subject_policy(policy_id, in_dict):
+ _check_generic_policy_in_dict("subject", policy_id, in_dict)
+
+
+def check_object_policy(policy_id, in_dict):
+ _check_generic_policy_in_dict("object", policy_id, in_dict)
+
+
+def check_action_policy(policy_id, in_dict):
+ _check_generic_policy_in_dict("action", policy_id, in_dict)
+
+
+def _check_generic_elt_id(field1, field1_id, field2, field2_id, result):
+ if type(field1) is str and type(field2) is str:
+ if result[field1] is None:
+ raise MoonCliException(
+ "Unexpected request result: {} shall not be empty".format(field1))
+ if field1_id not in result[field1]:
+ raise MoonCliException("Unexpected request result. Unknown {} with id".format(field1))
+ if field2 not in result[field1][field1_id]:
+ raise MoonCliException(
+ "Unexpected request result. {} element with id {} has no {} field".format(field1,
+ field1_id,
+ field2))
+ if field2_id != result[field1][field1_id][field2]:
+ raise MoonCliException(
+ "Unexpected request result. {} element with id {} has a bad {} id. Expected {}".format(
+ field1, field1_id, field2, field2_id))
+
+
+def check_policy_model_id(model_id, policy_id, result):
+ _check_generic_elt_id("policies", policy_id, "model_id", model_id, result)
+
+
+def check_pdp_project_id(project_id, pdp_id, result):
+ _check_generic_elt_id("pdps", pdp_id, "keystone_project_id", project_id, result)
+
+
+def check_subject_description(description, in_dict):
+ if description is not None:
+ if "description" not in in_dict:
+ raise MoonCliException(
+ "Unexpected request result. The description of the subject shall not be empty")
+ if description not in in_dict["description"]:
+ raise MoonCliException(
+ "Unexpected request result. The description {} shall be in the subject".format(
+ description))
+
+
+def check_meta_rules_list_in_model(meta_rule_list, model_id, result):
+ if result["models"] is None:
+ raise MoonCliException("Unexpected request result. results shall not be empty")
+ if model_id not in result['models']:
+ raise MoonCliException("Unexpected request result. Unknown Model id")
+ if "meta_rules" not in result['models'][model_id]:
+ raise MoonCliException(
+ "Unexpected request result. Meta rules related to model with id {} are empty".format(
+ model_id))
+ if meta_rule_list != result['models'][model_id]["meta_rules"]:
+ raise MoonCliException(
+ "Unexpected request result. Meta rule of model with id {} are different from those expected".format(
+ model_id))
+
+
+def check_name_in_slaves(name, slaves):
+ if name is None:
+ raise MoonCliException("The slave name must be provided !")
+ names = map(lambda x: x['name'], slaves)
+ if name not in names:
+ raise MoonCliException("The slave '{}' was not found !".format(name))
+
+
+def _check_generic_data_data(field, result):
+ if type(field) is str:
+ if field not in result:
+ raise MoonCliException(
+ "Unexpected request result. The {} field shall be in result".format(field))
+ # if "data" not in resulti[field]:
+ # raise MoonCliException("Unexpected request result. The data field shall be in result['{}']".format(field))
+
+
+def _check_id_in_generic_data_data(field, data_id, result):
+ if type(field) is str:
+ _check_generic_data_data(field, result)
+ for _data in result[field]:
+ if data_id not in list(_data['data'].keys()):
+ raise MoonCliException(
+ "Unexpected request result. Data id {} not in {}".format(data_id, field))
+
+
+def _check_id_not_in_generic_data_data(field, data_id, result):
+ if type(field) is str:
+ _check_generic_data_data(field, result)
+ for _data in result[field]:
+ if data_id in list(_data['data'].keys()):
+ raise MoonCliException(
+ "Unexpected request result. Data id {} shall not be in {}".format(data_id,
+ field))
+
+
+def _check_category_in_generic_data_data(field, category_id, result):
+ _check_generic_data_data(field, result)
+ for _data in result[field]:
+ if category_id != _data["category_id"]:
+ raise MoonCliException(
+ "Unexpected request result. Category id {} not in {} data".format(category_id,
+ field))
+
+
+def check_subject_data_data(result):
+ _check_generic_data_data("subject_data", result)
+
+
+def check_id_in_subject_data_data(data_id, result):
+ _check_id_in_generic_data_data("subject_data", data_id, result)
+
+
+def check_id_not_in_subject_data_data(data_id, result):
+ _check_id_not_in_generic_data_data("subject_data", data_id, result)
+
+
+def check_category_id_in_subject_data_data(category_id, result):
+ _check_category_in_generic_data_data('subject_data', category_id, result)
+
+
+def check_object_data_data(result):
+ _check_generic_data_data("object_data", result)
+
+
+def check_id_in_object_data_data(data_id, result):
+ _check_id_in_generic_data_data("object_data", data_id, result)
+
+
+def check_id_not_in_object_data_data(data_id, result):
+ _check_id_not_in_generic_data_data("object_data", data_id, result)
+
+
+def check_category_id_in_object_data_data(category_id, result):
+ _check_category_in_generic_data_data('object_data', category_id, result)
+
+
+def check_action_data_data(result):
+ _check_generic_data_data("action_data", result)
+
+
+def check_id_in_action_data_data(data_id, result):
+ _check_id_in_generic_data_data("action_data", data_id, result)
+
+
+def check_id_not_in_action_data_data(data_id, result):
+ _check_id_not_in_generic_data_data("action_data", data_id, result)
+
+
+def check_category_id_in_action_data_data(category_id, result):
+ _check_category_in_generic_data_data('action_data', category_id, result)
+
+
+def _check_generic_assignments(field, field_id_name, field_id, field_cat_id, field_data_id, result):
+ if type(field) is str and type(field_id_name) is str:
+ for key in result[field]:
+ if field_id_name not in result[field][key]:
+ raise MoonCliException(
+ "Unexpected request result. subject_id not in result[{}] data".format(field))
+ if "category_id" not in result[field][key]:
+ raise MoonCliException(
+ "Unexpected request result. category_id not in result[{}] data".format(field))
+ if "assignments" not in result[field][key]:
+ raise MoonCliException(
+ "Unexpected request result. assignments not in result[{}] data".format(field))
+ if result[field][key][field_id_name] == field_id and \
+ result[field][key]["category_id"] == field_cat_id:
+ if field_data_id not in result[field][key]["assignments"]:
+ raise MoonCliException(
+ "Unexpected request result. {} data with id {} not in result[{}][]['assignements'] data".format(
+ field, field_data_id, field))
+
+
+def check_subject_assignements(subject_id, subject_act_id, subject_data_id, result):
+ _check_generic_assignments("subject_assignments", "subject_id", subject_id, subject_act_id,
+ subject_data_id, result)
+
+
+def check_object_assignements(object_id, object_act_id, object_data_id, result):
+ _check_generic_assignments("object_assignments", "object_id", object_id, object_act_id,
+ object_data_id, result)
+
+
+def check_action_assignements(action_id, action_act_id, action_data_id, result):
+ _check_generic_assignments("action_assignments", "action_id", action_id, action_act_id,
+ action_data_id, result)
+
+
+def _check_not_generic_assignments(field, field_id_name, field_id, field_cat_id, field_data_id,
+ result):
+ if type(field) is str and type(field_id_name) is str:
+ for key in result[field]:
+ if field_id_name not in result[field][key]:
+ raise MoonCliException(
+ "Unexpected request result. subject_id not in result[{}] data".format(field))
+ if "category_id" not in result[field][key]:
+ raise MoonCliException(
+ "Unexpected request result. category_id not in result[{}] data".format(field))
+ if "assignments" not in result[field][key]:
+ raise MoonCliException(
+ "Unexpected request result. assignments not in result[{}] data".format(field))
+ if result[field][key]['subject_id'] == field_id and \
+ result[field][key]["category_id"] == field_cat_id:
+ if field_data_id in result[field][key]["assignments"]:
+ raise MoonCliException(
+ "Unexpected request result. {} data with id {} shall not be in result[{}][]['assignements'] data".format(
+ field, field_data_id, field))
+
+
+def check_not_subject_assignements(subject_id, subject_act_id, subject_data_id, result):
+ _check_not_generic_assignments("subject_assignments", "subject_id", subject_id, subject_act_id,
+ subject_data_id, result)
+
+
+def check_not_object_assignements(object_id, object_act_id, object_data_id, result):
+ _check_not_generic_assignments("object_assignments", "object_id", object_id, object_act_id,
+ object_data_id, result)
+
+
+def check_not_action_assignements(action_id, action_act_id, action_data_id, result):
+ _check_not_generic_assignments("action_assignments", "action_id", action_id, action_act_id,
+ action_data_id, result)
+
+
+def check_policy_id_in_dict(policy_id, in_dict):
+ if "policy_id" not in in_dict:
+ raise MoonCliException("Unexpected request result. policy_id not in result")
+ if policy_id != in_dict["policy_id"]:
+ raise MoonCliException(
+ "Unexpected request result. Bad policy id in result, expected {}".format(policy_id))
+
+
+def check_meta_rule_id_in_dict(meta_rule_id, in_dict):
+ if "meta_rule_id" not in in_dict:
+ raise MoonCliException("Unexpected request result. meta_rule_id not in result")
+ if meta_rule_id != in_dict["meta_rule_id"]:
+ raise MoonCliException(
+ "Unexpected request result. Bad meta rule id in result, expected {}".format(
+ meta_rule_id))
+
+
+def check_rule_in_dict(rule, in_dict):
+ if "rule" not in in_dict:
+ raise MoonCliException("Unexpected request result. rule not in result")
+ if rule != in_dict["rule"]:
+ raise MoonCliException(
+ "Unexpected request result. Bad rule in result, expected {}".format(rule))
+
+
+def check_rule_id_in_list(meta_rule_id, rule_id, rule, in_dict):
+ for item in in_dict:
+ if "meta_rule_id" not in item:
+ raise MoonCliException("Unexpected request result. meta_rule_id field not in result")
+ if meta_rule_id == item["meta_rule_id"]:
+ if rule_id == item["id"]:
+ if rule != item["rule"]:
+ raise MoonCliException(
+ "Unexpected request result. Bad rule in result, expected {}".format(rule))
+
+
+def check_rule_id_not_in_list(rule_id, in_dict):
+ found_rule = False
+ for item in in_dict:
+ if rule_id == item["id"]:
+ found_rule = True
+ if found_rule is True:
+ raise MoonCliException(
+ "Unexpected request result. Rule with id {} shall not be in result".format(rule_id))
diff --git a/old/python_moonclient/python_moonclient/core/cli_exceptions.py b/old/python_moonclient/python_moonclient/core/cli_exceptions.py
new file mode 100644
index 00000000..01fd23e0
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/core/cli_exceptions.py
@@ -0,0 +1,4 @@
+class MoonCliException(Exception):
+ def __init__(self, message):
+ # Call the base class constructor with the parameters it needs
+ super(MoonCliException, self).__init__(message)
diff --git a/old/python_moonclient/python_moonclient/core/config.py b/old/python_moonclient/python_moonclient/core/config.py
new file mode 100644
index 00000000..c123499b
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/core/config.py
@@ -0,0 +1,64 @@
+import base64
+import json
+import requests
+
+
+def get_configuration(consul_host, consul_port, key):
+ url = "http://{}:{}/v1/kv/{}".format(consul_host, consul_port, key)
+ req = requests.get(url)
+ if req.status_code != 200:
+ raise Exception("Exception when retrieving configuration from Consul: {} {}".format(
+ req.status_code, req.text
+ ))
+ data = req.json()
+ if len(data) == 1:
+ data = data[0]
+ return {data["Key"]: json.loads(base64.b64decode(data["Value"]).decode("utf-8"))}
+ return [
+ {item["Key"]: json.loads(base64.b64decode(item["Value"]).decode("utf-8"))}
+ for item in data
+ ]
+
+
+def get_config_data(consul_host, consul_port):
+ conf_data = dict()
+ conf_data['manager_host'] = get_configuration(
+ consul_host, consul_port,
+ 'components/manager')['components/manager']['external']['hostname']
+ conf_data['manager_port'] = get_configuration(
+ consul_host, consul_port,
+ 'components/manager')['components/manager']['external']['port']
+ try:
+ requests.get("http://{}:{}/".format(
+ conf_data['manager_host'],
+ conf_data['manager_port']
+ ),
+ timeout=2)
+ except requests.exceptions.ConnectionError:
+ conf_data['manager_host'] = get_configuration(consul_host, consul_port,
+ 'components/manager')[
+ 'components/manager']['hostname']
+ conf_data['manager_port'] = get_configuration(consul_host, consul_port,
+ 'components/manager')[
+ 'components/manager']['port']
+
+ conf_data['keystone_host'] = get_configuration(
+ consul_host, consul_port,
+ 'openstack/keystone')['openstack/keystone']['external']['url']
+ try:
+ requests.get(conf_data['keystone_host'], timeout=2)
+ except requests.exceptions.ConnectionError:
+ conf_data['keystone_host'] = get_configuration(
+ consul_host, consul_port,
+ 'openstack/keystone')['openstack/keystone']['url']
+
+ conf_data['keystone_user'] = get_configuration(consul_host, consul_port,
+ 'openstack/keystone')['openstack/keystone'][
+ 'user']
+ conf_data['keystone_password'] = get_configuration(consul_host, consul_port,
+ 'openstack/keystone')['openstack/keystone'][
+ 'password']
+ conf_data['keystone_project'] = get_configuration(consul_host, consul_port,
+ 'openstack/keystone')['openstack/keystone'][
+ 'project']
+ return conf_data
diff --git a/old/python_moonclient/python_moonclient/core/json_export.py b/old/python_moonclient/python_moonclient/core/json_export.py
new file mode 100644
index 00000000..edaeb177
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/core/json_export.py
@@ -0,0 +1,26 @@
+import logging
+import copy
+import requests
+from python_moonclient.core import config
+
+LOGGER = logging.getLogger("moonclient.core.export_json")
+
+URL = None
+HEADERS = None
+
+
+def init(consul_host, consul_port):
+ conf_data = config.get_config_data(consul_host, consul_port)
+ global URL, HEADERS
+ URL = "http://{}:{}".format(
+ conf_data['manager_host'],
+ conf_data['manager_port'])
+ URL = URL + "{}"
+ HEADERS = {"content-type": "application/json"}
+
+
+def export_to_json():
+ req = requests.get(URL.format("/export"))
+ req.raise_for_status()
+ result = req.json()
+ return result
diff --git a/old/python_moonclient/python_moonclient/core/json_import.py b/old/python_moonclient/python_moonclient/core/json_import.py
new file mode 100644
index 00000000..b65ec39b
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/core/json_import.py
@@ -0,0 +1,29 @@
+import logging
+import requests
+import copy
+from python_moonclient.core import config
+
+LOGGER = logging.getLogger("moonclient.core.import_json")
+
+URL = None
+HEADERS = None
+
+
+def init(consul_host, consul_port):
+ conf_data = config.get_config_data(consul_host, consul_port)
+ global URL, HEADERS
+ URL = "http://{}:{}".format(
+ conf_data['manager_host'],
+ conf_data['manager_port'])
+ URL = URL + "{}"
+ HEADERS = {"content-type": "application/json"}
+
+
+def import_json(file_name):
+ files = {'file': open(file_name, 'rb')}
+ req = requests.post(URL.format("/import"), files=files)
+ result = req.json()
+ if isinstance(result, dict) and "message" in result:
+ req.reason = result["message"]
+ req.raise_for_status()
+ return result
diff --git a/old/python_moonclient/python_moonclient/core/models.py b/old/python_moonclient/python_moonclient/core/models.py
new file mode 100644
index 00000000..8d3c8858
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/core/models.py
@@ -0,0 +1,279 @@
+import logging
+import copy
+import requests
+from python_moonclient.core import config
+from python_moonclient.core.check_tools import *
+
+LOGGER = logging.getLogger("moonclient.core.models")
+
+URL = None
+HEADERS = None
+
+model_template = {
+ "name": "test_model",
+ "description": "test",
+ "meta_rules": []
+}
+
+category_template = {
+ "name": "name of the category",
+ "description": "description of the category"
+}
+
+meta_rule_template = {
+ "name": "test_meta_rule",
+ "subject_categories": [],
+ "object_categories": [],
+ "action_categories": []
+}
+
+
+def init(consul_host, consul_port):
+ conf_data = config.get_config_data(consul_host, consul_port)
+ global URL, HEADERS
+ URL = "http://{}:{}".format(
+ conf_data['manager_host'],
+ conf_data['manager_port'])
+ URL = URL + "{}"
+ HEADERS = {"content-type": "application/json"}
+
+
+def check_model(model_id=None, do_check_model_name=True):
+ req = requests.get(URL.format("/models"))
+ req.raise_for_status()
+ result = req.json()
+ check_model_in_result(result)
+ if model_id:
+ check_model_name(model_template["name"], model_id, result, do_check_model_name)
+ return result
+
+
+def add_model(name=None):
+ if name:
+ model_template['name'] = name
+ req = requests.post(URL.format("/models"), json=model_template, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_model_in_result(result)
+ model_id = list(result['models'].keys())[0]
+ check_model_name(model_template["name"], model_id, result, True)
+ return model_id
+
+
+def delete_model(model_id):
+ req = requests.delete(URL.format("/models/{}".format(model_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_result(result)
+
+
+def add_subject_category(name="subject_cat_1"):
+ category_template["name"] = name
+ req = requests.post(URL.format("/subject_categories"), json=category_template, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+
+ check_subject_category_in_result(result)
+ category_id = list(result['subject_categories'].keys())[0]
+ check_optionnal_result(result)
+ check_subject_categories_name(category_template["name"], category_id, result)
+ return category_id
+
+
+def check_subject_category(category_id=None):
+ req = requests.get(URL.format("/subject_categories"))
+ req.raise_for_status()
+ result = req.json()
+
+ check_subject_category_in_result(result)
+ check_optionnal_result(result)
+ if category_id is not None:
+ check_subject_categories_name(category_template["name"], category_id, result)
+ return result
+
+
+def delete_subject_category(category_id):
+ req = requests.delete(URL.format("/subject_categories/{}".format(category_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_optionnal_result(result)
+
+
+def add_object_category(name="object_cat_1"):
+ category_template["name"] = name
+ req = requests.post(URL.format("/object_categories"), json=category_template, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_object_category_in_result(result)
+ category_id = list(result['object_categories'].keys())[0]
+ check_optionnal_result(result)
+ check_object_categories_name(category_template["name"], category_id, result)
+ return category_id
+
+
+def check_object_category(category_id=None):
+ req = requests.get(URL.format("/object_categories"))
+ req.raise_for_status()
+ result = req.json()
+ check_object_category_in_result(result)
+ check_optionnal_result(result)
+ if category_id is not None:
+ check_object_categories_name(category_template["name"], category_id, result)
+ return result
+
+
+def delete_object_category(category_id):
+ req = requests.delete(URL.format("/object_categories/{}".format(category_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_optionnal_result(result)
+
+
+def add_action_category(name="action_cat_1"):
+ category_template["name"] = name
+ req = requests.post(URL.format("/action_categories"), json=category_template, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_action_category_in_result(result)
+ category_id = list(result['action_categories'].keys())[0]
+ check_optionnal_result(result)
+ check_action_categories_name(category_template["name"], category_id, result)
+ return category_id
+
+
+def check_action_category(category_id=None):
+ req = requests.get(URL.format("/action_categories"))
+ req.raise_for_status()
+ result = req.json()
+ print(result)
+ check_action_category_in_result(result)
+ check_optionnal_result(result)
+ if category_id is not None:
+ check_action_categories_name(category_template["name"], category_id, result)
+ return result
+
+
+def delete_action_category(category_id):
+ req = requests.delete(URL.format("/action_categories/{}".format(category_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_optionnal_result(result)
+
+
+def add_categories_and_meta_rule(name="test_meta_rule"):
+ scat_id = add_subject_category()
+ ocat_id = add_object_category()
+ acat_id = add_action_category()
+ _meta_rule_template = copy.deepcopy(meta_rule_template)
+ _meta_rule_template["name"] = name
+ _meta_rule_template["subject_categories"].append(scat_id)
+ _meta_rule_template["object_categories"].append(ocat_id)
+ _meta_rule_template["action_categories"].append(acat_id)
+ req = requests.post(URL.format("/meta_rules"), json=_meta_rule_template, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_meta_rule_in_result(result)
+ meta_rule_id = list(result['meta_rules'].keys())[0]
+ check_optionnal_result(result)
+ check_meta_rules_name(_meta_rule_template["name"], meta_rule_id, result)
+ return meta_rule_id, scat_id, ocat_id, acat_id
+
+
+def add_meta_rule(name="test_meta_rule", scat=[], ocat=[], acat=[]):
+ _meta_rule_template = copy.deepcopy(meta_rule_template)
+ _meta_rule_template["name"] = name
+ _meta_rule_template["subject_categories"] = []
+ _meta_rule_template["subject_categories"].extend(scat)
+ _meta_rule_template["object_categories"] = []
+ _meta_rule_template["object_categories"].extend(ocat)
+ _meta_rule_template["action_categories"] = []
+ _meta_rule_template["action_categories"].extend(acat)
+ req = requests.post(URL.format("/meta_rules"), json=_meta_rule_template, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_meta_rule_in_result(result)
+ meta_rule_id = list(result['meta_rules'].keys())[0]
+ check_optionnal_result(result)
+ check_meta_rules_name(_meta_rule_template["name"], meta_rule_id, result)
+ return meta_rule_id
+
+
+def check_meta_rule(meta_rule_id, scat_id=None, ocat_id=None, acat_id=None):
+ req = requests.get(URL.format("/meta_rules"))
+ req.raise_for_status()
+ result = req.json()
+ check_meta_rule_in_result(result)
+ check_optionnal_result(result)
+ if not meta_rule_id:
+ return result
+ check_meta_rules_name(None, meta_rule_id, result)
+ if scat_id:
+ check_scat_id_in_dict(scat_id, result['meta_rules'][meta_rule_id]["subject_categories"])
+ if ocat_id:
+ check_ocat_id_in_dict(ocat_id, result['meta_rules'][meta_rule_id]["object_categories"])
+ if acat_id:
+ check_acat_id_in_dict(acat_id, result['meta_rules'][meta_rule_id]["action_categories"])
+ return result
+
+
+def delete_meta_rule(meta_rule_id):
+ req = requests.delete(URL.format("/meta_rules/{}".format(meta_rule_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_optionnal_result(result)
+
+
+def add_meta_rule_to_model(model_id, meta_rule_id):
+ model = check_model(model_id, do_check_model_name=False)['models']
+ meta_rule_list = model[model_id]["meta_rules"]
+ if meta_rule_id not in meta_rule_list:
+ meta_rule_list.append(meta_rule_id)
+ req = requests.patch(URL.format("/models/{}".format(model_id)),
+ json={"meta_rules": meta_rule_list},
+ headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_model_in_result(result)
+ model_id = list(result['models'].keys())[0]
+ check_optionnal_result(result)
+ check_meta_rules_list_in_model(meta_rule_list, model_id, result)
+
+
+def create_model(scenario, model_id=None):
+ LOGGER.info("Creating model {}".format(scenario.model_name))
+ if not model_id:
+ LOGGER.info("Add model")
+ model_id = add_model(name=scenario.model_name)
+ LOGGER.info("Add subject categories")
+ for cat in scenario.subject_categories:
+ scenario.subject_categories[cat] = add_subject_category(name=cat)
+ LOGGER.info("Add object categories")
+ for cat in scenario.object_categories:
+ scenario.object_categories[cat] = add_object_category(name=cat)
+ LOGGER.info("Add action categories")
+ for cat in scenario.action_categories:
+ scenario.action_categories[cat] = add_action_category(name=cat)
+ sub_cat = []
+ ob_cat = []
+ act_cat = []
+ meta_rule_list = []
+ for item_name, item_value in scenario.meta_rule.items():
+ for item in item_value["value"]:
+ if item in scenario.subject_categories:
+ sub_cat.append(scenario.subject_categories[item])
+ elif item in scenario.object_categories:
+ ob_cat.append(scenario.object_categories[item])
+ elif item in scenario.action_categories:
+ act_cat.append(scenario.action_categories[item])
+ meta_rules = check_meta_rule(meta_rule_id=None)
+ for _meta_rule_id, _meta_rule_value in meta_rules['meta_rules'].items():
+ if _meta_rule_value['name'] == item_name:
+ meta_rule_id = _meta_rule_id
+ break
+ else:
+ LOGGER.info("Add meta rule")
+ meta_rule_id = add_meta_rule(item_name, sub_cat, ob_cat, act_cat)
+ item_value["id"] = meta_rule_id
+ if meta_rule_id not in meta_rule_list:
+ meta_rule_list.append(meta_rule_id)
+ return model_id, meta_rule_list
diff --git a/old/python_moonclient/python_moonclient/core/pdp.py b/old/python_moonclient/python_moonclient/core/pdp.py
new file mode 100644
index 00000000..f67a4d01
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/core/pdp.py
@@ -0,0 +1,194 @@
+import sys
+import logging
+import requests
+from python_moonclient.core import config
+from python_moonclient.core.check_tools import *
+
+LOGGER = logging.getLogger("python_moonclient.core.pdp")
+
+URL = None
+HEADERS = None
+KEYSTONE_USER = None
+KEYSTONE_PASSWORD = None
+KEYSTONE_PROJECT = None
+KEYSTONE_SERVER = None
+
+pdp_template = {
+ "name": "test_pdp",
+ "security_pipeline": [],
+ "keystone_project_id": None,
+ "description": "test",
+}
+
+
+def init(consul_host, consul_port):
+ conf_data = config.get_config_data(consul_host, consul_port)
+ global URL, HEADERS, KEYSTONE_USER, KEYSTONE_PASSWORD, KEYSTONE_PROJECT, KEYSTONE_SERVER
+ URL = "http://{}:{}".format(
+ conf_data['manager_host'],
+ conf_data['manager_port'])
+ # URL = URL + "{}"
+ HEADERS = {"content-type": "application/json"}
+ KEYSTONE_USER = conf_data['keystone_user']
+ KEYSTONE_PASSWORD = conf_data['keystone_password']
+ KEYSTONE_PROJECT = conf_data['keystone_project']
+ KEYSTONE_SERVER = conf_data['keystone_host']
+
+
+def get_keystone_projects():
+ global HEADERS
+ HEADERS = {
+ "Content-Type": "application/json"
+ }
+
+ data_auth = {
+ "auth": {
+ "identity": {
+ "methods": [
+ "password"
+ ],
+ "password": {
+ "user": {
+ "name": KEYSTONE_USER,
+ "domain": {
+ "name": "Default"
+ },
+ "password": KEYSTONE_PASSWORD
+ }
+ }
+ }
+ }
+ }
+
+ req = requests.post("{}/auth/tokens".format(KEYSTONE_SERVER), json=data_auth, headers=HEADERS)
+ LOGGER.debug("{}/auth/tokens".format(KEYSTONE_SERVER))
+ LOGGER.debug(req.text)
+ req.raise_for_status()
+ token = req.headers['X-Subject-Token']
+ HEADERS['X-Auth-Token'] = token
+ req = requests.get("{}/projects".format(KEYSTONE_SERVER), headers=HEADERS)
+ if req.status_code not in (200, 201):
+ data_auth["auth"]["scope"] = {
+ "project": {
+ "name": KEYSTONE_PROJECT,
+ "domain": {
+ "id": "default"
+ }
+ }
+ }
+ req = requests.post("{}/auth/tokens".format(KEYSTONE_SERVER), json=data_auth,
+ headers=HEADERS)
+ req.raise_for_status()
+ token = req.headers['X-Subject-Token']
+ HEADERS['X-Auth-Token'] = token
+ req = requests.get("{}/projects".format(KEYSTONE_SERVER), headers=HEADERS)
+ req.raise_for_status()
+ return req.json()
+
+
+def get_keystone_id(pdp_name):
+ keystone_project_id = None
+ for pdp_key, pdp_value in check_pdp()["pdps"].items():
+ if pdp_name:
+ if pdp_name != pdp_value["name"]:
+ continue
+ if pdp_value['security_pipeline'] and pdp_value["keystone_project_id"]:
+ LOGGER.debug(
+ "Found pdp with keystone_project_id={}".format(pdp_value["keystone_project_id"]))
+ keystone_project_id = pdp_value["keystone_project_id"]
+
+ if not keystone_project_id:
+ LOGGER.error("Cannot find PDP with keystone project ID")
+ sys.exit(1)
+ return keystone_project_id
+
+
+def check_pdp(pdp_id=None, keystone_project_id=None, moon_url=None):
+ _url = URL
+ if moon_url:
+ _url = moon_url
+ req = requests.get(_url + "/pdp")
+ req.raise_for_status()
+ result = req.json()
+ check_pdp_in_result(result)
+ if pdp_id:
+ check_pdp_name(pdp_template["name"], pdp_id, result)
+ if keystone_project_id:
+ check_pdp_project_id(keystone_project_id, pdp_id, result)
+ return result
+
+
+def add_pdp(name="test_pdp", policy_id=None):
+ pdp_template['name'] = name
+ if policy_id:
+ pdp_template['security_pipeline'].append(policy_id)
+ req = requests.post(URL + "/pdp", json=pdp_template, headers=HEADERS)
+ LOGGER.debug(req.status_code)
+ LOGGER.debug(req)
+ req.raise_for_status()
+ result = req.json()
+ check_pdp_in_result(result)
+ pdp_id = list(result['pdps'].keys())[0]
+ check_pdp_name(pdp_template["name"], pdp_id, result)
+ return pdp_id
+
+
+def update_pdp(pdp_id, policy_id=None):
+ req = requests.get(URL + "/pdp/{}".format(pdp_id))
+ req.raise_for_status()
+ result = req.json()
+ check_pdp_id(pdp_id, result)
+ pipeline = result['pdps'][pdp_id]["security_pipeline"]
+ if policy_id not in pipeline:
+ pipeline.append(policy_id)
+ req = requests.patch(URL + "/pdp/{}".format(pdp_id),
+ json={"security_pipeline": pipeline})
+ req.raise_for_status()
+ result = req.json()
+ check_pdp_id(pdp_id, result)
+
+ req = requests.get(URL + "/pdp/{}".format(pdp_id))
+ req.raise_for_status()
+ result = req.json()
+ check_pdp_id(pdp_id, result)
+ check_policy_id_in_pipeline(pdp_id, pipeline)
+
+
+def map_to_keystone(pdp_id, keystone_project_id):
+ req = requests.patch(URL + "/pdp/{}".format(pdp_id),
+ json={"keystone_project_id": keystone_project_id},
+ headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_pdp_id(pdp_id, result)
+ # assert "name" in result['pdps'][pdp_id]
+ # assert pdp_template["name"] == result['pdps'][pdp_id]["name"]
+ return pdp_id
+
+
+def delete_pdp(pdp_id):
+ req = requests.delete(URL + "/pdp/{}".format(pdp_id))
+ req.raise_for_status()
+ result = req.json()
+ check_result(result)
+
+
+def create_pdp(scenario, policy_id=None, project_id=None):
+ LOGGER.info("Creating PDP {}".format(scenario.pdp_name))
+ projects = get_keystone_projects()
+ # if not project_id:
+ # for _project in projects['projects']:
+ # if _project['name'] == "admin":
+ # project_id = _project['id']
+ # assert project_id
+ pdps = check_pdp()["pdps"]
+ for pdp_id, pdp_value in pdps.items():
+ if scenario.pdp_name == pdp_value["name"]:
+ update_pdp(pdp_id, policy_id=policy_id)
+ LOGGER.debug(
+ "Found existing PDP named {} (will add policy {})".format(scenario.pdp_name,
+ policy_id))
+ return pdp_id
+ _pdp_id = add_pdp(name=scenario.pdp_name, policy_id=policy_id)
+ # map_to_keystone(pdp_id=_pdp_id, keystone_project_id=project_id)
+ return _pdp_id
diff --git a/old/python_moonclient/python_moonclient/core/policies.py b/old/python_moonclient/python_moonclient/core/policies.py
new file mode 100644
index 00000000..b9b05dd8
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/core/policies.py
@@ -0,0 +1,673 @@
+import logging
+import requests
+from python_moonclient.core import models, config
+from python_moonclient.core.check_tools import *
+
+LOGGER = logging.getLogger("moonclient.core.policies")
+
+URL = None
+HEADERS = None
+
+policy_template = {
+ "name": "test_policy",
+ "model_id": "",
+ "genre": "authz",
+ "description": "test",
+}
+
+subject_template = {
+ "name": "test_subject",
+ "description": "test",
+ "email": "mail",
+ "password": "my_pass",
+}
+
+object_template = {
+ "name": "test_subject",
+ "description": "test"
+}
+
+action_template = {
+ "name": "test_subject",
+ "description": "test"
+}
+
+subject_data_template = {
+ "name": "subject_data1",
+ "description": "description of the data subject"
+}
+
+object_data_template = {
+ "name": "object_data1",
+ "description": "description of the data subject"
+}
+
+action_data_template = {
+ "name": "action_data1",
+ "description": "description of the data subject"
+}
+
+subject_assignment_template = {
+ "id": "",
+ "category_id": "",
+ "scope_id": ""
+}
+
+
+def init(consul_host, consul_port):
+ conf_data = config.get_config_data(consul_host, consul_port)
+ global URL, HEADERS
+ URL = "http://{}:{}".format(
+ conf_data['manager_host'],
+ conf_data['manager_port'])
+ URL = URL + "{}"
+ HEADERS = {"content-type": "application/json"}
+
+
+def check_policy(policy_id=None):
+ req = requests.get(URL.format("/policies"))
+ req.raise_for_status()
+ result = req.json()
+ check_policy_in_result(result)
+ if policy_id:
+ check_policy_name(policy_template["name"], policy_id, result)
+ return result
+
+
+def add_policy(name="test_policy", genre="authz"):
+ policy_template["name"] = name
+ policy_template["genre"] = genre
+ req = requests.post(URL.format("/policies"), json=policy_template, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_policy_in_result(result)
+ policy_id = list(result['policies'].keys())[0]
+ check_optionnal_result(result)
+ check_policy_name(policy_template["name"], policy_id, result)
+ return policy_id
+
+
+def update_policy(policy_id, model_id):
+ req = requests.patch(URL.format("/policies/{}".format(policy_id)),
+ json={"model_id": model_id}, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_policy_in_result(result)
+ policy_id = list(result['policies'].keys())[0]
+ check_optionnal_result(result)
+ check_policy_model_id(model_id, policy_id, result)
+
+
+def delete_policy(policy_id):
+ req = requests.delete(URL.format("/policies/{}".format(policy_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_result(result)
+
+
+def add_subject(policy_id=None, name="test_subject"):
+ subject_template['name'] = name
+ if policy_id:
+ LOGGER.debug(URL.format("/policies/{}/subjects".format(policy_id)))
+ req = requests.post(URL.format("/policies/{}/subjects".format(policy_id)),
+ json=subject_template, headers=HEADERS)
+ else:
+ LOGGER.debug(URL.format("/subjects"))
+ req = requests.post(URL.format("/subjects"), json=subject_template, headers=HEADERS)
+ LOGGER.debug(req.text)
+ req.raise_for_status()
+ result = req.json()
+ check_subject_in_result(result)
+ subject_id = list(result['subjects'].keys())[0]
+ return subject_id
+
+
+def update_subject(subject_id, policy_id=None, description=None):
+ if policy_id and not description:
+ req = requests.patch(URL.format("/policies/{}/subjects/{}".format(policy_id, subject_id)),
+ json={})
+ elif policy_id and description:
+ req = requests.patch(URL.format("/policies/{}/subjects/{}".format(policy_id, subject_id)),
+ json={"description": description})
+ else:
+ req = requests.patch(URL.format("/subjects/{}".format(subject_id)),
+ json={"description": description})
+ req.raise_for_status()
+ result = req.json()
+ check_subject_name(subject_template["name"], subject_id, result)
+ check_subject_policy(policy_id, result["subjects"][subject_id])
+ check_subject_description(description, result["subjects"][subject_id])
+
+
+def check_subject(subject_id=None, policy_id=None):
+ if policy_id:
+ req = requests.get(URL.format("/policies/{}/subjects".format(policy_id)))
+ else:
+ req = requests.get(URL.format("/subjects"))
+ req.raise_for_status()
+ result = req.json()
+ check_subject_name(subject_template["name"], subject_id, result)
+ check_subject_policy(policy_id, result["subjects"][subject_id])
+
+
+def delete_subject(subject_id, policy_id=None):
+ if policy_id:
+ req = requests.delete(URL.format("/policies/{}/subjects/{}".format(policy_id, subject_id)))
+ else:
+ req = requests.delete(URL.format("/subjects/{}".format(subject_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_result(result)
+
+ if policy_id:
+ req = requests.get(URL.format("/policies/{}/subjects".format(policy_id)))
+ else:
+ req = requests.get(URL.format("/subjects"))
+ req.raise_for_status()
+ result = req.json()
+ check_subject_in_result(result)
+ if subject_id in result["subjects"]:
+ check_subject_name(subject_template["name"], subject_id, result)
+ check_subject_policy(policy_id, result["subjects"][subject_id])
+
+
+def add_object(policy_id=None, name="test_object"):
+ object_template['name'] = name
+ if policy_id:
+ req = requests.post(URL.format("/policies/{}/objects".format(policy_id)),
+ json=object_template, headers=HEADERS)
+ else:
+ req = requests.post(URL.format("/objects"), json=object_template, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_object_in_result(result)
+ object_id = list(result['objects'].keys())[0]
+ return object_id
+
+
+def update_object(object_id, policy_id):
+ req = requests.patch(URL.format("/policies/{}/objects/{}".format(policy_id, object_id)),
+ json={})
+ req.raise_for_status()
+ result = req.json()
+ check_object_in_result(result)
+ check_object_name(object_template["name"], object_id, result)
+ check_object_policy(policy_id, result["objects"][object_id])
+
+
+def check_object(object_id=None, policy_id=None):
+ if policy_id:
+ req = requests.get(URL.format("/policies/{}/objects".format(policy_id)))
+ else:
+ req = requests.get(URL.format("/objects"))
+ req.raise_for_status()
+ result = req.json()
+ check_object_in_result(result)
+ check_object_name(object_template["name"], object_id, result)
+ if policy_id:
+ check_object_policy(policy_id, result["objects"][object_id])
+
+
+def delete_object(object_id, policy_id=None):
+ if policy_id:
+ req = requests.delete(URL.format("/policies/{}/objects/{}".format(policy_id, object_id)))
+ else:
+ req = requests.delete(URL.format("/objects/{}".format(object_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_result(result)
+
+ if policy_id:
+ req = requests.get(URL.format("/policies/{}/objects".format(policy_id)))
+ else:
+ req = requests.get(URL.format("/objects"))
+ req.raise_for_status()
+ result = req.json()
+ check_object_in_result(result)
+ if object_id in result["objects"]:
+ check_object_name(object_template["name"], object_id, result)
+ if policy_id:
+ check_object_policy(policy_id, result["objects"][object_id])
+
+
+def add_action(policy_id=None, name="test_action"):
+ action_template['name'] = name
+ if policy_id:
+ req = requests.post(URL.format("/policies/{}/actions".format(policy_id)),
+ json=action_template, headers=HEADERS)
+ else:
+ req = requests.post(URL.format("/actions"), json=action_template, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_action_in_result(result)
+ action_id = list(result['actions'].keys())[0]
+ return action_id
+
+
+def update_action(action_id, policy_id):
+ req = requests.patch(URL.format("/policies/{}/actions/{}".format(policy_id, action_id)),
+ json={})
+ req.raise_for_status()
+ result = req.json()
+ check_action_in_result(result)
+ check_action_name(action_template["name"], action_id, result)
+ check_action_policy(policy_id, result["actions"][action_id])
+
+
+def check_action(action_id=None, policy_id=None):
+ if policy_id:
+ req = requests.get(URL.format("/policies/{}/actions".format(policy_id)))
+ else:
+ req = requests.get(URL.format("/actions"))
+ req.raise_for_status()
+ result = req.json()
+ check_action_in_result(result)
+ check_action_name(action_template["name"], action_id, result)
+ if policy_id:
+ check_action_policy(policy_id, result["actions"][action_id])
+
+
+def delete_action(action_id, policy_id=None):
+ if policy_id:
+ req = requests.delete(URL.format("/policies/{}/actions/{}".format(policy_id, action_id)))
+ else:
+ req = requests.delete(URL.format("/actions/{}".format(action_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_result(result)
+
+ if policy_id:
+ req = requests.get(URL.format("/policies/{}/actions".format(policy_id)))
+ else:
+ req = requests.get(URL.format("/actions"))
+ req.raise_for_status()
+ result = req.json()
+ check_action_in_result(result)
+ if action_id in result["actions"]:
+ check_action_name(action_template["name"], action_id, result)
+ if policy_id:
+ check_action_policy(policy_id, result["actions"][action_id])
+
+
+def add_subject_data(policy_id, category_id, name="subject_data1"):
+ subject_data_template['name'] = name
+ req = requests.post(URL.format("/policies/{}/subject_data/{}".format(policy_id, category_id)),
+ json=subject_data_template, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_subject_data_data(result)
+ subject_id = list(result['subject_data']['data'].keys())[0]
+ return subject_id
+
+
+def check_subject_data(policy_id, data_id, category_id):
+ req = requests.get(URL.format("/policies/{}/subject_data/{}".format(policy_id, category_id)))
+ req.raise_for_status()
+ result = req.json()
+ print(result)
+ if data_id is not None:
+ check_id_in_subject_data_data(data_id, result)
+ check_category_id_in_subject_data_data(category_id, result)
+ return result
+
+
+def delete_subject_data(policy_id, category_id, data_id):
+ req = requests.delete(
+ URL.format("/policies/{}/subject_data/{}/{}".format(policy_id, category_id, data_id)),
+ headers=HEADERS)
+ req.raise_for_status()
+ req = requests.get(URL.format("/policies/{}/subject_data/{}".format(policy_id, category_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_id_not_in_subject_data_data(data_id, result)
+ check_category_id_in_subject_data_data(category_id, result)
+
+
+def add_object_data(policy_id, category_id, name="object_data1"):
+ object_data_template['name'] = name
+ req = requests.post(URL.format("/policies/{}/object_data/{}".format(policy_id, category_id)),
+ json=object_data_template, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_object_data_data(result)
+ object_id = list(result['object_data']['data'].keys())[0]
+ return object_id
+
+
+def check_object_data(policy_id, data_id, category_id):
+ req = requests.get(URL.format("/policies/{}/object_data/{}".format(policy_id, category_id)))
+ req.raise_for_status()
+ result = req.json()
+ if data_id is not None:
+ check_id_in_object_data_data(data_id, result)
+ check_category_id_in_object_data_data(category_id, result)
+ return result
+
+
+def delete_object_data(policy_id, category_id, data_id):
+ req = requests.delete(
+ URL.format("/policies/{}/object_data/{}/{}".format(policy_id, category_id, data_id)),
+ headers=HEADERS)
+ req.raise_for_status()
+ req = requests.get(URL.format("/policies/{}/object_data/{}".format(policy_id, category_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_id_not_in_object_data_data(data_id, result)
+ check_category_id_in_object_data_data(category_id, result)
+
+
+def add_action_data(policy_id, category_id, name="action_data1"):
+ action_data_template['name'] = name
+ req = requests.post(URL.format("/policies/{}/action_data/{}".format(policy_id, category_id)),
+ json=action_data_template, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_action_data_data(result)
+ action_id = list(result['action_data']['data'].keys())[0]
+ return action_id
+
+
+def check_action_data(policy_id, data_id, category_id):
+ req = requests.get(URL.format("/policies/{}/action_data/{}".format(policy_id, category_id)))
+ req.raise_for_status()
+ result = req.json()
+ print(result)
+ if data_id is not None:
+ check_id_in_action_data_data(data_id, result)
+ check_category_id_in_action_data_data(category_id, result)
+ return result
+
+
+def delete_action_data(policy_id, category_id, data_id):
+ req = requests.delete(
+ URL.format("/policies/{}/action_data/{}/{}".format(policy_id, category_id, data_id)),
+ headers=HEADERS)
+ req.raise_for_status()
+ req = requests.get(URL.format("/policies/{}/action_data/{}".format(policy_id, category_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_id_not_in_action_data_data(data_id, result)
+ check_category_id_in_action_data_data(category_id, result)
+
+
+def add_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id):
+ req = requests.post(URL.format("/policies/{}/subject_assignments".format(policy_id)),
+ json={
+ "id": subject_id,
+ "category_id": subject_cat_id,
+ "data_id": subject_data_id
+ }, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_subject_assignment_in_result(result)
+
+
+def check_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id):
+ req = requests.get(URL.format("/policies/{}/subject_assignments/{}/{}/{}".format(
+ policy_id, subject_id, subject_cat_id, subject_data_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_subject_assignment_in_result(result)
+ check_subject_assignements(subject_id, subject_cat_id, subject_data_id, result)
+
+
+def check_object_assignments(policy_id, object_id, object_cat_id, object_data_id):
+ req = requests.get(URL.format("/policies/{}/object_assignments/{}/{}/{}".format(
+ policy_id, object_id, object_cat_id, object_data_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_object_assignment_in_result(result)
+ check_object_assignements(object_id, object_cat_id, object_data_id, result)
+
+
+def check_action_assignments(policy_id, action_id, action_cat_id, action_data_id):
+ req = requests.get(URL.format("/policies/{}/action_assignments/{}/{}/{}".format(
+ policy_id, action_id, action_cat_id, action_data_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_action_assignment_in_result(result)
+ check_action_assignements(action_id, action_cat_id, action_data_id, result)
+
+
+def add_object_assignments(policy_id, object_id, object_cat_id, object_data_id):
+ req = requests.post(URL.format("/policies/{}/object_assignments".format(policy_id)),
+ json={
+ "id": object_id,
+ "category_id": object_cat_id,
+ "data_id": object_data_id
+ }, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_object_assignment_in_result(result)
+
+
+def add_action_assignments(policy_id, action_id, action_cat_id, action_data_id):
+ req = requests.post(URL.format("/policies/{}/action_assignments".format(policy_id)),
+ json={
+ "id": action_id,
+ "category_id": action_cat_id,
+ "data_id": action_data_id
+ }, headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_action_assignment_in_result(result)
+
+
+def delete_subject_assignment(policy_id, subject_id, subject_cat_id, subject_data_id):
+ req = requests.delete(URL.format("/policies/{}/subject_assignments/{}/{}/{}".format(
+ policy_id, subject_id, subject_cat_id, subject_data_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_result(result)
+
+ req = requests.get(URL.format("/policies/{}/subject_assignments/{}/{}/{}".format(
+ policy_id, subject_id, subject_cat_id, subject_data_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_subject_assignment_in_result(result)
+ check_not_subject_assignements(subject_id, subject_cat_id, subject_data_id, result)
+
+
+def delete_object_assignment(policy_id, object_id, object_cat_id, object_data_id):
+ req = requests.delete(URL.format("/policies/{}/object_assignments/{}/{}/{}".format(
+ policy_id, object_id, object_cat_id, object_data_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_result(result)
+
+ req = requests.get(URL.format("/policies/{}/object_assignments/{}/{}/{}".format(
+ policy_id, object_id, object_cat_id, object_data_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_object_assignment_in_result(result)
+ check_not_object_assignements(object_id, object_cat_id, object_data_id, result)
+
+
+def delete_action_assignment(policy_id, action_id, action_cat_id, action_data_id):
+ req = requests.delete(URL.format("/policies/{}/action_assignments/{}/{}/{}".format(
+ policy_id, action_id, action_cat_id, action_data_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_result(result)
+
+ req = requests.get(URL.format("/policies/{}/action_assignments/{}/{}/{}".format(
+ policy_id, action_id, action_cat_id, action_data_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_action_assignment_in_result(result)
+ check_not_action_assignements(action_id, action_cat_id, action_data_id, result)
+
+
+def add_rule(policy_id, meta_rule_id, rule,
+ instructions={"chain": [{"security_pipeline": "rbac"}]}):
+ req = requests.post(URL.format("/policies/{}/rules".format(policy_id)),
+ json={
+ "meta_rule_id": meta_rule_id,
+ "rule": rule,
+ "instructions": instructions,
+ "enabled": True
+ },
+ headers=HEADERS)
+ req.raise_for_status()
+ result = req.json()
+ check_rule_in_result(result)
+ rule_id = list(result["rules"].keys())[0]
+ check_policy_id_in_dict(policy_id, result["rules"][rule_id])
+ check_meta_rule_id_in_dict(meta_rule_id, result["rules"][rule_id])
+ check_rule_in_dict(rule, result["rules"][rule_id])
+ return rule_id
+
+
+def check_rule(policy_id, meta_rule_id, rule_id, rule):
+ req = requests.get(URL.format("/policies/{}/rules".format(policy_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_rule_in_result(result)
+ check_policy_id_in_dict(policy_id, result["rules"])
+ check_rule_id_in_list(meta_rule_id, rule_id, rule, result["rules"]["rules"])
+
+
+def delete_rule(policy_id, rule_id):
+ req = requests.delete(URL.format("/policies/{}/rules/{}".format(policy_id, rule_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_result(result)
+ req = requests.get(URL.format("/policies/{}/rules".format(policy_id)))
+ req.raise_for_status()
+ result = req.json()
+ check_rule_in_result(result)
+ check_policy_id_in_dict(policy_id, result["rules"])
+ check_rule_id_not_in_list(rule_id, result["rules"]["rules"])
+
+
+def check_meta_rule():
+ req = requests.get(URL.format("/meta_rules/"))
+ req.raise_for_status()
+ result = req.json()
+ print(result)
+ return result
+
+
+def create_policy(scenario, model_id, meta_rule_list):
+ LOGGER.info("Creating policy {}".format(scenario.policy_name))
+ _policies = check_policy()
+ for _policy_id, _policy_value in _policies["policies"].items():
+ if _policy_value['name'] == scenario.policy_name:
+ policy_id = _policy_id
+ break
+ else:
+ policy_id = add_policy(name=scenario.policy_name, genre=scenario.policy_genre)
+
+ update_policy(policy_id, model_id)
+
+ for meta_rule_id in meta_rule_list:
+ LOGGER.debug("add_meta_rule_to_model {} {}".format(model_id, meta_rule_id))
+ models.add_meta_rule_to_model(model_id, meta_rule_id)
+
+ LOGGER.info("Add subject data")
+ for subject_cat_name in scenario.subject_data:
+ for subject_data_name in scenario.subject_data[subject_cat_name]:
+ data_id = scenario.subject_data[subject_cat_name][subject_data_name] = add_subject_data(
+ policy_id=policy_id,
+ category_id=scenario.subject_categories[subject_cat_name], name=subject_data_name)
+ scenario.subject_data[subject_cat_name][subject_data_name] = data_id
+ LOGGER.info("Add object data")
+ for object_cat_name in scenario.object_data:
+ for object_data_name in scenario.object_data[object_cat_name]:
+ data_id = scenario.object_data[object_cat_name][object_data_name] = add_object_data(
+ policy_id=policy_id,
+ category_id=scenario.object_categories[object_cat_name], name=object_data_name)
+ scenario.object_data[object_cat_name][object_data_name] = data_id
+ LOGGER.info("Add action data")
+ for action_cat_name in scenario.action_data:
+ for action_data_name in scenario.action_data[action_cat_name]:
+ data_id = scenario.action_data[action_cat_name][action_data_name] = add_action_data(
+ policy_id=policy_id,
+ category_id=scenario.action_categories[action_cat_name], name=action_data_name)
+ scenario.action_data[action_cat_name][action_data_name] = data_id
+
+ LOGGER.info("Add subjects")
+ for name in scenario.subjects:
+ scenario.subjects[name] = add_subject(policy_id, name=name)
+ LOGGER.info("Add objects")
+ for name in scenario.objects:
+ scenario.objects[name] = add_object(policy_id, name=name)
+ LOGGER.info("Add actions")
+ for name in scenario.actions:
+ scenario.actions[name] = add_action(policy_id, name=name)
+
+ LOGGER.info("Add subject assignments")
+ for subject_name in scenario.subject_assignments:
+ if type(scenario.subject_assignments[subject_name]) in (list, tuple):
+ for items in scenario.subject_assignments[subject_name]:
+ for subject_category_name in items:
+ subject_id = scenario.subjects[subject_name]
+ subject_cat_id = scenario.subject_categories[subject_category_name]
+ for data in scenario.subject_assignments[subject_name]:
+ subject_data_id = scenario.subject_data[subject_category_name][
+ data[subject_category_name]]
+ add_subject_assignments(policy_id, subject_id, subject_cat_id,
+ subject_data_id)
+ else:
+ for subject_category_name in scenario.subject_assignments[subject_name]:
+ subject_id = scenario.subjects[subject_name]
+ subject_cat_id = scenario.subject_categories[subject_category_name]
+ subject_data_id = scenario.subject_data[subject_category_name][
+ scenario.subject_assignments[subject_name][subject_category_name]]
+ add_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id)
+
+ LOGGER.info("Add object assignments")
+ for object_name in scenario.object_assignments:
+ if type(scenario.object_assignments[object_name]) in (list, tuple):
+ for items in scenario.object_assignments[object_name]:
+ for object_category_name in items:
+ object_id = scenario.objects[object_name]
+ object_cat_id = scenario.object_categories[object_category_name]
+ for data in scenario.object_assignments[object_name]:
+ object_data_id = scenario.object_data[object_category_name][
+ data[object_category_name]]
+ add_object_assignments(policy_id, object_id, object_cat_id, object_data_id)
+ else:
+ for object_category_name in scenario.object_assignments[object_name]:
+ object_id = scenario.objects[object_name]
+ object_cat_id = scenario.object_categories[object_category_name]
+ object_data_id = scenario.object_data[object_category_name][
+ scenario.object_assignments[object_name][object_category_name]]
+ add_object_assignments(policy_id, object_id, object_cat_id, object_data_id)
+
+ LOGGER.info("Add action assignments")
+ for action_name in scenario.action_assignments:
+ if type(scenario.action_assignments[action_name]) in (list, tuple):
+ for items in scenario.action_assignments[action_name]:
+ for action_category_name in items:
+ action_id = scenario.actions[action_name]
+ action_cat_id = scenario.action_categories[action_category_name]
+ for data in scenario.action_assignments[action_name]:
+ action_data_id = scenario.action_data[action_category_name][
+ data[action_category_name]]
+ add_action_assignments(policy_id, action_id, action_cat_id, action_data_id)
+ else:
+ for action_category_name in scenario.action_assignments[action_name]:
+ action_id = scenario.actions[action_name]
+ action_cat_id = scenario.action_categories[action_category_name]
+ action_data_id = scenario.action_data[action_category_name][
+ scenario.action_assignments[action_name][action_category_name]]
+ add_action_assignments(policy_id, action_id, action_cat_id, action_data_id)
+
+ LOGGER.info("Add rules")
+ for meta_rule_name in scenario.rules:
+ meta_rule_value = scenario.meta_rule[meta_rule_name]
+ for rule in scenario.rules[meta_rule_name]:
+ data_list = []
+ _meta_rule = list(meta_rule_value["value"])
+ for data_name in rule["rule"]:
+ category_name = _meta_rule.pop(0)
+ if category_name in scenario.subject_categories:
+ data_list.append(scenario.subject_data[category_name][data_name])
+ elif category_name in scenario.object_categories:
+ data_list.append(scenario.object_data[category_name][data_name])
+ elif category_name in scenario.action_categories:
+ data_list.append(scenario.action_data[category_name][data_name])
+ instructions = rule["instructions"]
+ add_rule(policy_id, meta_rule_value["id"], data_list, instructions)
+ return policy_id
diff --git a/old/python_moonclient/python_moonclient/core/slaves.py b/old/python_moonclient/python_moonclient/core/slaves.py
new file mode 100644
index 00000000..77b127c1
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/core/slaves.py
@@ -0,0 +1,59 @@
+import logging
+import requests
+from python_moonclient.core import config
+from python_moonclient.core.check_tools import *
+
+LOGGER = logging.getLogger("moonclient.core.slaves")
+
+URL = None
+HEADERS = None
+
+
+def init(consul_host, consul_port):
+ conf_data = config.get_config_data(consul_host, consul_port)
+ global URL, HEADERS
+ URL = "http://{}:{}".format(
+ conf_data['manager_host'],
+ conf_data['manager_port'])
+ URL = URL + "{}"
+ HEADERS = {"content-type": "application/json"}
+
+
+def get_slaves():
+ req = requests.get(URL.format("/slaves"))
+ req.raise_for_status()
+ result = req.json()
+ check_slaves_in_result(result)
+ return result
+
+
+def set_slave(name):
+ slaves = get_slaves().get("slaves", [])
+ check_name_in_slaves(name, slaves)
+ req = requests.patch(URL.format("/slaves/{}".format(name)),
+ headers=HEADERS,
+ json={
+ "op": "replace",
+ "variable": "configured",
+ "value": True
+ })
+ req.raise_for_status()
+ result = req.json()
+ check_slaves_in_result(result)
+ return get_slaves()
+
+
+def delete_slave(name):
+ slaves = get_slaves().get("slaves", [])
+ check_name_in_slaves(name, slaves)
+ req = requests.patch(URL.format("/slaves/{}".format(name)),
+ headers=HEADERS,
+ json={
+ "op": "replace",
+ "variable": "configured",
+ "value": False
+ })
+ req.raise_for_status()
+ result = req.json()
+ check_slaves_in_result(result)
+ return get_slaves()
diff --git a/old/python_moonclient/python_moonclient/moon.py b/old/python_moonclient/python_moonclient/moon.py
new file mode 100644
index 00000000..0bd80921
--- /dev/null
+++ b/old/python_moonclient/python_moonclient/moon.py
@@ -0,0 +1,37 @@
+import sys
+import python_moonclient
+
+from cliff.app import App
+from cliff.commandmanager import CommandManager
+
+
+class Moon(App):
+
+ def __init__(self):
+ super(Moon, self).__init__(
+ description='Moon client',
+ version=python_moonclient.__version__,
+ command_manager=CommandManager('moon'),
+ deferred_help=True,
+ )
+
+
+def main(argv=sys.argv[1:]):
+ myapp = Moon()
+ return myapp.run(argv)
+
+
+if __name__ == '__main__':
+ # import python_moonclient.python_moonclient.core.import_json
+ # import python_moonclient.python_moonclient.core.models
+ # import python_moonclient.core.policies.init as init_policy
+ # import python_moonclient.core.pdp.init as init_pdp
+ # consul_host = "consul"
+ # consul_port = "8005"
+
+ # init_model(consul_host, consul_port)
+ # init_policy.init(consul_host, consul_port)
+ # init_pdp.init(consul_host, consul_port)
+ # import_json('/home/fcellier/moon/tests/functional/scenario_available/rbac.json')
+
+ sys.exit(Moon(sys.argv[1:]))
diff --git a/old/python_moonclient/requirements.txt b/old/python_moonclient/requirements.txt
new file mode 100644
index 00000000..bbcd8cd5
--- /dev/null
+++ b/old/python_moonclient/requirements.txt
@@ -0,0 +1,4 @@
+werkzeug
+flask
+requests
+cliff
diff --git a/old/python_moonclient/setup.py b/old/python_moonclient/setup.py
new file mode 100644
index 00000000..4a3a8233
--- /dev/null
+++ b/old/python_moonclient/setup.py
@@ -0,0 +1,75 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from setuptools import setup, find_packages
+import python_moonclient
+import python_moonclient.core
+
+with open('requirements.txt') as f:
+ required = f.read().splitlines()
+
+
+setup(
+
+ name='python-moonclient',
+
+ version=python_moonclient.__version__,
+
+ packages=find_packages(),
+
+ author='Thomas Duval & Ruan He',
+
+ author_email='thomas.duval@orange.com, ruan.he@orange.com',
+
+ description='client lib for all the Moon components',
+
+ long_description=open('README.md').read(),
+
+ install_requires=required,
+
+ include_package_data=True,
+
+ url='https://git.opnfv.org/cgit/moon',
+
+ classifiers=[
+ 'Programming Language :: Python :: 3',
+ 'Development Status :: 1 - Planning',
+ 'License :: OSI Approved',
+ 'Natural Language :: English',
+ 'Operating System :: OS Independent',
+ ],
+
+ entry_points={
+ 'console_scripts': [
+ 'moon = python_moonclient.moon:main'
+ ],
+ 'moon': [
+ 'pdp_list = python_moonclient.cli.pdps:Pdps',
+ 'pdp_create = python_moonclient.cli.pdps:CreatePdp',
+ 'pdp_delete = python_moonclient.cli.pdps:DeletePdp',
+ 'pdp_map = python_moonclient.cli.pdps:MapPdp',
+ 'policy_list = python_moonclient.cli.policies:Policies',
+ 'policy_delete = python_moonclient.cli.policies:DeletePolicy',
+ 'project_list = python_moonclient.cli.projects:Projects',
+ 'slave_list = python_moonclient.cli.slaves:Slaves',
+ 'slave_set = python_moonclient.cli.slaves:SetSlave',
+ 'slave_delete = python_moonclient.cli.slaves:DeleteSlave',
+ 'authz_send = python_moonclient.cli.authz:SendAuthz',
+ 'import = python_moonclient.cli.import:Import',
+ 'export = python_moonclient.cli.export:Export',
+ 'model_list = python_moonclient.cli.models:Models',
+ 'subject_data_list = python_moonclient.cli.policies:SubjectDatas',
+ 'object_data_list = python_moonclient.cli.policies:ObjectDatas',
+ 'action_data_list = python_moonclient.cli.policies:ActionDatas',
+ 'subject_category_list = python_moonclient.cli.models:SubjectCategories',
+ 'object_category_list = python_moonclient.cli.models:ObjectCategories',
+ 'action_category_list = python_moonclient.cli.models:ActionCategories',
+ 'subject_category_create = python_moonclient.cli.models:SubjectCategoryAdd',
+ 'subject_data_create = python_moonclient.cli.policies:CreateSubjectData',
+ 'metarule_list = python_moonclient.cli.policies:MetaRules'
+ ],
+ }
+
+)
diff --git a/old/python_moonclient/tests/unit_python/__init__.py b/old/python_moonclient/tests/unit_python/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/__init__.py
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_action_assignments.py b/old/python_moonclient/tests/unit_python/conf/conf_action_assignments.py
new file mode 100644
index 00000000..43c4db59
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_action_assignments.py
@@ -0,0 +1,51 @@
+from .conf_all import *
+
+POST_ACTION_ASSIGNMENT = {
+ "action_assignments":{
+ "1":{
+ "policy_id": "1",
+ "action_id": "2",
+ "category_id": "1",
+ "assignments": ["1"]
+ }
+ }
+}
+
+POST_OTHER_ACTION_ASSIGNMENT = {
+ "action_assignments":{
+ "2":{
+ "policy_id": "1",
+ "action_id": "2",
+ "category_id": "1",
+ "assignments": ["2"]
+ }
+ }
+}
+
+DELETE_ACTION_ASSIGNMENT = {
+ "action_assignments":{
+
+ }
+}
+
+
+def conf_action_assignments(m):
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/action_assignments/2/1/1',
+ [{'headers': {'X-Subject-Token': "111111111"}, 'json': POST_ACTION_ASSIGNMENT},
+ {'headers': {'X-Subject-Token': "111111111"}, 'json': DELETE_ACTION_ASSIGNMENT}]
+ )
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/action_assignments/2/1/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_OTHER_ACTION_ASSIGNMENT
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/policies/2/action_assignments',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_ACTION_ASSIGNMENT
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/policies/2/action_assignments/2/1/1',
+ json=RESULT_OK
+ ) \ No newline at end of file
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_action_categories.py b/old/python_moonclient/tests/unit_python/conf/conf_action_categories.py
new file mode 100644
index 00000000..909befb2
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_action_categories.py
@@ -0,0 +1,32 @@
+
+
+ACTION_CATEGORIES = {
+ "action_categories": {
+ "1": {
+ "name": "action_cat_1",
+ "description": "description of the category"
+ }
+ }
+}
+
+POST_ACTION_CATEGORIES = {
+ "action_categories": {
+ "1": {
+ "name": "action_cat_1",
+ "description": "description of the category"
+ }
+ }
+}
+
+
+def conf_action_categories(m):
+ m.register_uri(
+ 'GET', 'http://manager:30001/action_categories',
+ headers={'X-Subject-Token': "111111111"},
+ json=ACTION_CATEGORIES
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/action_categories',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_ACTION_CATEGORIES
+ ) \ No newline at end of file
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_action_data.py b/old/python_moonclient/tests/unit_python/conf/conf_action_data.py
new file mode 100644
index 00000000..fb6f501c
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_action_data.py
@@ -0,0 +1,66 @@
+from .conf_all import *
+
+ACTION_DATA = {
+ "action_data":[{
+ "policy_id": "1",
+ "category_id": "1",
+ "data": {
+ "1": {
+ "name": "name of the data",
+ "description": "description of the data"
+ }
+ }
+ }]
+}
+
+POST_ACTION_DATA = {
+ "action_data":{
+ "policy_id": "1",
+ "category_id": "1",
+ "data": {
+ "1": {
+ "name": "name of the data",
+ "description": "description of the data"
+ }
+ }
+ }
+}
+
+POST_OTHER_ACTION_DATA = {
+ "action_data":{
+ "policy_id": "1",
+ "category_id": "1",
+ "data": {
+ "2": {
+ "name": "name of the data",
+ "description": "description of the data"
+ }
+ }
+ }
+}
+
+DELETE_ACTION_DATA= {
+ "action_data":[{
+ "policy_id": "1",
+ "category_id": "1",
+ "data":{}
+ }]
+}
+
+
+def conf_action_data(m):
+ m.register_uri(
+ 'POST', 'http://manager:30001/policies/2/action_data/1',
+ [{'headers': {'X-Subject-Token': "111111111"}, 'json': POST_ACTION_DATA},
+ {'headers': {'X-Subject-Token': "111111111"}, 'json': POST_OTHER_ACTION_DATA}]
+ )
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/action_data/1',
+ [{'headers': {'X-Subject-Token': "111111111"}, 'json': ACTION_DATA},
+ {'headers': {'X-Subject-Token': "111111111"}, 'json': DELETE_ACTION_DATA}]
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/policies/2/action_data/1/1',
+ headers={'X-Subject-Token': "111111111"},
+ json=RESULT_OK
+ ) \ No newline at end of file
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_actions.py b/old/python_moonclient/tests/unit_python/conf/conf_actions.py
new file mode 100644
index 00000000..4e6784dd
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_actions.py
@@ -0,0 +1,111 @@
+from .conf_all import *
+
+ACTIONS = {
+ "actions":{
+ "1": {
+ "name": "name of the action",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": ["1"]
+ }
+ }
+}
+
+ACTIONS_AFTER_POST = {
+ "actions":{
+ "1": {
+ "name": "name of the action",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": ["1"]
+ },
+ "2": {
+ "name": "test_action",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": []
+ }
+ }
+}
+
+ACTIONS_AFTER_PATCH = {
+ "actions":{
+ "1": {
+ "name": "name of the action",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": ["1"]
+ },
+ "2": {
+ "name": "test_action",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": ["2"]
+ }
+ }
+}
+
+
+POST_ACTIONS = {
+ "actions":{
+ "2": {
+ "name": "test_action",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": []
+ }
+ }
+}
+
+PATCH_ACTIONS = {
+ "actions":{
+ "2": {
+ "name": "test_action",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": ["2"]
+ }
+ }
+}
+
+def conf_actions(m):
+ m.register_uri(
+ 'GET', 'http://manager:30001/actions',
+ headers={'X-Subject-Token': "111111111"},
+ json=ACTIONS
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/actions',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_ACTIONS
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/actions/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=RESULT_OK
+ )
+ m.register_uri(
+ 'PATCH', 'http://manager:30001/policies/2/actions/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=PATCH_ACTIONS
+ )
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/actions',
+ headers={'X-Subject-Token': "111111111"},
+ json=ACTIONS_AFTER_PATCH
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/policies/2/actions',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_ACTIONS
+ )
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/actions/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=PATCH_ACTIONS
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/policies/2/actions/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=RESULT_OK
+ ) \ No newline at end of file
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_all.py b/old/python_moonclient/tests/unit_python/conf/conf_all.py
new file mode 100644
index 00000000..b87d4fe7
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_all.py
@@ -0,0 +1 @@
+RESULT_OK = {"result": "OK"}
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_meta_rules.py b/old/python_moonclient/tests/unit_python/conf/conf_meta_rules.py
new file mode 100644
index 00000000..67c14ddf
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_meta_rules.py
@@ -0,0 +1,44 @@
+from .conf_all import *
+
+
+META_RULES = {
+ "meta_rules": {
+ "1": {
+ "name": "test_meta_rule",
+ "algorithm": "name of the meta rule algorithm",
+ "subject_categories": ["1"],
+ "object_categories": ["1"],
+ "action_categories": ["1"]
+ }
+ }
+}
+
+POST_META_RULES = {
+ "meta_rules": {
+ "1": {
+ "name": "test_meta_rule",
+ "algorithm": "name of the meta rule algorithm",
+ "subject_categories": ["1"],
+ "object_categories": ["1"],
+ "action_categories": ["1"]
+ }
+ }
+}
+
+
+def conf_meta_rules(m):
+ m.register_uri(
+ 'GET', 'http://manager:30001/meta_rules',
+ headers={'X-Subject-Token': "111111111"},
+ json=META_RULES
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/meta_rules',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_META_RULES
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/meta_rules/1',
+ headers={'X-Subject-Token': "111111111"},
+ json=RESULT_OK
+ )
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_models.py b/old/python_moonclient/tests/unit_python/conf/conf_models.py
new file mode 100644
index 00000000..930af88f
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_models.py
@@ -0,0 +1,94 @@
+from .conf_all import *
+
+
+MODELS = {
+ "models": {
+ "1": {
+ "name": "model 1",
+ "description": "description model 1",
+ "meta_rules": [{
+ "meta_rule_id": "1"
+ }, {
+ "meta_rule_id": "2"
+ }]
+ },
+ "2": {
+ "name": "model 2",
+ "description": "description model 2",
+ "meta_rules": ["2"]
+ },
+ "3": {
+ "name": "test_model",
+ "description": "description model 3",
+ "meta_rules": ["2"]
+ }
+ }
+}
+
+POST_MODEL = {
+ "models": {
+ "3": {
+ "name": "test_model",
+ "description": "description model 3",
+ "meta_rules": ["2"]
+ }
+ }
+}
+
+PATCH_MODEL = {
+ "models": {
+ "3": {
+ "name": "test_model",
+ "description": "description model 3",
+ "meta_rules": ["2", "1"]
+ }
+ }
+}
+
+
+MODELS_AFTER_POST = {
+"models": {
+ "1": {
+ "name": "model 1",
+ "description": "description model 1",
+ "meta_rules": [{
+ "meta_rule_id": "1"
+ }, {
+ "meta_rule_id": "2"
+ }]
+ },
+ "2": {
+ "name": "model 2",
+ "description": "description model 2",
+ "meta_rules": ["2"]
+ },
+ "3": {
+ "name": "test_model",
+ "description": "description model 3",
+ "meta_rules": ["1", "2"]
+ }
+ }
+}
+
+
+def conf_models(m):
+ m.register_uri(
+ 'GET', 'http://manager:30001/models',
+ [{'json': MODELS, 'headers': {'X-Subject-Token': "111111111"}},
+ {'json': MODELS_AFTER_POST, 'headers': {'X-Subject-Token': "111111111"}}]
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/models',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_MODEL
+ )
+ m.register_uri(
+ 'PATCH', 'http://manager:30001/models/3',
+ headers={'X-Subject-Token': "111111111"},
+ json=PATCH_MODEL
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/models/3',
+ headers={'X-Subject-Token': "111111111"},
+ json=RESULT_OK
+ ) \ No newline at end of file
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_object_assignments.py b/old/python_moonclient/tests/unit_python/conf/conf_object_assignments.py
new file mode 100644
index 00000000..9e88e03e
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_object_assignments.py
@@ -0,0 +1,51 @@
+from .conf_all import *
+
+POST_OBJECT_ASSIGNMENT = {
+ "object_assignments":{
+ "1":{
+ "policy_id": "1",
+ "object_id": "2",
+ "category_id": "1",
+ "assignments": ["1"]
+ }
+ }
+}
+
+POST_OTHER_OBJECT_ASSIGNMENT = {
+ "object_assignments":{
+ "2":{
+ "policy_id": "1",
+ "object_id": "2",
+ "category_id": "1",
+ "assignments": ["2"]
+ }
+ }
+}
+
+DELETE_OBJECT_ASSIGNMENT = {
+ "object_assignments":{
+
+ }
+}
+
+
+def conf_object_assignments(m):
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/object_assignments/2/1/1',
+ [{'headers': {'X-Subject-Token': "111111111"}, 'json': POST_OBJECT_ASSIGNMENT},
+ {'headers': {'X-Subject-Token': "111111111"}, 'json': DELETE_OBJECT_ASSIGNMENT}]
+ )
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/object_assignments/2/1/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_OTHER_OBJECT_ASSIGNMENT
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/policies/2/object_assignments',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_OBJECT_ASSIGNMENT
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/policies/2/object_assignments/2/1/1',
+ json=RESULT_OK
+ ) \ No newline at end of file
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_object_categories.py b/old/python_moonclient/tests/unit_python/conf/conf_object_categories.py
new file mode 100644
index 00000000..a942f9c6
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_object_categories.py
@@ -0,0 +1,31 @@
+
+OBJECT_CATEGORIES = {
+ "object_categories": {
+ "1": {
+ "name": "object_cat_1",
+ "description": "description of the category"
+ }
+ }
+}
+
+POST_OBJECT_CATEGORIES = {
+ "object_categories": {
+ "1": {
+ "name": "object_cat_1",
+ "description": "description of the category"
+ }
+ }
+}
+
+
+def conf_object_categories(m):
+ m.register_uri(
+ 'GET', 'http://manager:30001/object_categories',
+ headers={'X-Subject-Token': "111111111"},
+ json=OBJECT_CATEGORIES
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/object_categories',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_OBJECT_CATEGORIES
+ )
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_object_data.py b/old/python_moonclient/tests/unit_python/conf/conf_object_data.py
new file mode 100644
index 00000000..8fa81d69
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_object_data.py
@@ -0,0 +1,67 @@
+
+from .conf_all import *
+
+OBJECT_DATA = {
+ "object_data":[{
+ "policy_id": "1",
+ "category_id": "1",
+ "data": {
+ "1": {
+ "name": "name of the data",
+ "description": "description of the data"
+ }
+ }
+ }]
+}
+
+POST_OBJECT_DATA = {
+ "object_data":{
+ "policy_id": "1",
+ "category_id": "1",
+ "data": {
+ "1": {
+ "name": "name of the data",
+ "description": "description of the data"
+ }
+ }
+ }
+}
+
+POST_OTHER_OBJECT_DATA = {
+ "object_data":{
+ "policy_id": "1",
+ "category_id": "1",
+ "data": {
+ "2": {
+ "name": "name of the data",
+ "description": "description of the data"
+ }
+ }
+ }
+}
+
+DELETE_OBJECT_DATA= {
+ "object_data":[{
+ "policy_id": "1",
+ "category_id": "1",
+ "data":{}
+ }]
+}
+
+
+def conf_object_data(m):
+ m.register_uri(
+ 'POST', 'http://manager:30001/policies/2/object_data/1',
+ [{'headers': {'X-Subject-Token': "111111111"}, 'json': POST_OBJECT_DATA},
+ {'headers': {'X-Subject-Token': "111111111"}, 'json': POST_OTHER_OBJECT_DATA}]
+ )
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/object_data/1',
+ [{'headers': {'X-Subject-Token': "111111111"}, 'json': OBJECT_DATA},
+ {'headers': {'X-Subject-Token': "111111111"}, 'json': DELETE_OBJECT_DATA}]
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/policies/2/object_data/1/1',
+ headers={'X-Subject-Token': "111111111"},
+ json=RESULT_OK
+ )
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_objects.py b/old/python_moonclient/tests/unit_python/conf/conf_objects.py
new file mode 100644
index 00000000..cf3e7aa4
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_objects.py
@@ -0,0 +1,112 @@
+from .conf_all import *
+
+OBJECTS = {
+ "objects":{
+ "1": {
+ "name": "name of the object",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": ["1"]
+ }
+ }
+}
+
+OBJECTS_AFTER_POST = {
+ "objects":{
+ "1": {
+ "name": "name of the object",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": ["1"]
+ },
+ "2": {
+ "name": "test_object",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": []
+ }
+ }
+}
+
+OBJECTS_AFTER_PATCH = {
+ "objects":{
+ "1": {
+ "name": "name of the object",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": ["1"]
+ },
+ "2": {
+ "name": "test_object",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": ["2"]
+ }
+ }
+}
+
+
+POST_OBJECTS = {
+ "objects":{
+ "2": {
+ "name": "test_object",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": []
+ }
+ }
+}
+
+PATCH_OBJECTS = {
+ "objects":{
+ "2": {
+ "name": "test_object",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": ["2"]
+ }
+ }
+}
+
+def conf_objects(m):
+ m.register_uri(
+ 'GET', 'http://manager:30001/objects',
+ [{'json': OBJECTS, 'headers': {'X-Subject-Token': "111111111"}},
+ {'json': OBJECTS_AFTER_POST, 'headers': {'X-Subject-Token': "111111111"}},
+ {'json': OBJECTS, 'headers': {'X-Subject-Token': "111111111"}}]
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/objects',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_OBJECTS
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/objects/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=RESULT_OK
+ )
+ m.register_uri(
+ 'PATCH', 'http://manager:30001/policies/2/objects/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=PATCH_OBJECTS
+ )
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/objects',
+ headers={'X-Subject-Token': "111111111"},
+ json=OBJECTS_AFTER_PATCH
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/policies/2/objects',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_OBJECTS
+ )
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/objects/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=PATCH_OBJECTS
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/policies/2/objects/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=RESULT_OK
+ )
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_pdps.py b/old/python_moonclient/tests/unit_python/conf/conf_pdps.py
new file mode 100644
index 00000000..1090fccb
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_pdps.py
@@ -0,0 +1,95 @@
+from .conf_all import *
+
+PDPS = {
+ "pdps": {
+ "1": {
+ "name": "...",
+ "security_pipeline": [],
+ "keystone_project_id": "",
+ "description": "...",
+ }
+ }
+ }
+
+
+POST_PDP = {
+ "pdps": {
+ "2": {
+ "name": "test_pdp",
+ "security_pipeline": [],
+ "keystone_project_id": "",
+ "description": "..."
+ }
+ }
+ }
+
+PATCH_PDP = {
+ "pdps": {
+ "2": {
+ "name": "test_pdp",
+ "security_pipeline": [],
+ "keystone_project_id": "0c4e939acacf4376bdcd1129f1a054ad",
+ "description": "..."
+ }
+ }
+ }
+
+PDPS_AFTER_POST = {
+ "pdps": {
+ "1": {
+ "name": "...",
+ "security_pipeline": [],
+ "keystone_project_id": "",
+ "description": "...",
+ },
+
+ "2": {
+ "name": "test_pdp",
+ "security_pipeline": [],
+ "keystone_project_id": "",
+ "description": "...",
+ }
+ }
+ }
+
+PDPS_AFTER_PATCH = {
+ "pdps": {
+ "1": {
+ "name": "...",
+ "security_pipeline": [],
+ "keystone_project_id": "",
+ "description": "...",
+ },
+
+ "2": {
+ "name": "test_pdp",
+ "security_pipeline": [],
+ "keystone_project_id": "0c4e939acacf4376bdcd1129f1a054ad",
+ "description": "...",
+ }
+ }
+ }
+
+def conf_pdps(m):
+ m.register_uri(
+ 'GET', 'http://manager:30001/pdp',
+ [{'json': PDPS, 'headers': {'X-Subject-Token': "111111111"}},
+ {'json': PDPS_AFTER_POST, 'headers': {'X-Subject-Token': "111111111"}},
+ {'json': PDPS_AFTER_PATCH, 'headers': {'X-Subject-Token': "111111111"}},
+ {'json': PDPS, 'headers': {'X-Subject-Token': "111111111"}}]
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/pdp',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_PDP
+ )
+ m.register_uri(
+ 'PATCH', 'http://manager:30001/pdp/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=PATCH_PDP
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/pdp/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=RESULT_OK
+ ) \ No newline at end of file
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_policies.py b/old/python_moonclient/tests/unit_python/conf/conf_policies.py
new file mode 100644
index 00000000..bf6883bc
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_policies.py
@@ -0,0 +1,78 @@
+from .conf_all import *
+
+POLICIES = {
+ "policies":{
+ "1": {
+ "name": "test_policy",
+ "model_id": "1",
+ "genre": "authz",
+ "description": "Description of the policy",
+ }
+ }
+}
+
+POLICIES_AFTER_POST= {
+ "policies":{
+ "1": {
+ "name": "test_policy",
+ "model_id": "1",
+ "genre": "authz",
+ "description": "Description of the policy",
+ },
+ "2": {
+ "name": "test_policy",
+ "model_id": "",
+ "genre": "",
+ "description": "Description of the policy",
+ }
+ }
+}
+
+
+POST_POLICIES ={
+ "policies":{
+ "2": {
+ "name": "test_policy",
+ "model_id": "",
+ "genre": "",
+ "description": "Description of the policy",
+ }
+ }
+}
+
+
+PATCH_POLICIES ={
+ "policies":{
+ "2": {
+ "name": "test_policy",
+ "model_id": "3",
+ "genre": "authz",
+ "description": "Description of the policy",
+ }
+ }
+}
+
+
+def conf_policies(m):
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies',
+ [{'json': POLICIES, 'headers': {'X-Subject-Token': "111111111"}},
+ {'json': POLICIES_AFTER_POST, 'headers': {'X-Subject-Token': "111111111"}},
+ {'json': POLICIES, 'headers': {'X-Subject-Token': "111111111"}}]
+
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/policies',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_POLICIES
+ )
+ m.register_uri(
+ 'PATCH', 'http://manager:30001/policies/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=PATCH_POLICIES
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/policies/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=RESULT_OK
+ ) \ No newline at end of file
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_projects.py b/old/python_moonclient/tests/unit_python/conf/conf_projects.py
new file mode 100644
index 00000000..63be05e0
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_projects.py
@@ -0,0 +1,44 @@
+
+
+PROJECTS = {
+ "projects": [
+ {
+ "is_domain": False,
+ "description": None,
+ "domain_id": "admin",
+ "enabled": True,
+ "id": "0c4e939acacf4376bdcd1129f1a054ad",
+ "links": {
+ "self": "http://example.com/identity/v3/projects/0c4e939acacf4376bdcd1129f1a054ad"
+ },
+ "name": "admin",
+ "parent_id": None,
+ "tags": []
+ },
+ {
+ "is_domain": False,
+ "description": None,
+ "domain_id": "default",
+ "enabled": True,
+ "id": "0cbd49cbf76d405d9c86562e1d579bd3",
+ "links": {
+ "self": "http://example.com/identity/v3/projects/0cbd49cbf76d405d9c86562e1d579bd3"
+ },
+ "name": "demo",
+ "parent_id": None,
+ "tags": []
+ }
+ ]
+}
+
+
+def conf_projects(m):
+ m.register_uri(
+ 'GET', 'http://keystone:5000/v3/projects',
+ headers={'X-Subject-Token': "111111111"},
+ json=PROJECTS
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/auth/tokens',
+ headers={'X-Subject-Token': "111111111"}
+ )
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_rules.py b/old/python_moonclient/tests/unit_python/conf/conf_rules.py
new file mode 100644
index 00000000..30b8c682
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_rules.py
@@ -0,0 +1,46 @@
+from .conf_all import *
+
+RULES = {
+ "rules":{
+ "policy_id": "2",
+ "rules": [{
+ "meta_rule_id": "1",
+ "id": "1",
+ "rule": ["1", "1", "1"]
+ }]
+ }
+}
+
+POST_RULES = {
+ "rules":{
+ "1":{
+ "policy_id": "2",
+ "meta_rule_id": "1",
+ "rule": ["1", "1", "1"]
+ }
+ }
+}
+
+DELETE_RULES = {
+ "rules":{
+ "policy_id": "2",
+ "rules": []
+ }
+}
+
+
+def conf_rule_assignments(m):
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/rules',
+ [{'headers': {'X-Subject-Token': "111111111"}, 'json': RULES},
+ {'headers': {'X-Subject-Token': "111111111"}, 'json': DELETE_RULES}]
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/policies/2/rules',
+ [{'headers': {'X-Subject-Token': "111111111"}, 'json': POST_RULES}]
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/policies/2/rules/1',
+ headers={'X-Subject-Token': "111111111"},
+ json=RESULT_OK
+ ) \ No newline at end of file
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_subject_assignments.py b/old/python_moonclient/tests/unit_python/conf/conf_subject_assignments.py
new file mode 100644
index 00000000..92b689c0
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_subject_assignments.py
@@ -0,0 +1,51 @@
+from .conf_all import *
+
+POST_SUBJECT_ASSIGNMENT = {
+ "subject_assignments":{
+ "1":{
+ "policy_id": "1",
+ "subject_id": "2",
+ "category_id": "1",
+ "assignments": ["1"]
+ }
+ }
+}
+
+DELETE_SUBJECT_ASSIGNMENT = {
+ "subject_assignments":{
+
+ }
+}
+
+POST_OTHER_SUBJECT_ASSIGNMENT = {
+ "subject_assignments":{
+ "2":{
+ "policy_id": "1",
+ "subject_id": "2",
+ "category_id": "1",
+ "assignments": ["2"]
+ }
+ }
+}
+
+
+def conf_subject_assignments(m):
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/subject_assignments/2/1/1',
+ [{'headers': {'X-Subject-Token': "111111111"}, 'json': POST_SUBJECT_ASSIGNMENT},
+ {'headers': {'X-Subject-Token': "111111111"}, 'json': DELETE_SUBJECT_ASSIGNMENT}]
+ )
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/subject_assignments/2/1/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_OTHER_SUBJECT_ASSIGNMENT
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/policies/2/subject_assignments',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_SUBJECT_ASSIGNMENT
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/policies/2/subject_assignments/2/1/1',
+ json=RESULT_OK
+ ) \ No newline at end of file
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_subject_categories.py b/old/python_moonclient/tests/unit_python/conf/conf_subject_categories.py
new file mode 100644
index 00000000..e59a458a
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_subject_categories.py
@@ -0,0 +1,30 @@
+
+SUBJECT_CATEGORIES = {
+ "subject_categories": {
+ "1": {
+ "name": "subject_cat_1",
+ "description": "description of the category"
+ }
+ }
+}
+
+POST_SUBJECT_CATEGORIES = {
+ "subject_categories": {
+ "1": {
+ "name": "subject_cat_1",
+ "description": "description of the category"
+ }
+ }
+}
+
+def conf_subject_categories(m):
+ m.register_uri(
+ 'GET', 'http://manager:30001/subject_categories',
+ headers={'X-Subject-Token': "111111111"},
+ json=SUBJECT_CATEGORIES
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/subject_categories',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_SUBJECT_CATEGORIES
+ )
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_subject_data.py b/old/python_moonclient/tests/unit_python/conf/conf_subject_data.py
new file mode 100644
index 00000000..19db217d
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_subject_data.py
@@ -0,0 +1,67 @@
+from .conf_all import *
+
+SUBJECT_DATA = {
+ "subject_data":[{
+ "policy_id": "1",
+ "category_id": "1",
+ "data": {
+ "1": {
+ "name": "name of the data",
+ "description": "description of the data"
+ }
+ }
+ }]
+}
+
+POST_SUBJECT_DATA = {
+ "subject_data":{
+ "policy_id": "1",
+ "category_id": "1",
+ "data": {
+ "1": {
+ "name": "name of the data",
+ "description": "description of the data"
+ }
+ }
+ }
+}
+
+
+POST_OTHER_SUBJECT_DATA = {
+ "subject_data":{
+ "policy_id": "1",
+ "category_id": "1",
+ "data": {
+ "2": {
+ "name": "name of the data",
+ "description": "description of the data"
+ }
+ }
+ }
+}
+
+DELETE_SUBJECT_DATA= {
+ "subject_data":[{
+ "policy_id": "1",
+ "category_id": "1",
+ "data":{}
+ }]
+}
+
+
+def conf_subject_data(m):
+ m.register_uri(
+ 'POST', 'http://manager:30001/policies/2/subject_data/1',
+ [{'headers': {'X-Subject-Token': "111111111"}, 'json': POST_SUBJECT_DATA},
+ {'headers': {'X-Subject-Token': "111111111"}, 'json': POST_OTHER_SUBJECT_DATA}]
+ )
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/subject_data/1',
+ [{'headers': {'X-Subject-Token': "111111111"}, 'json': SUBJECT_DATA},
+ {'headers': {'X-Subject-Token': "111111111"}, 'json': DELETE_SUBJECT_DATA}]
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/policies/2/subject_data/1/1',
+ headers={'X-Subject-Token': "111111111"},
+ json=RESULT_OK
+ ) \ No newline at end of file
diff --git a/old/python_moonclient/tests/unit_python/conf/conf_subjects.py b/old/python_moonclient/tests/unit_python/conf/conf_subjects.py
new file mode 100644
index 00000000..bde6093f
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conf/conf_subjects.py
@@ -0,0 +1,112 @@
+from .conf_all import *
+
+SUBJECTS = {
+ "subjects":{
+ "1": {
+ "name": "name of the subject",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": ["1"]
+ }
+ }
+}
+
+SUBJECTS_AFTER_POST= {
+ "subjects":{
+ "1": {
+ "name": "name of the subject",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": ["1"]
+ },
+ "2": {
+ "name": "test_subject",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": []
+ }
+ }
+}
+
+SUBJECTS_AFTER_PATCH= {
+ "subjects":{
+ "1": {
+ "name": "name of the subject",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": ["1"]
+ },
+ "2": {
+ "name": "test_subject",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": ["2"]
+ }
+ }
+}
+
+POST_SUBJECTS = {
+ "subjects":{
+ "2": {
+ "name": "test_subject",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": []
+ }
+ }
+}
+
+
+PATCH_SUBJECTS = {
+ "subjects":{
+ "2": {
+ "name": "test_subject",
+ "keystone_id": "1",
+ "description": "a description",
+ "policy_list": ["2"]
+ }
+ }
+}
+
+def conf_subjects(m):
+ m.register_uri(
+ 'GET', 'http://manager:30001/subjects',
+ [{'json': SUBJECTS, 'headers': {'X-Subject-Token': "111111111"}},
+ {'json': SUBJECTS_AFTER_POST, 'headers': {'X-Subject-Token': "111111111"}},
+ {'json': SUBJECTS, 'headers': {'X-Subject-Token': "111111111"}}]
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/subjects',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_SUBJECTS
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/subjects/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=RESULT_OK
+ )
+ m.register_uri(
+ 'PATCH', 'http://manager:30001/policies/2/subjects/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=PATCH_SUBJECTS
+ )
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/subjects',
+ headers={'X-Subject-Token': "111111111"},
+ json=SUBJECTS_AFTER_PATCH
+ )
+ m.register_uri(
+ 'POST', 'http://manager:30001/policies/2/subjects',
+ headers={'X-Subject-Token': "111111111"},
+ json=POST_SUBJECTS
+ )
+ m.register_uri(
+ 'GET', 'http://manager:30001/policies/2/subjects/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=PATCH_SUBJECTS
+ )
+ m.register_uri(
+ 'DELETE', 'http://manager:30001/policies/2/subjects/2',
+ headers={'X-Subject-Token': "111111111"},
+ json=RESULT_OK
+ ) \ No newline at end of file
diff --git a/old/python_moonclient/tests/unit_python/conftest.py b/old/python_moonclient/tests/unit_python/conftest.py
new file mode 100644
index 00000000..bd3e5f4d
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/conftest.py
@@ -0,0 +1,52 @@
+import pytest
+import requests_mock
+from . import mock_config
+
+from .conf.conf_projects import *
+from .conf.conf_models import *
+from .conf.conf_pdps import *
+from .conf.conf_action_categories import *
+from .conf.conf_object_categories import *
+from .conf.conf_subject_categories import *
+from .conf.conf_meta_rules import *
+from .conf.conf_action_assignments import *
+from .conf.conf_object_assignments import *
+from .conf.conf_subject_assignments import *
+from .conf.conf_policies import *
+from .conf.conf_subjects import *
+from .conf.conf_objects import *
+from .conf.conf_actions import *
+from .conf.conf_subject_data import *
+from .conf.conf_object_data import *
+from .conf.conf_action_data import *
+from .conf.conf_rules import *
+
+
+@pytest.fixture(autouse=True)
+def no_requests(monkeypatch):
+ """ Modify the response from Requests module
+ """
+ with requests_mock.Mocker(real_http=True) as m:
+ mock_config.register_consul(m)
+
+ conf_projects(m)
+ conf_models(m)
+ conf_pdps(m)
+ conf_action_categories(m)
+ conf_object_categories(m)
+ conf_subject_categories(m)
+ conf_meta_rules(m)
+ conf_policies(m)
+ conf_subjects(m)
+ conf_objects(m)
+ conf_actions(m)
+ conf_object_data(m)
+ conf_subject_data(m)
+ conf_action_data(m)
+ conf_action_assignments(m)
+ conf_object_assignments(m)
+ conf_subject_assignments(m)
+ conf_rule_assignments(m)
+ yield m
+
+
diff --git a/old/python_moonclient/tests/unit_python/mock_config.py b/old/python_moonclient/tests/unit_python/mock_config.py
new file mode 100644
index 00000000..b6c42d76
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/mock_config.py
@@ -0,0 +1,64 @@
+from . import utilities
+
+
+components_manager_mock = {
+ "port": 8082,
+ "bind": "0.0.0.0",
+ "hostname": "manager",
+ "container": "wukongsun/moon_manager:v4.3.1",
+ "external": {
+ "port": 30001,
+ "hostname": "88.88.88.2"
+ }
+}
+
+
+openstack_keystone_mock = {
+ "url": "http://keystone:5000/v3",
+ "user": "admin",
+ "password": "p4ssw0rd",
+ "domain": "default",
+ "project": "admin",
+ "check_token": False,
+ "certificate": False,
+ "external": {
+ "url": "http://88.88.88.2:30006/v3"
+ }
+}
+
+
+def register_consul(m):
+ for component in utilities.COMPONENTS:
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/{}'.format(component),
+ json=[{'Key': component, 'Value': utilities.get_b64_conf(component)}]
+ )
+
+ m.register_uri(
+ 'GET', 'http://manager:30001',
+ json={}
+ )
+ m.register_uri(
+ 'GET', 'http://keystone:5000/v3',
+ json={}
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/auth/tokens',
+ headers={'X-Subject-Token': "111111111"}
+ )
+ m.register_uri(
+ 'DELETE', 'http://keystone:5000/v3/auth/tokens',
+ headers={'X-Subject-Token': "111111111"}
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default',
+ json={"users": {}}
+ )
+ m.register_uri(
+ 'GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default',
+ json={"users": {}}
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/users/',
+ json={"users": [{"id": "1111111111111"}]}
+ )
diff --git a/old/python_moonclient/tests/unit_python/requirements.txt b/old/python_moonclient/tests/unit_python/requirements.txt
new file mode 100644
index 00000000..3c1ad607
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/requirements.txt
@@ -0,0 +1,2 @@
+pytest
+requests_mock \ No newline at end of file
diff --git a/old/python_moonclient/tests/unit_python/test_config.py b/old/python_moonclient/tests/unit_python/test_config.py
new file mode 100644
index 00000000..e4effec6
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/test_config.py
@@ -0,0 +1,8 @@
+from python_moonclient.core.cli_exceptions import MoonCliException
+
+
+def test_authz_request():
+ from python_moonclient.core import config
+ conf_data = config.get_config_data("consul", 8500)
+ if not isinstance(conf_data, dict):
+ raise MoonCliException("Unexpected error : the conf data is not a dictionnary")
diff --git a/old/python_moonclient/tests/unit_python/test_models.py b/old/python_moonclient/tests/unit_python/test_models.py
new file mode 100644
index 00000000..fed889e3
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/test_models.py
@@ -0,0 +1,38 @@
+from python_moonclient.core.models import *
+
+
+def test_models():
+ init("consul", 8500)
+ check_model()
+ model_id = add_model()
+ check_model(model_id)
+ delete_model(model_id)
+
+
+def test_meta_data_subject():
+ category_id = add_subject_category()
+ check_subject_category(category_id)
+ # TODO (asteroide): must implement the deletion of linked data
+ # delete_subject_category(category_id)
+
+
+def test_meta_data_object():
+ category_id = add_object_category()
+ check_object_category(category_id)
+ # TODO (asteroide): must implement the deletion of linked data
+ # delete_object_category(category_id)
+
+
+def test_meta_data_action():
+ category_id = add_action_category()
+ check_action_category(category_id)
+ # TODO (asteroide): must implement the deletion of linked data
+ # delete_action_category(category_id)
+
+
+def test_meta_rule():
+ meta_rule_id, scat_id, ocat_id, acat_id = add_categories_and_meta_rule()
+ check_meta_rule(meta_rule_id, scat_id, ocat_id, acat_id)
+ delete_meta_rule(meta_rule_id)
+
+
diff --git a/old/python_moonclient/tests/unit_python/test_pdp.py b/old/python_moonclient/tests/unit_python/test_pdp.py
new file mode 100644
index 00000000..e979aeae
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/test_pdp.py
@@ -0,0 +1,17 @@
+from python_moonclient.core.pdp import *
+
+def test_pdp():
+ init("consul", 8500)
+ projects = get_keystone_projects()
+ admin_project_id = None
+ for _project in projects['projects']:
+ if _project['name'] == "admin":
+ admin_project_id = _project['id']
+ if admin_project_id is None:
+ raise MoonCliException("Unexpected results, could not find the admin project")
+ check_pdp()
+ pdp_id = add_pdp()
+ check_pdp(pdp_id)
+ map_to_keystone(pdp_id=pdp_id, keystone_project_id=admin_project_id)
+ check_pdp(pdp_id=pdp_id, keystone_project_id=admin_project_id)
+ delete_pdp(pdp_id)
diff --git a/old/python_moonclient/tests/unit_python/test_policies.py b/old/python_moonclient/tests/unit_python/test_policies.py
new file mode 100644
index 00000000..9ab9003e
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/test_policies.py
@@ -0,0 +1,161 @@
+from python_moonclient.core.policies import *
+from python_moonclient.core.models import *
+from python_moonclient.core import policies
+from python_moonclient.core import models
+
+
+def test_policies():
+ policies.init("consul", 8500)
+ models.init("consul", 8500)
+ check_policy()
+ policy_id = add_policy()
+ check_policy(policy_id)
+ delete_policy(policy_id)
+
+
+def test_subjects():
+ policy_id = add_policy()
+ subject_id = add_subject()
+
+ update_subject(subject_id=subject_id, policy_id=policy_id)
+
+ check_subject(subject_id=subject_id, policy_id=policy_id)
+
+ delete_subject(subject_id, policy_id=policy_id)
+ delete_subject(subject_id)
+
+
+def test_objects():
+ policy_id = add_policy()
+ object_id = add_object()
+
+ update_object(object_id=object_id, policy_id=policy_id)
+ check_object(object_id=object_id, policy_id=policy_id)
+
+ delete_object(object_id=object_id, policy_id=policy_id)
+ delete_object(object_id=object_id)
+
+
+def test_actions():
+ policy_id = add_policy()
+ action_id = add_action()
+
+ update_action(action_id=action_id, policy_id=policy_id)
+ check_action(action_id=action_id, policy_id=policy_id)
+
+ delete_action(action_id=action_id, policy_id=policy_id)
+ delete_action(action_id=action_id)
+
+
+def test_subject_data():
+ policy_id = add_policy()
+
+ model_id = add_model()
+
+ update_policy(policy_id, model_id)
+
+ meta_rule_id, subject_cat_id, object_cat_id, action_cat_id = add_categories_and_meta_rule()
+ add_meta_rule_to_model(model_id, meta_rule_id)
+
+ subject_data_id = add_subject_data(policy_id=policy_id, category_id=subject_cat_id)
+ check_subject_data(policy_id=policy_id, data_id=subject_data_id, category_id=subject_cat_id)
+ delete_subject_data(policy_id=policy_id, data_id=subject_data_id, category_id=subject_cat_id)
+
+
+def test_object_data():
+ policy_id = add_policy()
+
+ model_id = add_model()
+
+ update_policy(policy_id, model_id)
+
+ meta_rule_id, object_cat_id, object_cat_id, action_cat_id = add_categories_and_meta_rule()
+ add_meta_rule_to_model(model_id, meta_rule_id)
+
+ object_data_id = add_object_data(policy_id=policy_id, category_id=object_cat_id)
+ check_object_data(policy_id=policy_id, data_id=object_data_id, category_id=object_cat_id)
+ delete_object_data(policy_id=policy_id, data_id=object_data_id, category_id=object_cat_id)
+ print('ok')
+
+def test_action_data():
+ policy_id = add_policy()
+
+ model_id = add_model()
+
+ update_policy(policy_id, model_id)
+
+ meta_rule_id, action_cat_id, action_cat_id, action_cat_id = add_categories_and_meta_rule()
+ add_meta_rule_to_model(model_id, meta_rule_id)
+
+ action_data_id = add_action_data(policy_id=policy_id, category_id=action_cat_id)
+ check_action_data(policy_id=policy_id, data_id=action_data_id, category_id=action_cat_id)
+ delete_action_data(policy_id=policy_id, data_id=action_data_id, category_id=action_cat_id)
+
+
+def test_assignments():
+ policy_id = add_policy()
+
+ model_id = add_model()
+
+ update_policy(policy_id, model_id)
+
+ meta_rule_id, subject_cat_id, object_cat_id, action_cat_id = add_categories_and_meta_rule()
+ add_meta_rule_to_model(model_id, meta_rule_id)
+
+ subject_data_id = add_subject_data(policy_id=policy_id, category_id=subject_cat_id)
+ subject_data_id_bis = add_subject_data(policy_id=policy_id, category_id=subject_cat_id)
+ object_data_id = add_object_data(policy_id=policy_id, category_id=object_cat_id)
+ object_data_id_bis = add_object_data(policy_id=policy_id, category_id=object_cat_id)
+ action_data_id = add_action_data(policy_id=policy_id, category_id=action_cat_id)
+ action_data_id_bis = add_action_data(policy_id=policy_id, category_id=action_cat_id)
+
+ subject_id = add_subject(policy_id)
+ object_id = add_object(policy_id)
+ action_id = add_action(policy_id)
+
+ add_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id)
+ add_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id_bis)
+ add_object_assignments(policy_id, object_id, object_cat_id, object_data_id)
+ add_object_assignments(policy_id, object_id, object_cat_id, object_data_id_bis)
+ add_action_assignments(policy_id, action_id, action_cat_id, action_data_id)
+ add_action_assignments(policy_id, action_id, action_cat_id, action_data_id_bis)
+
+ check_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id)
+ check_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id_bis)
+ check_object_assignments(policy_id, object_id, object_cat_id, object_data_id)
+ check_object_assignments(policy_id, object_id, object_cat_id, object_data_id_bis)
+ check_action_assignments(policy_id, action_id, action_cat_id, action_data_id)
+ check_action_assignments(policy_id, action_id, action_cat_id, action_data_id_bis)
+
+ delete_subject_assignment(policy_id, subject_id, subject_cat_id, subject_data_id)
+ delete_object_assignment(policy_id, object_id, object_cat_id, object_data_id)
+ delete_action_assignment(policy_id, action_id, action_cat_id, action_data_id)
+
+
+def test_rule():
+ policy_id = add_policy()
+
+ model_id = add_model()
+
+ update_policy(policy_id, model_id)
+
+ meta_rule_id, subject_cat_id, object_cat_id, action_cat_id = add_categories_and_meta_rule()
+ add_meta_rule_to_model(model_id, meta_rule_id)
+
+ subject_data_id = add_subject_data(policy_id=policy_id, category_id=subject_cat_id)
+ object_data_id = add_object_data(policy_id=policy_id, category_id=object_cat_id)
+ action_data_id = add_action_data(policy_id=policy_id, category_id=action_cat_id)
+
+ subject_id = add_subject(policy_id)
+ object_id = add_object(policy_id)
+ action_id = add_action(policy_id)
+
+ add_subject_assignments(policy_id, subject_id, subject_cat_id, subject_data_id)
+ add_object_assignments(policy_id, object_id, object_cat_id, object_data_id)
+ add_action_assignments(policy_id, action_id, action_cat_id, action_data_id)
+
+ rule_id = add_rule(policy_id, meta_rule_id, [subject_data_id, object_data_id, action_data_id])
+ check_rule(policy_id, meta_rule_id, rule_id, [subject_data_id, object_data_id, action_data_id])
+
+ delete_rule(policy_id, rule_id)
+
diff --git a/old/python_moonclient/tests/unit_python/utilities.py b/old/python_moonclient/tests/unit_python/utilities.py
new file mode 100644
index 00000000..ae2932c7
--- /dev/null
+++ b/old/python_moonclient/tests/unit_python/utilities.py
@@ -0,0 +1,153 @@
+import base64
+import json
+
+CONF = {
+ "openstack": {
+ "keystone": {
+ "url": "http://keystone:5000/v3",
+ "user": "admin",
+ "check_token": False,
+ "password": "p4ssw0rd",
+ "domain": "default",
+ "certificate": False,
+ "project": "admin",
+ "external": {
+ "url": "http://keystone:5000/v3",
+ }
+ }
+ },
+ "components": {
+ "wrapper": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_wrapper:v4.3",
+ "timeout": 5,
+ "hostname": "wrapper"
+ },
+ "manager": {
+ "bind": "0.0.0.0",
+ "port": 8082,
+ "container": "wukongsun/moon_manager:v4.3",
+ "hostname": "manager",
+ "external": {
+ "hostname": "manager",
+ "port": 30001
+ }
+ },
+ "port_start": 31001,
+ "orchestrator": {
+ "bind": "0.0.0.0",
+ "port": 8083,
+ "container": "wukongsun/moon_orchestrator:v4.3",
+ "hostname": "orchestrator"
+ },
+ "interface": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_interface:v4.3",
+ "hostname": "interface"
+ }
+ },
+ "plugins": {
+ "session": {
+ "port": 8082,
+ "container": "asteroide/session:latest"
+ },
+ "authz": {
+ "port": 8081,
+ "container": "wukongsun/moon_authz:v4.3"
+ }
+ },
+ "logging": {
+ "handlers": {
+ "file": {
+ "filename": "/tmp/moon.log",
+ "class": "logging.handlers.RotatingFileHandler",
+ "level": "DEBUG",
+ "formatter": "custom",
+ "backupCount": 3,
+ "maxBytes": 1048576
+ },
+ "console": {
+ "class": "logging.StreamHandler",
+ "formatter": "brief",
+ "level": "INFO",
+ "stream": "ext://sys.stdout"
+ }
+ },
+ "formatters": {
+ "brief": {
+ "format": "%(levelname)s %(name)s %(message)-30s"
+ },
+ "custom": {
+ "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s"
+ }
+ },
+ "root": {
+ "handlers": [
+ "console"
+ ],
+ "level": "ERROR"
+ },
+ "version": 1,
+ "loggers": {
+ "moon": {
+ "handlers": [
+ "console",
+ "file"
+ ],
+ "propagate": False,
+ "level": "DEBUG"
+ }
+ }
+ },
+ "slave": {
+ "name": None,
+ "master": {
+ "url": None,
+ "login": None,
+ "password": None
+ }
+ },
+ "docker": {
+ "url": "tcp://172.88.88.1:2376",
+ "network": "moon"
+ },
+ "database": {
+ "url": "sqlite:///database.db",
+ # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon",
+ "driver": "sql"
+ },
+ "messenger": {
+ "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon"
+ }
+}
+
+COMPONENTS = (
+ "logging",
+ "openstack/keystone",
+ "database",
+ "slave",
+ "components/manager",
+ "components/orchestrator",
+ "components/interface",
+ "components/wrapper",
+)
+
+
+def get_b64_conf(component=None):
+ if component == "components":
+ return base64.b64encode(
+ json.dumps(CONF["components"]).encode('utf-8')+b"\n").decode('utf-8')
+ elif component in CONF:
+ return base64.b64encode(
+ json.dumps(
+ CONF[component]).encode('utf-8')+b"\n").decode('utf-8')
+ elif not component:
+ return base64.b64encode(
+ json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8')
+ elif "/" in component:
+ key1, _, key2 = component.partition("/")
+ return base64.b64encode(
+ json.dumps(
+ CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8')
diff --git a/old/python_moondb/.gitignore b/old/python_moondb/.gitignore
new file mode 100644
index 00000000..9c29724f
--- /dev/null
+++ b/old/python_moondb/.gitignore
@@ -0,0 +1,106 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+
+/tests/unit_python/database.db
diff --git a/old/python_moondb/Changelog b/old/python_moondb/Changelog
new file mode 100644
index 00000000..9236c260
--- /dev/null
+++ b/old/python_moondb/Changelog
@@ -0,0 +1,128 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+CHANGES
+=======
+
+0.1.0
+-----
+- First version of the moon_db library.
+
+1.0.0
+-----
+- First public version of the moon_db library.
+
+1.0.1
+-----
+- Update setup.py to force the installation of requirements.
+
+1.0.2
+-----
+- Test PyPi upload
+
+1.0.3
+-----
+- Fix a bug in core.py
+- Update db_manager
+
+1.1.0
+-----
+- When adding a subject, check the existence of that user in the Keystone DB and
+ create it if necessary
+
+1.2.0
+-----
+- Update the db_manager in order to use it for tests
+
+1.2.1
+-----
+- Update moon_db_manager in order to use it for unit tests
+
+1.2.2
+-----
+- Fix a bug in moon_db_manager
+
+1.2.3
+-----
+- Cleanup moon_db code
+
+1.2.4
+-----
+- Update the name of the library (from moon_db)
+
+1.2.5
+-----
+- Code cleaning
+
+1.2.6
+-----
+- Remove some code duplication in moon_db
+- handle the extra field for the perimeter
+
+1.2.7
+-----
+- Fix some bugs
+
+1.2.8
+-----
+- Add unique constraints on db tables
+
+1.2.9
+-----
+- Add some verifications when deleting some elements in database
+
+1.2.10
+-----
+- Update the migration script because of a bug introduced in 1.2.8 in rule table
+- Fix bugs due to the previous version
+
+1.2.11
+------
+- adding test cases for perimeter
+- adding subject_object_action to model_test
+- update import of exception
+- add unit_test to test_model
+- add validation for not accepting blank perimeter name or category name
+
+1.2.12
+------
+- Fix the SubjectExisting exception problem
+
+1.2.13
+------
+- Add validations and refactor test cases
+
+1.2.14
+------
+- Fix some bugs for the manager and clean the code
+
+1.2.15
+------
+- Fix test cases after removing syntax error in exceptions
+
+1.2.16
+------
+- Fix the "key length error" in meta_rule table
+
+1.2.17
+------
+- adding extra validation for addition and deletion dependencies
+
+1.2.18
+------
+- adding changelog
+
+1.2.19
+------
+- adding extra validation for update requests
+
+1.2.20
+------
+- adding extra validation of rule content
+- update validation for category with meta-rule dependencies
+- update validation on updating meta-rule
+- applying PyLint
+- fixing Jira issues related to update policy \ No newline at end of file
diff --git a/old/python_moondb/LICENSE b/old/python_moondb/LICENSE
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/old/python_moondb/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/old/python_moondb/MANIFEST.in b/old/python_moondb/MANIFEST.in
new file mode 100644
index 00000000..02655837
--- /dev/null
+++ b/old/python_moondb/MANIFEST.in
@@ -0,0 +1,10 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+include README.md
+include LICENSE
+include setup.py
+include requirements.txt
+graft bin \ No newline at end of file
diff --git a/old/python_moondb/README.md b/old/python_moondb/README.md
new file mode 100644
index 00000000..d36c6ae3
--- /dev/null
+++ b/old/python_moondb/README.md
@@ -0,0 +1,32 @@
+# python_moondb
+
+This package contains the database module for the Moon project
+It is designed to provide a driver to access the Moon database.
+
+For any other information, refer to the parent project:
+
+ https://git.opnfv.org/moon
+
+## Build
+### Build Python Package
+```bash
+cd ${MOON_HOME}/python_moondb
+python3 setup.py sdist bdist_wheel
+```
+
+### Push Python Package to PIP
+```bash
+cd ${MOON_HOME}/python_moondb
+gpg --detach-sign -u "${GPG_ID}" -a dist/python_moondb-X.Y.Z-py3-none-any.whl
+gpg --detach-sign -u "${GPG_ID}" -a dist/python_moondb-X.Y.Z.tar.gz
+twine upload dist/python_moondb-X.Y.Z-py3-none-any.whl dist/python_moondb-X.Y.Z-py3-none-any.whl.asc
+twine upload dist/python_moondb-X.Y.Z.tar.gz dist/python_moondb-X.Y.Z.tar.gz.asc
+```
+
+## Test
+### Python Unit Test
+launch Docker for Python unit tests
+```bash
+cd ${MOON_HOME}/python_moondb
+docker run --rm --volume $(pwd):/data wukongsun/moon_python_unit_test:latest
+``` \ No newline at end of file
diff --git a/old/python_moondb/bin/drop_tables.sql b/old/python_moondb/bin/drop_tables.sql
new file mode 100644
index 00000000..f5f65ea7
--- /dev/null
+++ b/old/python_moondb/bin/drop_tables.sql
@@ -0,0 +1,18 @@
+use moon;
+drop table action_assignments;
+drop table object_assignments;
+drop table subject_assignments;
+drop table subject_scopes;
+drop table action_scopes;
+drop table object_scopes;
+drop table action_categories;
+drop table subject_categories;
+drop table object_categories;
+drop table rules;
+drop table sub_meta_rules;
+drop table actions;
+drop table objects;
+drop table subjects;
+drop table tenants;
+drop table intra_extensions;
+show tables;
diff --git a/old/python_moondb/python_moondb/__init__.py b/old/python_moondb/python_moondb/__init__.py
new file mode 100644
index 00000000..37c9a725
--- /dev/null
+++ b/old/python_moondb/python_moondb/__init__.py
@@ -0,0 +1,6 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+__version__ = "1.2.20"
diff --git a/old/python_moondb/python_moondb/api/__init__.py b/old/python_moondb/python_moondb/api/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/python_moondb/python_moondb/api/__init__.py
diff --git a/old/python_moondb/python_moondb/api/keystone.py b/old/python_moondb/python_moondb/api/keystone.py
new file mode 100644
index 00000000..57521c36
--- /dev/null
+++ b/old/python_moondb/python_moondb/api/keystone.py
@@ -0,0 +1,105 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import os
+import requests
+import json
+from uuid import uuid4
+import logging
+from python_moonutilities import exceptions, configuration
+from python_moonutilities.security_functions import filter_input, login, logout
+from python_moondb.api.managers import Managers
+
+logger = logging.getLogger("moon.db.api.keystone")
+
+
+class KeystoneManager(Managers):
+
+ def __init__(self, connector=None):
+ self.driver = connector.driver
+ Managers.KeystoneManager = self
+ conf = configuration.get_configuration("openstack/keystone")['openstack/keystone']
+
+ self.__url = conf['url']
+ self.__user = conf['user']
+ self.__password = conf['password']
+ self.__domain = conf['domain']
+ self.__project = conf['project']
+ try:
+ os.environ.pop("http_proxy")
+ os.environ.pop("https_proxy")
+ except KeyError:
+ pass
+
+ def __get(self, endpoint, _exception=exceptions.KeystoneError):
+ _headers = login()
+ req = requests.get("{}{}".format(self.__url, endpoint), headers=_headers, verify=False)
+ if req.status_code not in (200, 201):
+ logger.error(req.text)
+ raise _exception
+ data = req.json()
+ logout(_headers)
+ return data
+
+ def __post(self, endpoint, data=None, _exception=exceptions.KeystoneError):
+ _headers = login()
+ req = requests.post("{}{}".format(self.__url, endpoint),
+ data=json.dumps(data),
+ headers=_headers, verify=False)
+ if req.status_code == 409:
+ logger.warning(req.text)
+ raise exceptions.KeystoneUserConflict
+ if req.status_code not in (200, 201):
+ logger.error(req.text)
+ raise _exception
+ data = req.json()
+ logout(_headers)
+ return data
+
+ def list_projects(self):
+ return self.__get(endpoint="/projects/", _exception=exceptions.KeystoneProjectError)
+
+ @filter_input
+ def create_project(self, tenant_dict):
+ if "name" not in tenant_dict:
+ raise exceptions.KeystoneProjectError("Cannot get the project name.")
+ _project = {
+ "project": {
+ "description": tenant_dict['description'] if 'description' in tenant_dict else "",
+ "domain_id": tenant_dict['domain'] if 'domain' in tenant_dict else "default",
+ "enabled": True,
+ "is_domain": False,
+ "name": tenant_dict['name']
+ }
+ }
+ return self.__post(endpoint="/projects/",
+ data=_project,
+ _exception=exceptions.KeystoneProjectError)
+
+ @filter_input
+ def get_user_by_name(self, username, domain_id="default"):
+ return self.__get(endpoint="/users?name={}&domain_id={}".format(username, domain_id),
+ _exception=exceptions.KeystoneUserError)
+
+ @filter_input
+ def create_user(self, subject_dict):
+ _user = {
+ "user": {
+ "enabled": True,
+ "name": subject_dict['name'] if 'name' in subject_dict else uuid4().hex,
+ }
+ }
+ if 'project' in subject_dict:
+ _user['user']['default_project_id'] = subject_dict['project']
+ if 'domain' in subject_dict:
+ _user['user']['domain_id'] = subject_dict['domain']
+ if 'password' in subject_dict:
+ _user['user']['password'] = subject_dict['password']
+ try:
+ return self.__post(endpoint="/users/",
+ data=_user,
+ _exception=exceptions.KeystoneUserError)
+ except exceptions.KeystoneUserConflict:
+ return True
diff --git a/old/python_moondb/python_moondb/api/managers.py b/old/python_moondb/python_moondb/api/managers.py
new file mode 100644
index 00000000..414725f6
--- /dev/null
+++ b/old/python_moondb/python_moondb/api/managers.py
@@ -0,0 +1,16 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import logging
+
+logger = logging.getLogger("moon.db.api.managers")
+
+
+class Managers(object):
+ """Object that links managers together"""
+ ModelManager = None
+ KeystoneManager = None
+ PDPManager = None
+ PolicyManager = None
diff --git a/old/python_moondb/python_moondb/api/model.py b/old/python_moondb/python_moondb/api/model.py
new file mode 100644
index 00000000..4f6c34cb
--- /dev/null
+++ b/old/python_moondb/python_moondb/api/model.py
@@ -0,0 +1,338 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from uuid import uuid4
+import logging
+from python_moonutilities import exceptions
+from python_moonutilities.security_functions import filter_input, enforce
+from python_moondb.api.managers import Managers
+import copy
+
+logger = logging.getLogger("moon.db.api.model")
+
+
+class ModelManager(Managers):
+
+ def __init__(self, connector=None):
+ self.driver = connector.driver
+ Managers.ModelManager = self
+
+ @enforce(("read", "write"), "models")
+ def update_model(self, user_id, model_id, value):
+ if model_id not in self.driver.get_models(model_id=model_id):
+ raise exceptions.ModelUnknown
+
+ if not value['name'].strip():
+ raise exceptions.ModelContentError('Model name invalid')
+
+ if 'meta_rules' not in value:
+ raise exceptions.MetaRuleUnknown
+
+ if not value['name']:
+ raise exceptions.ModelContentError
+
+ model = self.get_models(user_id=user_id, model_id=model_id)
+ model = model[next(iter(model))]
+ if ((model['meta_rules'] and value['meta_rules'] and model['meta_rules'] != value[
+ 'meta_rules']) \
+ or (model['meta_rules'] and not value['meta_rules'])):
+ policies = Managers.PolicyManager.get_policies(user_id=user_id)
+ for policy_id in policies:
+ if policies[policy_id]["model_id"] == model_id:
+ raise exceptions.DeleteModelWithPolicy
+
+ if value and 'meta_rules' in value:
+ for meta_rule_id in value['meta_rules']:
+ if not self.driver.get_meta_rules(meta_rule_id=meta_rule_id):
+ raise exceptions.MetaRuleUnknown
+
+ return self.driver.update_model(model_id=model_id, value=value)
+
+ @enforce(("read", "write"), "models")
+ def delete_model(self, user_id, model_id):
+ if model_id not in self.driver.get_models(model_id=model_id):
+ raise exceptions.ModelUnknown
+ # TODO (asteroide): check that no policy is connected to this model
+ policies = Managers.PolicyManager.get_policies(user_id=user_id)
+ for policy in policies:
+ if policies[policy]['model_id'] == model_id:
+ raise exceptions.DeleteModelWithPolicy
+ return self.driver.delete_model(model_id=model_id)
+
+ @enforce(("read", "write"), "models")
+ def add_model(self, user_id, model_id=None, value=None):
+
+ if not value['name']:
+ raise exceptions.ModelContentError
+
+ if not value['name'].strip():
+ raise exceptions.ModelContentError('Model name invalid')
+
+ models = self.driver.get_models()
+ if model_id in models:
+ raise exceptions.ModelExisting
+
+ for model in models:
+ if models[model]['name'] == value['name']:
+ raise exceptions.ModelExisting("Model Name Existed")
+ same_meta_rule_counter = 0
+ for meta_rule_id in models[model]['meta_rules']:
+ if meta_rule_id in value['meta_rules']:
+ same_meta_rule_counter += 1
+ if same_meta_rule_counter == len(value['meta_rules']) and \
+ len(models[model]['meta_rules']) == len(value['meta_rules']):
+ raise exceptions.ModelExisting("Meta Rules List Existed in another Model")
+
+ if not model_id:
+ model_id = uuid4().hex
+ if value and 'meta_rules' in value:
+ for meta_rule_id in value['meta_rules']:
+ if not meta_rule_id:
+ raise exceptions.MetaRuleUnknown
+ meta_rule = self.driver.get_meta_rules(meta_rule_id=meta_rule_id)
+ if not meta_rule:
+ raise exceptions.MetaRuleUnknown
+
+ meta_rule_content = meta_rule[next(iter(meta_rule))]
+ if (not meta_rule_content['subject_categories']) or (
+ not meta_rule_content['object_categories']) or (
+ not meta_rule_content['action_categories']):
+ raise exceptions.MetaRuleContentError
+
+ return self.driver.add_model(model_id=model_id, value=value)
+
+ @enforce("read", "models")
+ def get_models(self, user_id, model_id=None):
+ return self.driver.get_models(model_id=model_id)
+
+ @enforce(("read", "write"), "meta_rules")
+ def update_meta_rule(self, user_id, meta_rule_id, value):
+ meta_rules=self.driver.get_meta_rules()
+ if not meta_rule_id or meta_rule_id not in meta_rules:
+ raise exceptions.MetaRuleUnknown
+ self.__check_meta_rule_dependencies(user_id=user_id, meta_rule_id=meta_rule_id)
+ if value:
+ if 'subject_categories' in value:
+ for subject_category_id in value['subject_categories']:
+ if not subject_category_id or not self.driver.get_subject_categories(
+ category_id=subject_category_id):
+ raise exceptions.SubjectCategoryUnknown
+ if 'object_categories' in value:
+ for object_category_id in value['object_categories']:
+ if not object_category_id or not self.driver.get_object_categories(
+ category_id=object_category_id):
+ raise exceptions.ObjectCategoryUnknown
+ if 'action_categories' in value:
+ for action_category_id in value['action_categories']:
+ if not action_category_id or not self.driver.get_action_categories(
+ category_id=action_category_id):
+ raise exceptions.ActionCategoryUnknown
+
+ for meta_rule_obj_id in meta_rules:
+ counter_matched_list = 0
+ counter_matched_list += self.check_combination(meta_rules[meta_rule_obj_id]['subject_categories'],
+ value['subject_categories'])
+ counter_matched_list += self.check_combination(meta_rules[meta_rule_obj_id]['object_categories'],
+ value['object_categories'])
+ counter_matched_list += self.check_combination(meta_rules[meta_rule_obj_id]['action_categories'],
+ value['action_categories'])
+ if counter_matched_list == 3 and meta_rule_obj_id!=meta_rule_id:
+ raise exceptions.MetaRuleExisting("Same categories combination existed")
+
+ return self.driver.set_meta_rule(meta_rule_id=meta_rule_id, value=value)
+
+ def __check_meta_rule_dependencies(self, user_id, meta_rule_id):
+ policies = Managers.PolicyManager.get_policies(user_id=user_id)
+ for policy_id in policies:
+ rules = Managers.PolicyManager.get_rules(user_id=user_id, policy_id=policy_id,
+ meta_rule_id=meta_rule_id)
+ if len(rules['rules']):
+ raise exceptions.MetaRuleUpdateError
+
+ @enforce("read", "meta_rules")
+ def get_meta_rules(self, user_id, meta_rule_id=None):
+ return self.driver.get_meta_rules(meta_rule_id=meta_rule_id)
+
+ @enforce(("read", "write"), "meta_rules")
+ def add_meta_rule(self, user_id, meta_rule_id=None, value=None):
+
+ if not value['name']:
+ raise exceptions.MetaRuleContentError
+
+ meta_rules = self.driver.get_meta_rules()
+
+ if meta_rule_id in meta_rules:
+ raise exceptions.MetaRuleExisting
+
+ if value:
+ if 'subject_categories' in value:
+ for subject_category_id in value['subject_categories']:
+ if not self.driver.get_subject_categories(category_id=subject_category_id):
+ raise exceptions.SubjectCategoryUnknown
+ if 'object_categories' in value:
+ for object_category_id in value['object_categories']:
+ if not self.driver.get_object_categories(category_id=object_category_id):
+ raise exceptions.ObjectCategoryUnknown
+ if 'action_categories' in value:
+ for action_category_id in value['action_categories']:
+ if not self.driver.get_action_categories(category_id=action_category_id):
+ raise exceptions.ActionCategoryUnknown
+
+ for meta_rule_obj_id in meta_rules:
+ counter_matched_list = 0
+ counter_matched_list += self.check_combination(meta_rules[meta_rule_obj_id]['subject_categories'],
+ value['subject_categories'])
+ counter_matched_list += self.check_combination(meta_rules[meta_rule_obj_id]['object_categories'],
+ value['object_categories'])
+ counter_matched_list += self.check_combination(meta_rules[meta_rule_obj_id]['action_categories'],
+ value['action_categories'])
+ if counter_matched_list == 3:
+ raise exceptions.MetaRuleExisting("Same categories combination existed")
+
+ return self.driver.set_meta_rule(meta_rule_id=meta_rule_id, value=value)
+
+ @enforce(("read", "write"), "meta_rules")
+ def check_combination(self, list_one, list_two):
+ counter_removed_items = 0
+ temp_list_two = copy.deepcopy(list_two)
+ for item in list_one:
+ if item in temp_list_two:
+ temp_list_two.remove(item)
+ counter_removed_items += 1
+
+ if counter_removed_items == len(list_two) and len(list_two) == len(list_one) and len(list_two):
+ return 1
+ return 0
+
+ @enforce(("read", "write"), "meta_rules")
+ def delete_meta_rule(self, user_id, meta_rule_id=None):
+ if meta_rule_id not in self.driver.get_meta_rules(meta_rule_id=meta_rule_id):
+ raise exceptions.MetaRuleUnknown
+ # TODO (asteroide): check and/or delete data and assignments and rules linked to that meta_rule
+ models = self.get_models(user_id=user_id)
+ for model_id in models:
+ for id in models[model_id]['meta_rules']:
+ if id == meta_rule_id:
+ raise exceptions.DeleteMetaRuleWithModel
+ return self.driver.delete_meta_rule(meta_rule_id=meta_rule_id)
+
+ @enforce("read", "meta_data")
+ def get_subject_categories(self, user_id, category_id=None):
+ return self.driver.get_subject_categories(category_id=category_id)
+
+ @enforce(("read", "write"), "meta_data")
+ def add_subject_category(self, user_id, category_id=None, value=None):
+ subject_categories = self.driver.get_subject_categories(category_id=category_id)
+
+ if not value['name']:
+ raise exceptions.CategoryNameInvalid
+
+ if category_id in subject_categories:
+ raise exceptions.SubjectCategoryExisting
+
+ return self.driver.add_subject_category(name=value["name"],
+ description=value["description"], uuid=category_id)
+
+ @enforce(("read", "write"), "meta_data")
+ def delete_subject_category(self, user_id, category_id):
+ # TODO (asteroide): delete all data linked to that category
+ # TODO (asteroide): delete all meta_rules linked to that category
+ if category_id not in self.driver.get_subject_categories(category_id=category_id):
+ raise exceptions.SubjectCategoryUnknown
+ meta_rules = self.get_meta_rules(user_id=user_id)
+ for meta_rule_id in meta_rules:
+ for subject_category_id in meta_rules[meta_rule_id]['subject_categories']:
+ logger.info(
+ "delete_subject_category {} {}".format(subject_category_id, meta_rule_id))
+ logger.info("delete_subject_category {}".format(meta_rules[meta_rule_id]))
+ if subject_category_id == category_id:
+ # has_rules = self.driver.is_meta_rule_has_rules(meta_rule_id)
+ # if has_rules:
+ raise exceptions.DeleteSubjectCategoryWithMetaRule
+
+ if self.driver.is_subject_category_has_assignment(category_id):
+ raise exceptions.DeleteCategoryWithAssignment
+
+ if self.driver.is_subject_data_exist(category_id=category_id):
+ raise exceptions.DeleteCategoryWithData
+
+ return self.driver.delete_subject_category(category_id=category_id)
+
+ @enforce("read", "meta_data")
+ def get_object_categories(self, user_id, category_id=None):
+ return self.driver.get_object_categories(category_id)
+
+ @enforce(("read", "write"), "meta_data")
+ def add_object_category(self, user_id, category_id=None, value=None):
+ if not value['name']:
+ raise exceptions.CategoryNameInvalid
+
+ object_categories = self.driver.get_object_categories(category_id=category_id)
+ if category_id in object_categories:
+ raise exceptions.ObjectCategoryExisting
+
+ return self.driver.add_object_category(name=value["name"], description=value["description"],
+ uuid=category_id)
+
+ @enforce(("read", "write"), "meta_data")
+ def delete_object_category(self, user_id, category_id):
+ # TODO (asteroide): delete all data linked to that category
+ # TODO (asteroide): delete all meta_rules linked to that category
+ if category_id not in self.driver.get_object_categories(category_id=category_id):
+ raise exceptions.ObjectCategoryUnknown
+ meta_rules = self.get_meta_rules(user_id=user_id)
+ for meta_rule_id in meta_rules:
+ for object_category_id in meta_rules[meta_rule_id]['object_categories']:
+ if object_category_id == category_id:
+ # has_rules = self.driver.is_meta_rule_has_rules(meta_rule_id)
+ # if has_rules:
+ raise exceptions.DeleteObjectCategoryWithMetaRule
+
+ if self.driver.is_object_category_has_assignment(category_id):
+ raise exceptions.DeleteCategoryWithAssignment
+
+ if self.driver.is_object_data_exist(category_id=category_id):
+ raise exceptions.DeleteCategoryWithData
+
+ return self.driver.delete_object_category(category_id=category_id)
+
+ @enforce("read", "meta_data")
+ def get_action_categories(self, user_id, category_id=None):
+ return self.driver.get_action_categories(category_id=category_id)
+
+ @enforce(("read", "write"), "meta_data")
+ def add_action_category(self, user_id, category_id=None, value=None):
+
+ if not value['name']:
+ raise exceptions.CategoryNameInvalid
+
+ action_categories = self.driver.get_action_categories(category_id=category_id)
+ if category_id in action_categories:
+ raise exceptions.ActionCategoryExisting
+
+ return self.driver.add_action_category(name=value["name"], description=value["description"],
+ uuid=category_id)
+
+ @enforce(("read", "write"), "meta_data")
+ def delete_action_category(self, user_id, category_id):
+ # TODO (asteroide): delete all data linked to that category
+ # TODO (asteroide): delete all meta_rules linked to that category
+ if category_id not in self.driver.get_action_categories(category_id=category_id):
+ raise exceptions.ActionCategoryUnknown
+ meta_rules = self.get_meta_rules(user_id=user_id)
+ for meta_rule_id in meta_rules:
+ for action_category_id in meta_rules[meta_rule_id]['action_categories']:
+ if action_category_id == category_id:
+ # has_rules = self.driver.is_meta_rule_has_rules(meta_rule_id)
+ # if has_rules:
+ raise exceptions.DeleteActionCategoryWithMetaRule
+
+ if self.driver.is_action_category_has_assignment(category_id):
+ raise exceptions.DeleteCategoryWithAssignment
+
+ if self.driver.is_action_data_exist(category_id=category_id):
+ raise exceptions.DeleteCategoryWithData
+
+ return self.driver.delete_action_category(category_id=category_id)
diff --git a/old/python_moondb/python_moondb/api/pdp.py b/old/python_moondb/python_moondb/api/pdp.py
new file mode 100644
index 00000000..d0a071c9
--- /dev/null
+++ b/old/python_moondb/python_moondb/api/pdp.py
@@ -0,0 +1,51 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from uuid import uuid4
+import logging
+from python_moonutilities.security_functions import enforce
+from python_moondb.api.managers import Managers
+from python_moonutilities import exceptions
+
+logger = logging.getLogger("moon.db.api.pdp")
+
+
+class PDPManager(Managers):
+
+ def __init__(self, connector=None):
+ self.driver = connector.driver
+ Managers.PDPManager = self
+
+ @enforce(("read", "write"), "pdp")
+ def update_pdp(self, user_id, pdp_id, value):
+ if pdp_id not in self.driver.get_pdp(pdp_id=pdp_id):
+ raise exceptions.PdpUnknown
+ if value and 'security_pipeline' in value:
+ for policy_id in value['security_pipeline']:
+ if not Managers.PolicyManager.get_policies(user_id=user_id, policy_id=policy_id):
+ raise exceptions.PolicyUnknown
+ return self.driver.update_pdp(pdp_id=pdp_id, value=value)
+
+ @enforce(("read", "write"), "pdp")
+ def delete_pdp(self, user_id, pdp_id):
+ if pdp_id not in self.driver.get_pdp(pdp_id=pdp_id):
+ raise exceptions.PdpUnknown
+ return self.driver.delete_pdp(pdp_id=pdp_id)
+
+ @enforce(("read", "write"), "pdp")
+ def add_pdp(self, user_id, pdp_id=None, value=None):
+ if pdp_id in self.driver.get_pdp(pdp_id=pdp_id):
+ raise exceptions.PdpExisting
+ if not pdp_id:
+ pdp_id = uuid4().hex
+ if value and 'security_pipeline' in value:
+ for policy_id in value['security_pipeline']:
+ if not Managers.PolicyManager.get_policies(user_id=user_id, policy_id=policy_id):
+ raise exceptions.PolicyUnknown
+ return self.driver.add_pdp(pdp_id=pdp_id, value=value)
+
+ @enforce("read", "pdp")
+ def get_pdp(self, user_id, pdp_id=None):
+ return self.driver.get_pdp(pdp_id=pdp_id)
diff --git a/old/python_moondb/python_moondb/api/policy.py b/old/python_moondb/python_moondb/api/policy.py
new file mode 100644
index 00000000..03a93ff5
--- /dev/null
+++ b/old/python_moondb/python_moondb/api/policy.py
@@ -0,0 +1,751 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from uuid import uuid4
+import logging
+from python_moonutilities.security_functions import enforce
+from python_moondb.api.managers import Managers
+from python_moonutilities import exceptions
+
+# from python_moondb.core import PDPManager
+
+logger = logging.getLogger("moon.db.api.policy")
+
+
+class PolicyManager(Managers):
+
+ def __init__(self, connector=None):
+ self.driver = connector.driver
+ Managers.PolicyManager = self
+
+ def get_policy_from_meta_rules(self, user_id, meta_rule_id):
+ policies = self.PolicyManager.get_policies("admin")
+ models = self.ModelManager.get_models("admin")
+ for pdp_key, pdp_value in self.PDPManager.get_pdp(user_id).items():
+ if 'security_pipeline' not in pdp_value:
+ raise exceptions.PdpContentError
+ for policy_id in pdp_value["security_pipeline"]:
+ if not policies or policy_id not in policies:
+ raise exceptions.PolicyUnknown
+ model_id = policies[policy_id]["model_id"]
+ if not models:
+ raise exceptions.ModelUnknown
+ if model_id not in models:
+ raise exceptions.ModelUnknown
+ if meta_rule_id in models[model_id]["meta_rules"]:
+ return policy_id
+
+ @enforce(("read", "write"), "policies")
+ def update_policy(self, user_id, policy_id, value):
+
+ if not value or not value['name']:
+ raise exceptions.PolicyContentError
+
+ policyList = self.driver.get_policies(policy_id=policy_id)
+ if not policy_id or policy_id not in policyList:
+ raise exceptions.PolicyUnknown
+
+ policies = self.driver.get_policies(policy_name=value['name'])
+ if len(policies) and not (policy_id in policies):
+ raise exceptions.PolicyExisting("Policy name Existed")
+
+ if 'model_id' in value and value['model_id']:
+ if not Managers.ModelManager.get_models(user_id, model_id=value['model_id']):
+ raise exceptions.ModelUnknown
+
+ policy_obj = policyList[policy_id]
+ if (policy_obj["model_id"] and value["model_id"] != policy_obj["model_id"]):
+
+ subjects = self.driver.get_subjects(policy_id=policy_id)
+ if subjects:
+ raise exceptions.PolicyUpdateError("Policy is used in subject")
+ objects = self.driver.get_objects(policy_id=policy_id)
+ if objects:
+ raise exceptions.PolicyUpdateError("Policy is used in object")
+ actions = self.driver.get_actions(policy_id=policy_id)
+ if actions:
+ raise exceptions.PolicyUpdateError("Policy is used in action")
+
+ rules = self.driver.get_rules(policy_id=policy_id)["rules"]
+ if rules:
+ raise exceptions.PolicyUpdateError("Policy is used in rule")
+
+ subject_data = self.get_subject_data(user_id, policy_id=policy_id)
+ if subject_data and subject_data[0]["data"]:
+ raise exceptions.PolicyUpdateError("Policy is used in subject_data")
+ object_data = self.get_object_data(user_id, policy_id=policy_id)
+ if object_data and object_data[0]["data"]:
+ raise exceptions.PolicyUpdateError("Policy is used in object_data")
+ action_data = self.get_action_data(user_id, policy_id=policy_id)
+ if action_data and action_data[0]["data"]:
+ raise exceptions.PolicyUpdateError("Policy is used in action_data")
+
+ return self.driver.update_policy(policy_id=policy_id, value=value)
+
+ @enforce(("read", "write"), "policies")
+ def delete_policy(self, user_id, policy_id):
+ # TODO (asteroide): unmap PDP linked to that policy
+ if policy_id not in self.driver.get_policies(policy_id=policy_id):
+ raise exceptions.PolicyUnknown
+ pdps = self.PDPManager.get_pdp(user_id=user_id)
+ for pdp in pdps:
+ for policy_id in pdps[pdp]['security_pipeline']:
+ if policy_id == policy_id:
+ raise exceptions.DeletePolicyWithPdp
+ subjects = self.driver.get_subjects(policy_id=policy_id)
+ if subjects:
+ raise exceptions.DeletePolicyWithPerimeter
+ objects = self.driver.get_objects(policy_id=policy_id)
+ if objects:
+ raise exceptions.DeletePolicyWithPerimeter
+ actions = self.driver.get_actions(policy_id=policy_id)
+ if actions:
+ raise exceptions.DeletePolicyWithPerimeter
+
+ rules = self.driver.get_rules(policy_id=policy_id)["rules"]
+ if rules:
+ raise exceptions.DeletePolicyWithRules
+
+ subject_data = self.get_subject_data(user_id, policy_id=policy_id)
+ if subject_data and subject_data[0]["data"]:
+ raise exceptions.DeletePolicyWithData
+ object_data = self.get_object_data(user_id, policy_id=policy_id)
+ if object_data and object_data[0]["data"]:
+ raise exceptions.DeletePolicyWithData
+ action_data = self.get_action_data(user_id, policy_id=policy_id)
+ if action_data and action_data[0]["data"]:
+ raise exceptions.DeletePolicyWithData
+
+ return self.driver.delete_policy(policy_id=policy_id)
+
+ @enforce(("read", "write"), "policies")
+ def add_policy(self, user_id, policy_id=None, value=None):
+
+ if not value or not value['name']:
+ raise exceptions.PolicyContentError
+ if policy_id in self.driver.get_policies(policy_id=policy_id):
+ raise exceptions.PolicyExisting
+
+ if len(self.driver.get_policies(policy_name=value['name'])):
+ raise exceptions.PolicyExisting("Policy name Existed")
+
+ if not policy_id:
+ policy_id = uuid4().hex
+ if 'model_id' in value and value['model_id'] != "":
+ if not Managers.ModelManager.get_models(user_id, model_id=value['model_id']):
+ raise exceptions.ModelUnknown
+ return self.driver.add_policy(policy_id=policy_id, value=value)
+
+ @enforce("read", "policies")
+ def get_policies(self, user_id, policy_id=None):
+ return self.driver.get_policies(policy_id=policy_id)
+
+ @enforce("read", "perimeter")
+ def get_subjects(self, user_id, policy_id, perimeter_id=None):
+ # if not policy_id:
+ # raise exceptions.PolicyUnknown
+ if policy_id and (not self.get_policies(user_id=user_id, policy_id=policy_id)):
+ raise exceptions.PolicyUnknown
+ return self.driver.get_subjects(policy_id=policy_id, perimeter_id=perimeter_id)
+
+ @enforce(("read", "write"), "perimeter")
+ def add_subject(self, user_id, policy_id, perimeter_id=None, value=None):
+
+ if not value or "name" not in value or not value["name"].strip():
+ raise exceptions.PerimeterContentError('invalid name')
+
+ if not policy_id or (not self.get_policies(user_id=user_id, policy_id=policy_id)):
+ raise exceptions.PolicyUnknown
+
+ if perimeter_id:
+ subjects = self.driver.get_subjects(policy_id=None, perimeter_id=perimeter_id)
+ if subjects and subjects[perimeter_id]['name'] != value['name']:
+ raise exceptions.PerimeterContentError
+
+ if not perimeter_id:
+ subject_per = self.driver.get_subject_by_name(value['name'])
+ if len(subject_per):
+ perimeter_id = next(iter(subject_per))
+
+ k_user = Managers.KeystoneManager.get_user_by_name(value.get('name'))
+ if not k_user['users']:
+ k_user = Managers.KeystoneManager.create_user(value)
+ if not perimeter_id:
+ try:
+ logger.info("k_user={}".format(k_user))
+ perimeter_id = k_user['users'][0].get('id', uuid4().hex)
+ except IndexError:
+ k_user = Managers.KeystoneManager.get_user_by_name(
+ value.get('name'))
+ perimeter_id = uuid4().hex
+ except KeyError:
+ k_user = Managers.KeystoneManager.get_user_by_name(
+ value.get('name'))
+ perimeter_id = uuid4().hex
+
+ value.update(k_user['users'][0])
+
+ return self.driver.set_subject(policy_id=policy_id, perimeter_id=perimeter_id, value=value)
+
+ @enforce(("read", "write"), "perimeter")
+ def update_subject(self, user_id, perimeter_id, value):
+ logger.debug("update_subject perimeter_id = {}".format(perimeter_id))
+
+ if not perimeter_id:
+ raise exceptions.SubjectUnknown
+
+ subjects = self.driver.get_subjects(policy_id=None, perimeter_id=perimeter_id)
+ if not subjects or not (perimeter_id in subjects):
+ raise exceptions.PerimeterContentError
+
+ if 'policy_list' in value or ('name' in value and not value['name']):
+ raise exceptions.PerimeterContentError
+
+ return self.driver.update_subject(perimeter_id=perimeter_id, value=value)
+
+ @enforce(("read", "write"), "perimeter")
+ def delete_subject(self, user_id, policy_id, perimeter_id):
+
+ if not perimeter_id:
+ raise exceptions.SubjectUnknown
+
+ if not policy_id:
+ raise exceptions.PolicyUnknown
+
+ if not self.get_subjects(user_id=user_id, policy_id=policy_id, perimeter_id=perimeter_id):
+ raise exceptions.SubjectUnknown
+
+ if not self.get_policies(user_id=user_id, policy_id=policy_id):
+ raise exceptions.PolicyUnknown
+
+ subj_assig = self.driver.get_subject_assignments(policy_id=policy_id,
+ subject_id=perimeter_id)
+ if subj_assig:
+ raise exceptions.DeletePerimeterWithAssignment
+
+ return self.driver.delete_subject(policy_id=policy_id, perimeter_id=perimeter_id)
+
+ @enforce("read", "perimeter")
+ def get_objects(self, user_id, policy_id, perimeter_id=None):
+ # if not policy_id:
+ # pass
+ if policy_id and (not self.get_policies(user_id=user_id, policy_id=policy_id)):
+ raise exceptions.PolicyUnknown
+ return self.driver.get_objects(policy_id=policy_id, perimeter_id=perimeter_id)
+
+ @enforce(("read", "write"), "perimeter")
+ def add_object(self, user_id, policy_id, perimeter_id=None, value=None):
+ if not value or "name" not in value or not value["name"].strip():
+ raise exceptions.PerimeterContentError('invalid name')
+
+ if not policy_id or (not self.get_policies(user_id=user_id, policy_id=policy_id)):
+ raise exceptions.PolicyUnknown
+
+ if perimeter_id:
+ object_perimeter = self.driver.get_objects(policy_id=None, perimeter_id=perimeter_id)
+ if not object_perimeter:
+ raise exceptions.PerimeterContentError
+
+ if not perimeter_id:
+ object_perimeter = self.driver.get_object_by_name(value['name'])
+ if len(object_perimeter):
+ perimeter_id = next(iter(object_perimeter))
+
+ if perimeter_id and object_perimeter[perimeter_id]['name'] != value['name']:
+ raise exceptions.PerimeterContentError
+
+ if not perimeter_id:
+ perimeter_id = uuid4().hex
+ return self.driver.set_object(policy_id=policy_id, perimeter_id=perimeter_id, value=value)
+
+ @enforce(("read", "write"), "perimeter")
+ def update_object(self, user_id, perimeter_id, value):
+ logger.debug("update_object perimeter_id = {}".format(perimeter_id))
+
+ if not perimeter_id:
+ raise exceptions.ObjectUnknown
+
+ objects = self.driver.get_objects(policy_id=None, perimeter_id=perimeter_id)
+ if not objects or not (perimeter_id in objects):
+ raise exceptions.PerimeterContentError
+
+ if 'policy_list' in value or ('name' in value and not value['name']):
+ raise exceptions.PerimeterContentError
+
+ return self.driver.update_object(perimeter_id=perimeter_id, value=value)
+
+ @enforce(("read", "write"), "perimeter")
+ def delete_object(self, user_id, policy_id, perimeter_id):
+
+ if not perimeter_id:
+ raise exceptions.ObjectUnknown
+
+ if not policy_id:
+ raise exceptions.PolicyUnknown
+
+ if not self.get_objects(user_id=user_id, policy_id=policy_id, perimeter_id=perimeter_id):
+ raise exceptions.ObjectUnknown
+
+ if not self.get_policies(user_id=user_id, policy_id=policy_id):
+ raise exceptions.PolicyUnknown
+
+ obj_assig = self.driver.get_object_assignments(policy_id=policy_id, object_id=perimeter_id)
+ if obj_assig:
+ raise exceptions.DeletePerimeterWithAssignment
+
+ return self.driver.delete_object(policy_id=policy_id, perimeter_id=perimeter_id)
+
+ @enforce("read", "perimeter")
+ def get_actions(self, user_id, policy_id, perimeter_id=None):
+ # if not policy_id:
+ # pass
+ if policy_id and (not self.get_policies(user_id=user_id, policy_id=policy_id)):
+ raise exceptions.PolicyUnknown
+ return self.driver.get_actions(policy_id=policy_id, perimeter_id=perimeter_id)
+
+ @enforce(("read", "write"), "perimeter")
+ def add_action(self, user_id, policy_id, perimeter_id=None, value=None):
+ logger.debug("add_action {}".format(policy_id))
+
+ if not value or "name" not in value or not value["name"].strip():
+ raise exceptions.PerimeterContentError('invalid name')
+
+ if not policy_id or (not self.get_policies(user_id=user_id, policy_id=policy_id)):
+ raise exceptions.PolicyUnknown
+
+ if perimeter_id:
+ action_perimeter = self.driver.get_actions(policy_id=None, perimeter_id=perimeter_id)
+ if not action_perimeter:
+ raise exceptions.PerimeterContentError
+
+ if not perimeter_id:
+ action_perimeter = self.driver.get_action_by_name(value['name'])
+ if len(action_perimeter):
+ perimeter_id = next(iter(action_perimeter))
+
+ if perimeter_id and action_perimeter[perimeter_id]['name'] != value['name']:
+ raise exceptions.PerimeterContentError
+
+ if not perimeter_id:
+ perimeter_id = uuid4().hex
+
+ return self.driver.set_action(policy_id=policy_id, perimeter_id=perimeter_id, value=value)
+
+ @enforce(("read", "write"), "perimeter")
+ def update_action(self, user_id, perimeter_id, value):
+ logger.debug("update_action perimeter_id = {}".format(perimeter_id))
+
+ if not perimeter_id:
+ raise exceptions.ActionUnknown
+
+ actions = self.driver.get_actions(policy_id=None, perimeter_id=perimeter_id)
+ if not actions or not (perimeter_id in actions):
+ raise exceptions.PerimeterContentError
+
+ if 'policy_list' in value or ('name' in value and not value['name']):
+ raise exceptions.PerimeterContentError
+
+ return self.driver.update_action(perimeter_id=perimeter_id, value=value)
+
+ @enforce(("read", "write"), "perimeter")
+ def delete_action(self, user_id, policy_id, perimeter_id):
+
+ if not perimeter_id:
+ raise exceptions.ActionUnknown
+
+ if not policy_id:
+ raise exceptions.PolicyUnknown
+
+ if not self.get_actions(user_id=user_id, policy_id=policy_id, perimeter_id=perimeter_id):
+ raise exceptions.ActionUnknown
+
+ logger.debug("delete_action {} {} {}".format(policy_id, perimeter_id,
+ self.get_policies(user_id=user_id,
+ policy_id=policy_id)))
+ if not self.get_policies(user_id=user_id, policy_id=policy_id):
+ raise exceptions.PolicyUnknown
+
+ act_assig = self.driver.get_action_assignments(policy_id=policy_id, action_id=perimeter_id)
+ if act_assig:
+ raise exceptions.DeletePerimeterWithAssignment
+ return self.driver.delete_action(policy_id=policy_id, perimeter_id=perimeter_id)
+
+ @enforce("read", "data")
+ def get_subject_data(self, user_id, policy_id, data_id=None, category_id=None):
+ available_metadata = self.get_available_metadata(user_id, policy_id)
+ results = []
+ if not category_id:
+ for cat in available_metadata["subject"]:
+ results.append(self.driver.get_subject_data(policy_id=policy_id, data_id=data_id,
+ category_id=cat))
+ if category_id and category_id in available_metadata["subject"]:
+ results.append(self.driver.get_subject_data(policy_id=policy_id, data_id=data_id,
+ category_id=category_id))
+ return results
+
+ @enforce(("read", "write"), "data")
+ def set_subject_data(self, user_id, policy_id, data_id=None, category_id=None, value=None):
+ if not category_id or (
+ not Managers.ModelManager.get_subject_categories(user_id=user_id,
+ category_id=category_id)):
+ raise exceptions.SubjectCategoryUnknown
+
+ self.__category_dependency_validation(user_id, policy_id, category_id, 'subject_categories')
+
+ if not data_id:
+ data_id = uuid4().hex
+ return self.driver.set_subject_data(policy_id=policy_id, data_id=data_id,
+ category_id=category_id, value=value)
+
+ @enforce(("read", "write"), "data")
+ def delete_subject_data(self, user_id, policy_id, data_id, category_id=None):
+ # TODO (asteroide): check and/or delete assignments linked to that data
+ subject_assignments = self.get_subject_assignments(user_id=user_id, policy_id=policy_id,
+ category_id=category_id)
+ if subject_assignments:
+ raise exceptions.DeleteData
+ return self.driver.delete_subject_data(policy_id=policy_id, category_id=category_id,
+ data_id=data_id)
+
+ @enforce("read", "data")
+ def get_object_data(self, user_id, policy_id, data_id=None, category_id=None):
+ available_metadata = self.get_available_metadata(user_id, policy_id)
+ results = []
+ if not category_id:
+ for cat in available_metadata["object"]:
+ results.append(self.driver.get_object_data(policy_id=policy_id, data_id=data_id,
+ category_id=cat))
+ if category_id and category_id in available_metadata["object"]:
+ results.append(self.driver.get_object_data(policy_id=policy_id, data_id=data_id,
+ category_id=category_id))
+ return results
+
+ @enforce(("read", "write"), "data")
+ def add_object_data(self, user_id, policy_id, data_id=None, category_id=None, value=None):
+
+ if not category_id or (
+ not Managers.ModelManager.get_object_categories(user_id=user_id,
+ category_id=category_id)):
+ raise exceptions.ObjectCategoryUnknown
+
+ self.__category_dependency_validation(user_id, policy_id, category_id, 'object_categories')
+
+ if not data_id:
+ data_id = uuid4().hex
+ return self.driver.set_object_data(policy_id=policy_id, data_id=data_id,
+ category_id=category_id, value=value)
+
+ @enforce(("read", "write"), "data")
+ def delete_object_data(self, user_id, policy_id, data_id, category_id=None):
+ # TODO (asteroide): check and/or delete assignments linked to that data
+ object_assignments = self.get_object_assignments(user_id=user_id, policy_id=policy_id,
+ category_id=category_id)
+ if object_assignments:
+ raise exceptions.DeleteData
+ return self.driver.delete_object_data(policy_id=policy_id, category_id=category_id,
+ data_id=data_id)
+
+ @enforce("read", "data")
+ def get_action_data(self, user_id, policy_id, data_id=None, category_id=None):
+ available_metadata = self.get_available_metadata(user_id, policy_id)
+ results = []
+ if not category_id:
+ for cat in available_metadata["action"]:
+ results.append(self.driver.get_action_data(policy_id=policy_id, data_id=data_id,
+ category_id=cat))
+ if category_id and category_id in available_metadata["action"]:
+ results.append(self.driver.get_action_data(policy_id=policy_id, data_id=data_id,
+ category_id=category_id))
+ return results
+
+ @enforce(("read", "write"), "data")
+ def add_action_data(self, user_id, policy_id, data_id=None, category_id=None, value=None):
+ if not category_id or (
+ not Managers.ModelManager.get_action_categories(user_id=user_id,
+ category_id=category_id)):
+ raise exceptions.ActionCategoryUnknown
+
+ self.__category_dependency_validation(user_id, policy_id, category_id, 'action_categories')
+
+ if not data_id:
+ data_id = uuid4().hex
+ return self.driver.set_action_data(policy_id=policy_id, data_id=data_id,
+ category_id=category_id, value=value)
+
+ @enforce(("read", "write"), "data")
+ def delete_action_data(self, user_id, policy_id, data_id, category_id=None):
+ # TODO (asteroide): check and/or delete assignments linked to that data
+ action_assignments = self.get_action_assignments(user_id=user_id, policy_id=policy_id,
+ category_id=category_id)
+ if action_assignments:
+ raise exceptions.DeleteData
+ return self.driver.delete_action_data(policy_id=policy_id, category_id=category_id,
+ data_id=data_id)
+
+ @enforce("read", "assignments")
+ def get_subject_assignments(self, user_id, policy_id, subject_id=None, category_id=None):
+ return self.driver.get_subject_assignments(policy_id=policy_id, subject_id=subject_id,
+ category_id=category_id)
+
+ @enforce(("read", "write"), "assignments")
+ def add_subject_assignment(self, user_id, policy_id, subject_id, category_id, data_id):
+
+ if not category_id or (
+ not Managers.ModelManager.get_subject_categories(user_id=user_id,
+ category_id=category_id)):
+ raise exceptions.SubjectCategoryUnknown
+
+ self.__category_dependency_validation(user_id, policy_id, category_id, 'subject_categories')
+
+ if not subject_id or (
+ not self.get_subjects(user_id=user_id, policy_id=policy_id,
+ perimeter_id=subject_id)):
+ raise exceptions.SubjectUnknown
+
+ if not data_id or (
+ not self.get_subject_data(user_id=user_id, policy_id=policy_id, data_id=data_id,
+ category_id=category_id)):
+ raise exceptions.DataUnknown
+
+ return self.driver.add_subject_assignment(policy_id=policy_id, subject_id=subject_id,
+ category_id=category_id, data_id=data_id)
+
+ @enforce(("read", "write"), "assignments")
+ def delete_subject_assignment(self, user_id, policy_id, subject_id, category_id, data_id):
+ return self.driver.delete_subject_assignment(policy_id=policy_id, subject_id=subject_id,
+ category_id=category_id, data_id=data_id)
+
+ @enforce("read", "assignments")
+ def get_object_assignments(self, user_id, policy_id, object_id=None, category_id=None):
+ return self.driver.get_object_assignments(policy_id=policy_id, object_id=object_id,
+ category_id=category_id)
+
+ @enforce(("read", "write"), "assignments")
+ def add_object_assignment(self, user_id, policy_id, object_id, category_id, data_id):
+
+ if not category_id or (
+ not Managers.ModelManager.get_object_categories(user_id=user_id,
+ category_id=category_id)):
+ raise exceptions.ObjectCategoryUnknown
+
+ self.__category_dependency_validation(user_id, policy_id, category_id, 'object_categories')
+
+ if not object_id or (
+ not self.get_objects(user_id=user_id, policy_id=policy_id, perimeter_id=object_id)):
+ raise exceptions.ObjectUnknown
+
+ if not data_id or (
+ not self.get_object_data(user_id=user_id, policy_id=policy_id, data_id=data_id,
+ category_id=category_id)):
+ raise exceptions.DataUnknown
+
+ return self.driver.add_object_assignment(policy_id=policy_id, object_id=object_id,
+ category_id=category_id, data_id=data_id)
+
+ @enforce(("read", "write"), "assignments")
+ def delete_object_assignment(self, user_id, policy_id, object_id, category_id, data_id):
+ return self.driver.delete_object_assignment(policy_id=policy_id, object_id=object_id,
+ category_id=category_id, data_id=data_id)
+
+ @enforce("read", "assignments")
+ def get_action_assignments(self, user_id, policy_id, action_id=None, category_id=None):
+ return self.driver.get_action_assignments(policy_id=policy_id, action_id=action_id,
+ category_id=category_id)
+
+ @enforce(("read", "write"), "assignments")
+ def add_action_assignment(self, user_id, policy_id, action_id, category_id, data_id):
+
+ if not category_id or (
+ not Managers.ModelManager.get_action_categories(user_id=user_id,
+ category_id=category_id)):
+ raise exceptions.ActionCategoryUnknown
+
+ self.__category_dependency_validation(user_id, policy_id, category_id, 'action_categories')
+
+ if not action_id or (
+ not self.get_actions(user_id=user_id, policy_id=policy_id, perimeter_id=action_id)):
+ raise exceptions.ActionUnknown
+
+ if not data_id or (
+ not self.get_action_data(user_id=user_id, policy_id=policy_id, data_id=data_id,
+ category_id=category_id)):
+ raise exceptions.DataUnknown
+
+ return self.driver.add_action_assignment(policy_id=policy_id, action_id=action_id,
+ category_id=category_id, data_id=data_id)
+
+ @enforce(("read", "write"), "assignments")
+ def delete_action_assignment(self, user_id, policy_id, action_id, category_id, data_id):
+ return self.driver.delete_action_assignment(policy_id=policy_id, action_id=action_id,
+ category_id=category_id, data_id=data_id)
+
+ @enforce("read", "rules")
+ def get_rules(self, user_id, policy_id, meta_rule_id=None, rule_id=None):
+ return self.driver.get_rules(policy_id=policy_id, meta_rule_id=meta_rule_id,
+ rule_id=rule_id)
+
+ @enforce(("read", "write"), "rules")
+ def add_rule(self, user_id, policy_id, meta_rule_id, value):
+ if not meta_rule_id or (
+ not self.ModelManager.get_meta_rules(user_id=user_id, meta_rule_id=meta_rule_id)):
+ raise exceptions.MetaRuleUnknown
+
+ self.__check_existing_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, user_id=user_id,
+ rule_value=value)
+ self.__dependencies_validation(user_id, policy_id, meta_rule_id)
+
+ return self.driver.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value)
+
+ def __check_existing_rule(self, user_id, policy_id, meta_rule_id, rule_value):
+
+ if not meta_rule_id:
+ raise exceptions.MetaRuleUnknown
+
+ meta_rule = self.ModelManager.get_meta_rules(user_id=user_id, meta_rule_id=meta_rule_id)
+ if not meta_rule:
+ raise exceptions.MetaRuleUnknown
+
+ if len(meta_rule[meta_rule_id]['subject_categories']) + len(
+ meta_rule[meta_rule_id]['object_categories']) \
+ + len(meta_rule[meta_rule_id]['action_categories']) > len(rule_value['rule']):
+ raise exceptions.RuleContentError(message="Missing Data")
+
+ if len(meta_rule[meta_rule_id]['subject_categories']) + len(
+ meta_rule[meta_rule_id]['object_categories']) \
+ + len(meta_rule[meta_rule_id]['action_categories']) < len(rule_value['rule']):
+ raise exceptions.MetaRuleContentError(message="Missing Data")
+
+ temp_rule_data = list(
+ rule_value['rule'][0:len(meta_rule[meta_rule_id]['subject_categories'])])
+ found_data_counter = 0
+ start_sub = len(meta_rule[meta_rule_id]['subject_categories'])
+
+ for sub_cat_id in meta_rule[meta_rule_id]['subject_categories']:
+ subjects_data = self.get_subject_data(user_id=user_id,
+ category_id=sub_cat_id, policy_id=policy_id)
+ found_data_counter = self.__validate_data_id(sub_cat_id, subjects_data[0]['data'],
+ temp_rule_data,
+ "Missing Subject_category "
+ , found_data_counter)
+
+ if found_data_counter != len(meta_rule[meta_rule_id]['subject_categories']):
+ raise exceptions.RuleContentError(message="Missing Data")
+
+ temp_rule_data = list(
+ rule_value['rule'][
+ start_sub:start_sub + len(meta_rule[meta_rule_id]['object_categories'])])
+ found_data_counter = 0
+ start_sub = start_sub + len(meta_rule[meta_rule_id]['object_categories'])
+
+ for ob_cat_id in meta_rule[meta_rule_id]['object_categories']:
+ object_data = self.get_object_data(user_id=user_id,
+ category_id=ob_cat_id, policy_id=policy_id)
+
+ found_data_counter = self.__validate_data_id(ob_cat_id, object_data[0]['data'],
+ temp_rule_data,
+ "Missing Object_category ",
+ found_data_counter)
+
+ if found_data_counter != len(meta_rule[meta_rule_id]['object_categories']):
+ raise exceptions.RuleContentError(message="Missing Data")
+
+ temp_rule_data = list(
+ rule_value['rule'][
+ start_sub:start_sub + len(meta_rule[meta_rule_id]['action_categories'])])
+ found_data_counter = 0
+
+ for act_cat_id in meta_rule[meta_rule_id]['action_categories']:
+ action_data = self.get_action_data(user_id=user_id, category_id=act_cat_id,
+ policy_id=policy_id)
+ found_data_counter = self.__validate_data_id(act_cat_id, action_data[0]['data'],
+ temp_rule_data,
+ "Missing Action_category ",
+ found_data_counter)
+
+ if found_data_counter != len(meta_rule[meta_rule_id]['action_categories']):
+ raise exceptions.RuleContentError(message="Missing Data")
+
+ def __validate_data_id(self, cat_id, data_ids, temp_rule_data, error_msg, found_data_counter):
+ for ID in data_ids:
+ if ID in temp_rule_data:
+ temp_rule_data.remove(ID)
+ found_data_counter += 1
+ # if no data id found in the rule, so rule not valid
+ if found_data_counter < 1:
+ raise exceptions.RuleContentError(message=error_msg + cat_id)
+ return found_data_counter
+
+ @enforce(("read", "write"), "rules")
+ def delete_rule(self, user_id, policy_id, rule_id):
+ return self.driver.delete_rule(policy_id=policy_id, rule_id=rule_id)
+
+ @enforce("read", "meta_data")
+ def get_available_metadata(self, user_id, policy_id):
+ categories = {
+ "subject": [],
+ "object": [],
+ "action": []
+ }
+ policy = self.driver.get_policies(policy_id=policy_id)
+ if not policy:
+ raise exceptions.PolicyUnknown
+ model_id = policy[policy_id]["model_id"]
+ model = Managers.ModelManager.get_models(user_id=user_id, model_id=model_id)
+ try:
+ meta_rule_list = model[model_id]["meta_rules"]
+ for meta_rule_id in meta_rule_list:
+ meta_rule = Managers.ModelManager.get_meta_rules(user_id=user_id,
+ meta_rule_id=meta_rule_id)
+ categories["subject"].extend(meta_rule[meta_rule_id]["subject_categories"])
+ categories["object"].extend(meta_rule[meta_rule_id]["object_categories"])
+ categories["action"].extend(meta_rule[meta_rule_id]["action_categories"])
+ finally:
+ return categories
+
+ def __dependencies_validation(self, user_id, policy_id, meta_rule_id=None):
+
+ policies = self.get_policies(user_id=user_id, policy_id=policy_id)
+ if not policy_id or (not policies):
+ raise exceptions.PolicyUnknown
+
+ policy_content = policies[next(iter(policies))]
+ model_id = policy_content['model_id']
+ models = Managers.ModelManager.get_models(user_id=user_id, model_id=model_id)
+ if not model_id or not models:
+ raise exceptions.ModelUnknown
+
+ model_content = models[next(iter(models))]
+ if meta_rule_id:
+ meta_rule_exists = False
+
+ for model_meta_rule_id in model_content['meta_rules']:
+ if model_meta_rule_id == meta_rule_id:
+ meta_rule_exists = True
+ break
+
+ if not meta_rule_exists:
+ raise exceptions.MetaRuleNotLinkedWithPolicyModel
+
+ meta_rule = self.ModelManager.get_meta_rules(user_id=user_id, meta_rule_id=meta_rule_id)
+ meta_rule_content = meta_rule[next(iter(meta_rule))]
+ if (not meta_rule_content['subject_categories']) or (
+ not meta_rule_content['object_categories']) or (
+ not meta_rule_content['action_categories']):
+ raise exceptions.MetaRuleContentError
+ return model_content
+
+ def __category_dependency_validation(self, user_id, policy_id, category_id, category_key):
+ model = self.__dependencies_validation(user_id=user_id, policy_id=policy_id)
+ category_found = False
+ for model_meta_rule_id in model['meta_rules']:
+ meta_rule = self.ModelManager.get_meta_rules(user_id=user_id,
+ meta_rule_id=model_meta_rule_id)
+ meta_rule_content = meta_rule[next(iter(meta_rule))]
+ if meta_rule_content[category_key] and category_id in meta_rule_content[category_key]:
+ category_found = True
+ break
+
+ if not category_found:
+ raise exceptions.CategoryNotAssignedMetaRule
diff --git a/old/python_moondb/python_moondb/backends/__init__.py b/old/python_moondb/python_moondb/backends/__init__.py
new file mode 100644
index 00000000..6f1cd3d5
--- /dev/null
+++ b/old/python_moondb/python_moondb/backends/__init__.py
@@ -0,0 +1,96 @@
+"""
+intra_extensions = {
+ intra_extension_id1: {
+ name: xxx,
+ model: yyy,
+ description: zzz},
+ intra_extension_id2: {...},
+ ...
+}
+
+tenants = {
+ tenant_id1: {
+ name: xxx,
+ description: yyy,
+ intra_authz_extension_id: zzz,
+ intra_admin_extension_id: zzz,
+ },
+ tenant_id2: {...},
+ ...
+}
+
+--------------- for each intra-extension -----------------
+
+subject_categories = {
+ subject_category_id1: {
+ name: xxx,
+ description: yyy},
+ subject_category_id2: {...},
+ ...
+}
+
+subjects = {
+ subject_id1: {
+ name: xxx,
+ description: yyy,
+ ...},
+ subject_id2: {...},
+ ...
+}
+
+subject_scopes = {
+ subject_category_id1: {
+ subject_scope_id1: {
+ name: xxx,
+ description: aaa},
+ subject_scope_id2: {
+ name: yyy,
+ description: bbb},
+ ...},
+ subject_scope_id3: {
+ ...}
+ subject_category_id2: {...},
+ ...
+}
+
+subject_assignments = {
+ subject_id1: {
+ subject_category_id1: [subject_scope_id1, subject_scope_id2, ...],
+ subject_category_id2: [subject_scope_id3, subject_scope_id4, ...],
+ ...
+ },
+ subject_id2: {
+ subject_category_id1: [subject_scope_id1, subject_scope_id2, ...],
+ subject_category_id2: [subject_scope_id3, subject_scope_id4, ...],
+ ...
+ },
+ ...
+}
+
+aggregation_algorithm = {
+ aggregation_algorithm_id: {
+ name: xxx,
+ description: yyy
+ }
+ }
+
+sub_meta_rules = {
+ sub_meta_rule_id_1: {
+ "name": xxx,
+ "algorithm": yyy,
+ "subject_categories": [subject_category_id1, subject_category_id2,...],
+ "object_categories": [object_category_id1, object_category_id2,...],
+ "action_categories": [action_category_id1, action_category_id2,...]
+ sub_meta_rule_id_2: {...},
+ ...
+}
+
+rules = {
+ sub_meta_rule_id1: {
+ rule_id1: [subject_scope1, subject_scope2, ..., action_scope1, ..., object_scope1, ... ],
+ rule_id2: [subject_scope3, subject_scope4, ..., action_scope3, ..., object_scope3, ... ],
+ rule_id3: [thomas, write, admin.subjects]
+ ...},
+ sub_meta_rule_id2: { },
+ ...}
+"""
diff --git a/old/python_moondb/python_moondb/backends/sql.py b/old/python_moondb/python_moondb/backends/sql.py
new file mode 100644
index 00000000..d25586ba
--- /dev/null
+++ b/old/python_moondb/python_moondb/backends/sql.py
@@ -0,0 +1,1884 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import copy
+import json
+from uuid import uuid4
+import sqlalchemy as sql
+import logging
+from sqlalchemy.orm import sessionmaker
+from sqlalchemy.ext.declarative import declarative_base, declared_attr
+from sqlalchemy import create_engine
+from contextlib import contextmanager
+from sqlalchemy import types as sql_types
+from python_moonutilities import configuration
+from python_moonutilities import exceptions
+from python_moondb.core import PDPDriver, PolicyDriver, ModelDriver
+import sqlalchemy
+
+logger = logging.getLogger("moon.db.driver.sql")
+Base = declarative_base()
+DEBUG = True if configuration.get_configuration("logging")['logging']['loggers']['moon'][
+ 'level'] == "DEBUG" else False
+
+
+class DictBase:
+ attributes = []
+
+ @classmethod
+ def from_dict(cls, d):
+ new_d = d.copy()
+ return cls(**new_d)
+ # new_d = d.copy()
+ #
+ # new_d['extra'] = {k: new_d.pop(k) for k in six.iterkeys(d)
+ # if k not in cls.attributes and k != 'extra'}
+ #
+ # return cls(**new_d)
+
+ def to_dict(self):
+ d = dict()
+ for attr in self.__class__.attributes:
+ d[attr] = getattr(self, attr)
+ return d
+
+ def __getitem__(self, key):
+ # if "extra" in dir(self) and key in self.extra:
+ # return self.extra[key]
+ return getattr(self, key)
+
+
+class JsonBlob(sql_types.TypeDecorator):
+ impl = sql.Text
+
+ def process_bind_param(self, value, dialect):
+ return json.dumps(value)
+
+ def process_result_value(self, value, dialect):
+ return json.loads(value)
+
+
+class Model(Base, DictBase):
+ __tablename__ = 'models'
+ attributes = ['id', 'name', 'value']
+ id = sql.Column(sql.String(64), primary_key=True)
+ name = sql.Column(sql.String(256), nullable=False)
+ value = sql.Column(JsonBlob(), nullable=True)
+
+ def to_dict(self):
+ return {
+ "name": self.name,
+ "description": self.value.get("description", ""),
+ "meta_rules": self.value.get("meta_rules", list()),
+ }
+
+
+class Policy(Base, DictBase):
+ __tablename__ = 'policies'
+ attributes = ['id', 'name', 'model_id', 'value']
+ id = sql.Column(sql.String(64), primary_key=True)
+ name = sql.Column(sql.String(256), nullable=False)
+ model_id = sql.Column(sql.String(64), nullable=True, default="")
+ value = sql.Column(JsonBlob(), nullable=True)
+
+ def to_dict(self):
+ return {
+ "description": self.value.get("description", ""),
+ "genre": self.value.get("genre", ""),
+ "model_id": self.model_id,
+ "name": self.name
+ }
+
+
+class PDP(Base, DictBase):
+ __tablename__ = 'pdp'
+ attributes = ['id', 'name', 'keystone_project_id', 'value']
+ id = sql.Column(sql.String(64), primary_key=True)
+ name = sql.Column(sql.String(256), nullable=False)
+ keystone_project_id = sql.Column(sql.String(64), nullable=True, default="")
+ value = sql.Column(JsonBlob(), nullable=True)
+
+ def to_dict(self):
+ return {
+ "name": self.name,
+ "description": self.value.get("description", ""),
+ "keystone_project_id": self.keystone_project_id,
+ "security_pipeline": self.value.get("security_pipeline", []),
+ }
+
+
+class PerimeterCategoryBase(DictBase):
+ attributes = ['id', 'name', 'description']
+ id = sql.Column(sql.String(64), primary_key=True)
+ name = sql.Column(sql.String(256), nullable=False)
+ description = sql.Column(sql.String(256), nullable=True)
+
+
+class SubjectCategory(Base, PerimeterCategoryBase):
+ __tablename__ = 'subject_categories'
+
+
+class ObjectCategory(Base, PerimeterCategoryBase):
+ __tablename__ = 'object_categories'
+
+
+class ActionCategory(Base, PerimeterCategoryBase):
+ __tablename__ = 'action_categories'
+
+
+class PerimeterBase(DictBase):
+ attributes = ['id', 'name', 'value']
+ id = sql.Column(sql.String(64), primary_key=True)
+ name = sql.Column(sql.String(256), nullable=False)
+ value = sql.Column(JsonBlob(), nullable=True)
+ __mapper_args__ = {'concrete': True}
+
+ def __repr__(self):
+ return "{} with name {} : {}".format(self.id, self.name, json.dumps(self.value))
+
+ def to_return(self):
+ return {
+ 'id': self.id,
+ 'name': self.name,
+ 'description': self.value.get("description", ""),
+ 'email': self.value.get("email", ""),
+ 'extra': self.value.get("extra", dict()),
+ 'policy_list': self.value.get("policy_list", [])
+ }
+
+ def to_dict(self):
+ dict_value = copy.deepcopy(self.value)
+ dict_value["name"] = self.name
+ return {
+ 'id': self.id,
+ 'value': dict_value
+ }
+
+
+class Subject(Base, PerimeterBase):
+ __tablename__ = 'subjects'
+
+
+class Object(Base, PerimeterBase):
+ __tablename__ = 'objects'
+
+
+class Action(Base, PerimeterBase):
+ __tablename__ = 'actions'
+
+
+class PerimeterDataBase(DictBase):
+ attributes = ['id', 'name', 'value', 'category_id', 'policy_id']
+ id = sql.Column(sql.String(64), primary_key=True)
+ name = sql.Column(sql.String(256), nullable=False)
+ value = sql.Column(JsonBlob(), nullable=True)
+
+ @declared_attr
+ def policy_id(cls):
+ return sql.Column(sql.ForeignKey("policies.id"), nullable=False)
+
+ def to_dict(self):
+ return {
+ 'id': self.id,
+ 'name': self.name,
+ 'description': self.value.get("description", ""),
+ 'category_id': self.category_id,
+ 'policy_id': self.policy_id
+ }
+
+
+class SubjectData(Base, PerimeterDataBase):
+ __tablename__ = 'subject_data'
+ category_id = sql.Column(sql.ForeignKey("subject_categories.id"), nullable=False)
+
+
+class ObjectData(Base, PerimeterDataBase):
+ __tablename__ = 'object_data'
+ category_id = sql.Column(sql.ForeignKey("object_categories.id"), nullable=False)
+
+
+class ActionData(Base, PerimeterDataBase):
+ __tablename__ = 'action_data'
+ category_id = sql.Column(sql.ForeignKey("action_categories.id"), nullable=False)
+
+
+class PerimeterAssignmentBase(DictBase):
+ attributes = ['id', 'assignments', 'policy_id', 'subject_id', 'category_id']
+ id = sql.Column(sql.String(64), primary_key=True)
+ assignments = sql.Column(JsonBlob(), nullable=True)
+ category_id = None
+
+ @declared_attr
+ def policy_id(cls):
+ return sql.Column(sql.ForeignKey("policies.id"), nullable=False)
+
+ def _to_dict(self, element_key, element_value):
+ return {
+ "id": self.id,
+ "policy_id": self.policy_id,
+ element_key: element_value,
+ "category_id": self.category_id,
+ "assignments": self.assignments,
+ }
+
+
+class SubjectAssignment(Base, PerimeterAssignmentBase):
+ __tablename__ = 'subject_assignments'
+ subject_id = sql.Column(sql.ForeignKey("subjects.id"), nullable=False)
+ category_id = sql.Column(sql.ForeignKey("subject_categories.id"), nullable=False)
+
+ def to_dict(self):
+ return self._to_dict("subject_id", self.subject_id)
+
+
+class ObjectAssignment(Base, PerimeterAssignmentBase):
+ __tablename__ = 'object_assignments'
+ attributes = ['id', 'assignments', 'policy_id', 'object_id', 'category_id']
+ object_id = sql.Column(sql.ForeignKey("objects.id"), nullable=False)
+ category_id = sql.Column(sql.ForeignKey("object_categories.id"), nullable=False)
+
+ def to_dict(self):
+ return self._to_dict("object_id", self.object_id)
+
+
+class ActionAssignment(Base, PerimeterAssignmentBase):
+ __tablename__ = 'action_assignments'
+ attributes = ['id', 'assignments', 'policy_id', 'action_id', 'category_id']
+ action_id = sql.Column(sql.ForeignKey("actions.id"), nullable=False)
+ category_id = sql.Column(sql.ForeignKey("action_categories.id"), nullable=False)
+
+ def to_dict(self):
+ return self._to_dict("action_id", self.action_id)
+
+
+class MetaRule(Base, DictBase):
+ __tablename__ = 'meta_rules'
+ attributes = ['id', 'name', 'subject_categories', 'object_categories', 'action_categories',
+ 'value']
+ id = sql.Column(sql.String(64), primary_key=True)
+ name = sql.Column(sql.String(256), nullable=False)
+ subject_categories = sql.Column(JsonBlob(), nullable=True)
+ object_categories = sql.Column(JsonBlob(), nullable=True)
+ action_categories = sql.Column(JsonBlob(), nullable=True)
+ value = sql.Column(JsonBlob(), nullable=True)
+
+ def to_dict(self):
+ return {
+ "name": self.name,
+ "description": self.value.get("description", ""),
+ "subject_categories": self.subject_categories,
+ "object_categories": self.object_categories,
+ "action_categories": self.action_categories,
+ }
+
+
+class Rule(Base, DictBase):
+ __tablename__ = 'rules'
+ attributes = ['id', 'rule', 'policy_id', 'meta_rule_id']
+ id = sql.Column(sql.String(64), primary_key=True)
+ rule = sql.Column(JsonBlob(), nullable=True)
+ policy_id = sql.Column(sql.ForeignKey("policies.id"), nullable=False)
+ meta_rule_id = sql.Column(sql.ForeignKey("meta_rules.id"), nullable=False)
+
+ def to_dict(self):
+ return {
+ 'id': self.id,
+ 'rule': self.rule["rule"],
+ 'instructions': self.rule["instructions"],
+ 'enabled': self.rule["enabled"],
+ 'policy_id': self.policy_id,
+ 'meta_rule_id': self.meta_rule_id
+ }
+
+ def __repr__(self):
+ return "{}".format(self.rule)
+
+
+@contextmanager
+def session_scope(engine):
+ """Provide a transactional scope around a series of operations."""
+ if type(engine) is str:
+ echo = DEBUG
+ engine = create_engine(engine, echo=echo)
+ session = sessionmaker(bind=engine)()
+ try:
+ yield session
+ session.commit()
+ except:
+ session.rollback()
+ raise
+ finally:
+ session.close()
+
+
+class BaseConnector(object):
+ """Provide a base connector to connect them all"""
+ engine = ""
+
+ def __init__(self, engine_name):
+ echo = DEBUG
+ self.engine = create_engine(engine_name, echo=echo)
+
+ def init_db(self):
+ Base.metadata.create_all(self.engine)
+
+ def set_engine(self, engine_name):
+ self.engine = engine_name
+
+ def get_session(self):
+ return session_scope(self.engine)
+
+ def get_session_for_read(self):
+ return self.get_session()
+
+ def get_session_for_write(self):
+ return self.get_session()
+
+
+class PDPConnector(BaseConnector, PDPDriver):
+
+ def update_pdp(self, pdp_id, value):
+ try:
+ with self.get_session_for_write() as session:
+ query = session.query(PDP)
+ query = query.filter_by(id=pdp_id)
+ ref = query.first()
+ if ref:
+ value_wo_name = copy.deepcopy(value)
+ value_wo_name.pop("name", None)
+ value_wo_name.pop("keystone_project_id", None)
+ ref.name = value["name"]
+ ref.keystone_project_id = value["keystone_project_id"]
+ d = dict(ref.value)
+ d.update(value_wo_name)
+ setattr(ref, "value", d)
+ return {ref.id: ref.to_dict()}
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.PdpExisting
+ raise error
+
+ def delete_pdp(self, pdp_id):
+ with self.get_session_for_write() as session:
+ ref = session.query(PDP).get(pdp_id)
+ session.delete(ref)
+
+ def add_pdp(self, pdp_id=None, value=None):
+ try:
+ with self.get_session_for_write() as session:
+ value_wo_name = copy.deepcopy(value)
+ value_wo_name.pop("name", None)
+ value_wo_name.pop("keystone_project_id", None)
+ new = PDP.from_dict({
+ "id": pdp_id if pdp_id else uuid4().hex,
+ "name": value["name"],
+ "keystone_project_id": value["keystone_project_id"],
+ "value": value_wo_name
+ })
+ session.add(new)
+ return {new.id: new.to_dict()}
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.PdpExisting
+ raise error
+
+ def get_pdp(self, pdp_id=None):
+ with self.get_session_for_read() as session:
+ query = session.query(PDP)
+ if pdp_id:
+ query = query.filter_by(id=pdp_id)
+ ref_list = query.all()
+ return {_ref.id: _ref.to_dict() for _ref in ref_list}
+
+
+class PolicyConnector(BaseConnector, PolicyDriver):
+
+ def update_policy(self, policy_id, value):
+ try:
+ with self.get_session_for_write() as session:
+ query = session.query(Policy)
+ query = query.filter_by(id=policy_id)
+ ref = query.first()
+
+ if ref:
+ value_wo_other_info = copy.deepcopy(value)
+ value_wo_other_info.pop("name", None)
+ value_wo_other_info.pop("model_id", None)
+ ref.name = value["name"]
+ ref.model_id = value["model_id"]
+ d = dict(ref.value)
+ d.update(value_wo_other_info)
+ setattr(ref, "value", d)
+ return {ref.id: ref.to_dict()}
+
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.PolicyExisting
+ raise error
+
+ def delete_policy(self, policy_id):
+ with self.get_session_for_write() as session:
+ ref = session.query(Policy).get(policy_id)
+ session.delete(ref)
+
+ def add_policy(self, policy_id=None, value=None):
+ try:
+ with self.get_session_for_write() as session:
+ value_wo_other_info = copy.deepcopy(value)
+ value_wo_other_info.pop("name", None)
+ value_wo_other_info.pop("model_id", None)
+ new = Policy.from_dict({
+ "id": policy_id if policy_id else uuid4().hex,
+ "name": value["name"],
+ "model_id": value.get("model_id", ""),
+ "value": value_wo_other_info
+ })
+ session.add(new)
+ return {new.id: new.to_dict()}
+
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.PolicyExisting
+ raise error
+
+ def get_policies(self, policy_id=None, policy_name=None):
+ with self.get_session_for_read() as session:
+ query = session.query(Policy)
+ if policy_id:
+ query = query.filter_by(id=policy_id)
+ elif policy_name:
+ query = query.filter_by(name=policy_name)
+
+ ref_list = query.all()
+ return {_ref.id: _ref.to_dict() for _ref in ref_list}
+
+ def __get_perimeters(self, ClassType, policy_id, perimeter_id=None):
+ # if not policy_id:
+ # raise exceptions.PolicyUnknown
+
+ with self.get_session_for_read() as session:
+ query = session.query(ClassType)
+
+ if perimeter_id:
+ query = query.filter_by(id=perimeter_id)
+
+ ref_list = copy.deepcopy(query.all())
+
+ if policy_id:
+ results = []
+ for _ref in ref_list:
+ _ref_value = _ref.to_return()
+ if policy_id in _ref_value["policy_list"]:
+ results.append(_ref)
+ return {_ref.id: _ref.to_return() for _ref in results}
+ return {_ref.id: _ref.to_return() for _ref in ref_list}
+
+ def __get_perimeter_by_name(self, ClassType, perimeter_name):
+ # if not policy_id:
+ # raise exceptions.PolicyUnknown
+ with self.get_session_for_read() as session:
+ query = session.query(ClassType)
+ if not perimeter_name or not perimeter_name.strip():
+ raise exceptions.PerimeterContentError('invalid name')
+ query = query.filter_by(name=perimeter_name)
+ ref_list = copy.deepcopy(query.all())
+ return {_ref.id: _ref.to_return() for _ref in ref_list}
+
+ def __update_perimeter(self, class_type, class_type_exception, perimeter_id, value):
+ if not perimeter_id:
+ return exceptions.PerimeterContentError
+ with self.get_session_for_write() as session:
+ query = session.query(class_type)
+ query = query.filter_by(id=perimeter_id)
+ _perimeter = query.first()
+ if not _perimeter:
+ raise class_type_exception
+ temp_perimeter = copy.deepcopy(_perimeter.to_dict())
+ if 'name' in value:
+ temp_perimeter['value']['name'] = value['name']
+ if 'description' in value:
+ temp_perimeter['value']['description'] = value['description']
+ if 'extra' in value:
+ temp_perimeter['value']['extra'] = value['extra']
+ name = temp_perimeter['value']['name']
+ temp_perimeter['value'].pop("name", None)
+ new_perimeter = class_type.from_dict({
+ "id": temp_perimeter["id"],
+ "name": name,
+ "value": temp_perimeter["value"]
+ })
+ _perimeter.value = new_perimeter.value
+ _perimeter.name = new_perimeter.name
+ return {_perimeter.id: _perimeter.to_return()}
+
+ def __set_perimeter(self, ClassType, ClassTypeException, policy_id, perimeter_id=None,
+ value=None):
+ if not value or "name" not in value or not value["name"].strip():
+ raise exceptions.PerimeterContentError('invalid name')
+ with self.get_session_for_write() as session:
+ _perimeter = None
+ if perimeter_id:
+ query = session.query(ClassType)
+ query = query.filter_by(id=perimeter_id)
+ _perimeter = query.first()
+ if not perimeter_id and not _perimeter:
+ query = session.query(ClassType)
+ query = query.filter_by(name=value['name'])
+ _perimeter = query.first()
+ if _perimeter:
+ raise ClassTypeException
+ if not _perimeter:
+ if "policy_list" not in value or type(value["policy_list"]) is not list:
+ value["policy_list"] = []
+ if policy_id and policy_id not in value["policy_list"]:
+ value["policy_list"] = [policy_id, ]
+
+ value_wo_name = copy.deepcopy(value)
+ value_wo_name.pop("name", None)
+ new = ClassType.from_dict({
+ "id": perimeter_id if perimeter_id else uuid4().hex,
+ "name": value["name"],
+ "value": value_wo_name
+ })
+ session.add(new)
+ return {new.id: new.to_return()}
+ else:
+ _value = copy.deepcopy(_perimeter.to_dict())
+ if "policy_list" not in _value["value"] or type(
+ _value["value"]["policy_list"]) is not list:
+ _value["value"]["policy_list"] = []
+ if policy_id and policy_id not in _value["value"]["policy_list"]:
+ _value["value"]["policy_list"].append(policy_id)
+ else:
+ if policy_id:
+ raise exceptions.PolicyExisting
+ raise exceptions.PerimeterContentError
+
+ _value["value"].update(value)
+
+ name = _value["value"]["name"]
+ _value["value"].pop("name")
+ new_perimeter = ClassType.from_dict({
+ "id": _value["id"],
+ "name": name,
+ "value": _value["value"]
+ })
+ _perimeter.value = new_perimeter.value
+ _perimeter.name = new_perimeter.name
+ return {_perimeter.id: _perimeter.to_return()}
+
+ def __delete_perimeter(self, ClassType, ClassUnknownException, policy_id, perimeter_id):
+ with self.get_session_for_write() as session:
+ query = session.query(ClassType)
+ query = query.filter_by(id=perimeter_id)
+ _perimeter = query.first()
+ if not _perimeter:
+ raise ClassUnknownException
+ old_perimeter = copy.deepcopy(_perimeter.to_dict())
+ try:
+ old_perimeter["value"]["policy_list"].remove(policy_id)
+ new_perimeter = ClassType.from_dict(old_perimeter)
+ if not new_perimeter.value["policy_list"]:
+ session.delete(_perimeter)
+ else:
+ setattr(_perimeter, "value", getattr(new_perimeter, "value"))
+ except ValueError:
+ if not _perimeter.value["policy_list"]:
+ session.delete(_perimeter)
+
+ def get_subjects(self, policy_id, perimeter_id=None):
+ return self.__get_perimeters(Subject, policy_id, perimeter_id)
+
+ def get_subject_by_name(self, perimeter_name):
+ return self.__get_perimeter_by_name(Subject, perimeter_name)
+
+ def set_subject(self, policy_id, perimeter_id=None, value=None):
+ try:
+ return self.__set_perimeter(Subject, exceptions.SubjectExisting, policy_id,
+ perimeter_id=perimeter_id, value=value)
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.SubjectExisting
+ raise error
+
+ def update_subject(self, perimeter_id, value):
+ try:
+ return self.__update_perimeter(Subject, exceptions.SubjectExisting, perimeter_id, value)
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.SubjectExisting
+ raise error
+
+ def delete_subject(self, policy_id, perimeter_id):
+ self.__delete_perimeter(Subject, exceptions.SubjectUnknown, policy_id, perimeter_id)
+
+ def get_objects(self, policy_id, perimeter_id=None):
+ return self.__get_perimeters(Object, policy_id, perimeter_id)
+
+ def get_object_by_name(self, perimeter_name):
+ return self.__get_perimeter_by_name(Object, perimeter_name)
+
+ def set_object(self, policy_id, perimeter_id=None, value=None):
+ try:
+ return self.__set_perimeter(Object, exceptions.ObjectExisting, policy_id,
+ perimeter_id=perimeter_id, value=value)
+ except sqlalchemy.exc.IntegrityError as error:
+ logger.exception("IntegrityError {}".format(error))
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.ObjectExisting
+ raise error
+
+ def update_object(self, perimeter_id, value):
+ try:
+ return self.__update_perimeter(Object, exceptions.ObjectExisting, perimeter_id, value)
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.ObjectExisting
+ raise error
+
+ def delete_object(self, policy_id, perimeter_id):
+ self.__delete_perimeter(Object, exceptions.ObjectUnknown, policy_id, perimeter_id)
+
+ def get_actions(self, policy_id, perimeter_id=None):
+ return self.__get_perimeters(Action, policy_id, perimeter_id)
+
+ def get_action_by_name(self, perimeter_name):
+ return self.__get_perimeter_by_name(Action, perimeter_name)
+
+ def set_action(self, policy_id, perimeter_id=None, value=None):
+ try:
+ return self.__set_perimeter(Action, exceptions.ActionExisting, policy_id,
+ perimeter_id=perimeter_id, value=value)
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.ActionExisting
+ raise error
+
+ def update_action(self, perimeter_id, value):
+ try:
+ return self.__update_perimeter(Action, exceptions.ActionExisting, perimeter_id, value)
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.ActionExisting
+ raise error
+
+ def delete_action(self, policy_id, perimeter_id):
+ self.__delete_perimeter(Action, exceptions.ActionUnknown, policy_id, perimeter_id)
+
+ def __is_data_exist(self, ClassType, category_id=None):
+
+ with self.get_session_for_read() as session:
+ query = session.query(ClassType)
+ query = query.filter_by(category_id=category_id)
+ ref_list = query.all()
+ if ref_list:
+ return True
+ return False
+
+ def __get_data(self, ClassType, policy_id, data_id=None, category_id=None):
+ with self.get_session_for_read() as session:
+ query = session.query(ClassType)
+ if policy_id and data_id and category_id:
+ query = query.filter_by(policy_id=policy_id, id=data_id, category_id=category_id)
+ elif policy_id and category_id:
+ query = query.filter_by(policy_id=policy_id, category_id=category_id)
+ elif category_id:
+ query = query.filter_by(category_id=category_id)
+ elif policy_id:
+ query = query.filter_by(policy_id=policy_id)
+ else:
+ raise exceptions.PolicyUnknown
+
+ ref_list = query.all()
+ return {
+ "policy_id": policy_id,
+ "category_id": category_id,
+ "data": {_ref.id: _ref.to_dict() for _ref in ref_list}
+ }
+
+ def __set_data(self, ClassType, ClassTypeData, policy_id, data_id=None, category_id=None,
+ value=None):
+ with self.get_session_for_write() as session:
+ query = session.query(ClassTypeData)
+ query = query.filter_by(policy_id=policy_id, id=data_id, category_id=category_id)
+ ref = query.first()
+ if not ref:
+ value_wo_name = copy.deepcopy(value)
+ value_wo_name.pop("name", None)
+ new_ref = ClassTypeData.from_dict(
+ {
+ "id": data_id if data_id else uuid4().hex,
+ 'name': value["name"],
+ 'value': value_wo_name,
+ 'category_id': category_id,
+ 'policy_id': policy_id,
+ }
+ )
+ session.add(new_ref)
+ ref = new_ref
+ else:
+ for attr in ClassType.attributes:
+ if attr != 'id':
+ setattr(ref, attr, getattr(ref, attr))
+ # session.flush()
+ return {
+ "policy_id": policy_id,
+ "category_id": category_id,
+ "data": {ref.id: ref.to_dict()}
+ }
+
+ def __delete_data(self, ClassType, policy_id, category_id, data_id):
+
+ if not data_id:
+ raise exceptions.DataUnknown
+ with self.get_session_for_write() as session:
+ query = session.query(ClassType)
+ if category_id:
+ query = query.filter_by(policy_id=policy_id, category_id=category_id, id=data_id)
+ else:
+ query = query.filter_by(policy_id=policy_id, id=data_id)
+ ref = query.first()
+ if ref:
+ session.delete(ref)
+
+ def is_subject_data_exist(self, category_id=None):
+ return self.__is_data_exist(SubjectData, category_id=category_id)
+
+ def get_subject_data(self, policy_id, data_id=None, category_id=None):
+ return self.__get_data(SubjectData, policy_id, data_id=data_id, category_id=category_id)
+
+ def set_subject_data(self, policy_id, data_id=None, category_id=None, value=None):
+ try:
+ return self.__set_data(Subject, SubjectData, policy_id, data_id=data_id,
+ category_id=category_id, value=value)
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.SubjectScopeExisting
+ raise error
+
+ def delete_subject_data(self, policy_id, category_id, data_id):
+ return self.__delete_data(SubjectData, policy_id, category_id, data_id)
+
+ def is_object_data_exist(self, category_id=None):
+ return self.__is_data_exist(ObjectData, category_id=category_id)
+
+ def get_object_data(self, policy_id, data_id=None, category_id=None):
+ return self.__get_data(ObjectData, policy_id, data_id=data_id, category_id=category_id)
+
+ def set_object_data(self, policy_id, data_id=None, category_id=None, value=None):
+ try:
+ return self.__set_data(Object, ObjectData, policy_id, data_id=data_id,
+ category_id=category_id, value=value)
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.ObjectScopeExisting
+ raise error
+
+ def delete_object_data(self, policy_id, category_id, data_id):
+ return self.__delete_data(ObjectData, policy_id, category_id, data_id)
+
+ def is_action_data_exist(self, category_id=None):
+ return self.__is_data_exist(ActionData, category_id=category_id)
+
+ def get_action_data(self, policy_id, data_id=None, category_id=None):
+ return self.__get_data(ActionData, policy_id, data_id=data_id, category_id=category_id)
+
+ def set_action_data(self, policy_id, data_id=None, category_id=None, value=None):
+ try:
+ return self.__set_data(Action, ActionData, policy_id, data_id=data_id,
+ category_id=category_id, value=value)
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.ActionScopeExisting
+ raise error
+
+ def delete_action_data(self, policy_id, category_id, data_id):
+ return self.__delete_data(ActionData, policy_id, category_id, data_id)
+
+ def get_subject_assignments(self, policy_id, subject_id=None, category_id=None):
+ with self.get_session_for_write() as session:
+ query = session.query(SubjectAssignment)
+ if subject_id and category_id:
+ # TODO change the subject_id to perimeter_id to allow code refactoring
+ query = query.filter_by(policy_id=policy_id, subject_id=subject_id,
+ category_id=category_id)
+ elif subject_id:
+ query = query.filter_by(policy_id=policy_id, subject_id=subject_id)
+ else:
+ query = query.filter_by(policy_id=policy_id)
+ ref_list = query.all()
+ return {_ref.id: _ref.to_dict() for _ref in ref_list}
+
+ def add_subject_assignment(self, policy_id, subject_id, category_id, data_id):
+ with self.get_session_for_write() as session:
+ query = session.query(SubjectAssignment)
+ query = query.filter_by(policy_id=policy_id, subject_id=subject_id,
+ category_id=category_id)
+ ref = query.first()
+ if ref:
+ old_ref = copy.deepcopy(ref.to_dict())
+ assignments = old_ref["assignments"]
+ if data_id not in assignments:
+ assignments.append(data_id)
+ setattr(ref, "assignments", assignments)
+ else:
+ raise exceptions.SubjectAssignmentExisting
+ else:
+ ref = SubjectAssignment.from_dict(
+ {
+ "id": uuid4().hex,
+ "policy_id": policy_id,
+ "subject_id": subject_id,
+ "category_id": category_id,
+ "assignments": [data_id, ],
+ }
+ )
+ session.add(ref)
+ return {ref.id: ref.to_dict()}
+
+ def is_subject_category_has_assignment(self, category_id):
+ return self.__is_category_has_assignment(SubjectAssignment, category_id)
+
+ def is_object_category_has_assignment(self, category_id):
+ return self.__is_category_has_assignment(ObjectAssignment, category_id)
+
+ def is_action_category_has_assignment(self, category_id):
+ return self.__is_category_has_assignment(ActionAssignment, category_id)
+
+ def __is_category_has_assignment(self, ClassType, category_id):
+ with self.get_session_for_write() as session:
+ query = session.query(ClassType)
+ query = query.filter_by(category_id=category_id)
+ count = query.count()
+ return count > 0
+
+ def delete_subject_assignment(self, policy_id, subject_id, category_id, data_id):
+ with self.get_session_for_write() as session:
+ query = session.query(SubjectAssignment)
+ query = query.filter_by(policy_id=policy_id, subject_id=subject_id,
+ category_id=category_id)
+ ref = query.first()
+ if ref:
+ old_ref = copy.deepcopy(ref.to_dict())
+ assignments = old_ref["assignments"]
+ # TODO (asteroide): if data_id is None, delete all
+ if data_id in assignments:
+ assignments.remove(data_id)
+ # FIXME (asteroide): the setattr doesn't work here ; the assignments is not updated in the database
+ setattr(ref, "assignments", assignments)
+ if not assignments:
+ session.delete(ref)
+
+ def get_object_assignments(self, policy_id, object_id=None, category_id=None):
+ with self.get_session_for_write() as session:
+ query = session.query(ObjectAssignment)
+ if object_id and category_id:
+ # TODO change the object_id to perimeter_id to allow code refactoring
+ query = query.filter_by(policy_id=policy_id, object_id=object_id,
+ category_id=category_id)
+ elif object_id:
+ query = query.filter_by(policy_id=policy_id, object_id=object_id)
+ else:
+ query = query.filter_by(policy_id=policy_id)
+ ref_list = query.all()
+ return {_ref.id: _ref.to_dict() for _ref in ref_list}
+
+ def add_object_assignment(self, policy_id, object_id, category_id, data_id):
+ with self.get_session_for_write() as session:
+ query = session.query(ObjectAssignment)
+ query = query.filter_by(policy_id=policy_id, object_id=object_id,
+ category_id=category_id)
+ ref = query.first()
+ if ref:
+ old_ref = copy.deepcopy(ref.to_dict())
+ assignments = old_ref["assignments"]
+ if data_id not in assignments:
+ assignments.append(data_id)
+ setattr(ref, "assignments", assignments)
+ else:
+ raise exceptions.ObjectAssignmentExisting
+ else:
+ ref = ObjectAssignment.from_dict(
+ {
+ "id": uuid4().hex,
+ "policy_id": policy_id,
+ "object_id": object_id,
+ "category_id": category_id,
+ "assignments": [data_id, ],
+ }
+ )
+ session.add(ref)
+ return {ref.id: ref.to_dict()}
+
+ def delete_object_assignment(self, policy_id, object_id, category_id, data_id):
+ with self.get_session_for_write() as session:
+ query = session.query(ObjectAssignment)
+ query = query.filter_by(policy_id=policy_id, object_id=object_id,
+ category_id=category_id)
+ ref = query.first()
+ if ref:
+ old_ref = copy.deepcopy(ref.to_dict())
+ assignments = old_ref["assignments"]
+ # TODO (asteroide): if data_id is None, delete all
+ if data_id in assignments:
+ assignments.remove(data_id)
+ # FIXME (asteroide): the setattr doesn't work here ; the assignments is not updated in the database
+ setattr(ref, "assignments", assignments)
+ if not assignments:
+ session.delete(ref)
+
+ def get_action_assignments(self, policy_id, action_id=None, category_id=None):
+ with self.get_session_for_write() as session:
+ if not policy_id:
+ return exceptions.PolicyUnknown
+ query = session.query(ActionAssignment)
+ if action_id and category_id:
+ # TODO change the action_id to perimeter_id to allow code refactoring
+ query = query.filter_by(policy_id=policy_id, action_id=action_id,
+ category_id=category_id)
+ elif action_id:
+ query = query.filter_by(policy_id=policy_id, action_id=action_id)
+ elif category_id:
+ query = query.filter_by(policy_id=policy_id, category_id=category_id)
+ else:
+ query = query.filter_by(policy_id=policy_id)
+ ref_list = query.all()
+ return {_ref.id: _ref.to_dict() for _ref in ref_list}
+
+ def add_action_assignment(self, policy_id, action_id, category_id, data_id):
+ with self.get_session_for_write() as session:
+ query = session.query(ActionAssignment)
+ query = query.filter_by(policy_id=policy_id, action_id=action_id,
+ category_id=category_id)
+ ref = query.first()
+ if ref:
+ old_ref = copy.deepcopy(ref.to_dict())
+ assignments = old_ref["assignments"]
+ if data_id not in assignments:
+ assignments.append(data_id)
+ setattr(ref, "assignments", assignments)
+ else:
+ raise exceptions.ActionAssignmentExisting
+ else:
+ ref = ActionAssignment.from_dict(
+ {
+ "id": uuid4().hex,
+ "policy_id": policy_id,
+ "action_id": action_id,
+ "category_id": category_id,
+ "assignments": [data_id, ],
+ }
+ )
+ session.add(ref)
+ return {ref.id: ref.to_dict()}
+
+ def delete_action_assignment(self, policy_id, action_id, category_id, data_id):
+ with self.get_session_for_write() as session:
+ query = session.query(ActionAssignment)
+ query = query.filter_by(policy_id=policy_id, action_id=action_id,
+ category_id=category_id)
+ ref = query.first()
+ if ref:
+ old_ref = copy.deepcopy(ref.to_dict())
+ assignments = old_ref["assignments"]
+ # TODO (asteroide): if data_id is None, delete all
+ if data_id in assignments:
+ assignments.remove(data_id)
+ # FIXME (asteroide): the setattr doesn't work here ; the assignments is not updated in the database
+ setattr(ref, "assignments", assignments)
+ if not assignments:
+ session.delete(ref)
+
+ def get_rules(self, policy_id, rule_id=None, meta_rule_id=None):
+ with self.get_session_for_read() as session:
+ query = session.query(Rule)
+ if rule_id:
+ query = query.filter_by(policy_id=policy_id, rule_id=rule_id)
+ ref = query.first()
+ return {ref.id: ref.to_dict()}
+ elif meta_rule_id and policy_id:
+ query = query.filter_by(policy_id=policy_id, meta_rule_id=meta_rule_id)
+ ref_list = query.all()
+ return {
+ "meta_rule_id": meta_rule_id,
+ "policy_id": policy_id,
+ "rules": list(map(lambda x: x.to_dict(), ref_list))
+ }
+ else:
+ query = query.filter_by(policy_id=policy_id)
+ ref_list = query.all()
+ return {
+ "policy_id": policy_id,
+ "rules": list(map(lambda x: x.to_dict(), ref_list))
+ }
+
+ def is_meta_rule_has_rules(self, meta_rule_id):
+ with self.get_session_for_read() as session:
+ query = session.query(Rule)
+
+ query = query.filter_by(meta_rule_id=meta_rule_id)
+ count = query.count()
+ return count > 0
+
+ def add_rule(self, policy_id, meta_rule_id, value):
+ try:
+ rules = self.get_rules(policy_id, meta_rule_id=meta_rule_id)
+ for _rule in map(lambda x: x["rule"], rules["rules"]):
+ if list(value.get('rule')) == list(_rule):
+ raise exceptions.RuleExisting
+ with self.get_session_for_write() as session:
+ ref = Rule.from_dict(
+ {
+ "id": uuid4().hex,
+ "policy_id": policy_id,
+ "meta_rule_id": meta_rule_id,
+ "rule": value
+ }
+ )
+ session.add(ref)
+ return {ref.id: ref.to_dict()}
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.RuleExisting
+ raise error
+
+ def delete_rule(self, policy_id, rule_id):
+ with self.get_session_for_write() as session:
+ query = session.query(Rule)
+ query = query.filter_by(policy_id=policy_id, id=rule_id)
+ ref = query.first()
+ if ref:
+ session.delete(ref)
+
+
+class ModelConnector(BaseConnector, ModelDriver):
+
+ def update_model(self, model_id, value):
+ try:
+ with self.get_session_for_write() as session:
+ query = session.query(Model)
+ if model_id:
+ query = query.filter_by(id=model_id)
+ ref = query.first()
+ if ref:
+ value_wo_name = copy.deepcopy(value)
+ value_wo_name.pop("name", None)
+ setattr(ref, "name", value["name"])
+ d = dict(ref.value)
+ d.update(value_wo_name)
+ setattr(ref, "value", d)
+ return {ref.id: ref.to_dict()}
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.ModelExisting
+ raise error
+
+ def delete_model(self, model_id):
+ with self.get_session_for_write() as session:
+ ref = session.query(Model).get(model_id)
+ session.delete(ref)
+
+ def add_model(self, model_id=None, value=None):
+ try:
+ with self.get_session_for_write() as session:
+ value_wo_name = copy.deepcopy(value)
+ value_wo_name.pop("name", None)
+ new = Model.from_dict({
+ "id": model_id if model_id else uuid4().hex,
+ "name": value["name"],
+ "value": value_wo_name
+ })
+ session.add(new)
+ return {new.id: new.to_dict()}
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.ModelExisting
+
+ def get_models(self, model_id=None):
+ with self.get_session_for_read() as session:
+ query = session.query(Model)
+ if model_id:
+ ref_list = query.filter(Model.id == model_id)
+ else:
+ ref_list = query.all()
+
+ r = {_ref.id: _ref.to_dict() for _ref in ref_list}
+ return r
+
+ def set_meta_rule(self, meta_rule_id, value):
+ try:
+ with self.get_session_for_write() as session:
+ value_wo_other_data = copy.deepcopy(value)
+ value_wo_other_data.pop("name", None)
+ value_wo_other_data.pop("subject_categories", None)
+ value_wo_other_data.pop("object_categories", None)
+ value_wo_other_data.pop("action_categories", None)
+ if meta_rule_id is None:
+ try:
+ ref = MetaRule.from_dict(
+ {
+ "id": uuid4().hex,
+ "name": value["name"],
+ "subject_categories": value["subject_categories"],
+ "object_categories": value["object_categories"],
+ "action_categories": value["action_categories"],
+ "value": value_wo_other_data
+ }
+ )
+ session.add(ref)
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.MetaRuleExisting
+ raise error
+ else:
+ query = session.query(MetaRule)
+ query = query.filter_by(id=meta_rule_id)
+ ref = query.first()
+ setattr(ref, "name", value["name"])
+ setattr(ref, "subject_categories", value["subject_categories"])
+ setattr(ref, "object_categories", value["object_categories"])
+ setattr(ref, "action_categories", value["action_categories"])
+ setattr(ref, "value", value_wo_other_data)
+ return {ref.id: ref.to_dict()}
+ except sqlalchemy.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.MetaRuleExisting
+ raise error
+
+ def get_meta_rules(self, meta_rule_id=None):
+ with self.get_session_for_read() as session:
+ query = session.query(MetaRule)
+ if meta_rule_id:
+ query = query.filter_by(id=meta_rule_id)
+ ref_list = query.all()
+ return {_ref.id: _ref.to_dict() for _ref in ref_list}
+
+ def delete_meta_rule(self, meta_rule_id=None):
+ with self.get_session_for_write() as session:
+ query = session.query(MetaRule)
+ query = query.filter_by(id=meta_rule_id)
+ ref = query.first()
+ if ref:
+ session.delete(ref)
+
+ def __get_perimeter_categories(self, ClassType, category_id=None):
+ with self.get_session_for_read() as session:
+ query = session.query(ClassType)
+ if category_id:
+ query = query.filter_by(id=category_id)
+ ref_list = query.all()
+ return {_ref.id: _ref.to_dict() for _ref in ref_list}
+
+ def __add_perimeter_category(self, ClassType, name, description, uuid=None):
+ if not name or not name.strip():
+ raise exceptions.CategoryNameInvalid
+ with self.get_session_for_write() as session:
+ ref = ClassType.from_dict(
+ {
+ "id": uuid if uuid else uuid4().hex,
+ "name": name,
+ "description": description
+ }
+ )
+ session.add(ref)
+ return {ref.id: ref.to_dict()}
+
+ def __delete_perimeter_category(self, ClassType, category_id):
+ with self.get_session_for_write() as session:
+ query = session.query(ClassType)
+ query = query.filter_by(id=category_id)
+ ref = query.first()
+ if ref:
+ session.delete(ref)
+
+ def get_subject_categories(self, category_id=None):
+ return self.__get_perimeter_categories(SubjectCategory, category_id=category_id)
+
+ def add_subject_category(self, name, description, uuid=None):
+ try:
+ return self.__add_perimeter_category(SubjectCategory, name, description, uuid=uuid)
+ except sql.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.SubjectCategoryExisting
+ raise error
+
+ def delete_subject_category(self, category_id):
+ self.__delete_perimeter_category(SubjectCategory, category_id)
+
+ def get_object_categories(self, category_id=None):
+ return self.__get_perimeter_categories(ObjectCategory, category_id=category_id)
+
+ def add_object_category(self, name, description, uuid=None):
+ try:
+ return self.__add_perimeter_category(ObjectCategory, name, description, uuid=uuid)
+ except sql.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.ObjectCategoryExisting
+ raise error
+
+ def delete_object_category(self, category_id):
+ self.__delete_perimeter_category(ObjectCategory, category_id)
+
+ def get_action_categories(self, category_id=None):
+
+ return self.__get_perimeter_categories(ActionCategory, category_id=category_id)
+
+ def add_action_category(self, name, description, uuid=None):
+ try:
+ return self.__add_perimeter_category(ActionCategory, name, description, uuid=uuid)
+ except sql.exc.IntegrityError as error:
+ if 'UNIQUE constraint' in str(error):
+ raise exceptions.ActionCategoryExisting
+ raise error
+
+ def delete_action_category(self, category_id):
+ self.__delete_perimeter_category(ActionCategory, category_id)
+
+ # Getter and Setter for subject_category
+
+ # def get_subject_categories_dict(self, intra_extension_id):
+ # with self.get_session_for_read() as session:
+ # query = session.query(SubjectCategory)
+ # query = query.filter_by(intra_extension_id=intra_extension_id)
+ # ref_list = query.all()
+ # return {_ref.id: _ref.subject_category for _ref in ref_list}
+ #
+ # def set_subject_category_dict(self, intra_extension_id, subject_category_id, subject_category_dict):
+ # with self.get_session_for_write() as session:
+ # query = session.query(SubjectCategory)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, id=subject_category_id)
+ # ref = query.first()
+ # new_ref = SubjectCategory.from_dict(
+ # {
+ # "id": subject_category_id,
+ # 'subject_category': subject_category_dict,
+ # 'intra_extension_id': intra_extension_id
+ # }
+ # )
+ # if not ref:
+ # session.add(new_ref)
+ # ref = new_ref
+ # else:
+ # for attr in SubjectCategory.attributes:
+ # if attr != 'id':
+ # setattr(ref, attr, getattr(new_ref, attr))
+ # # # session.flush()
+ # return {subject_category_id: SubjectCategory.to_dict(ref)['subject_category']}
+ #
+ # def del_subject_category(self, intra_extension_id, subject_category_id):
+ # with self.get_session_for_write() as session:
+ # query = session.query(SubjectCategory)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, id=subject_category_id)
+ # ref = query.first()
+ # self.del_subject_assignment(intra_extension_id, None, None, None)
+ # session.delete(ref)
+ #
+ # # Getter and Setter for object_category
+ #
+ # def get_object_categories_dict(self, intra_extension_id):
+ # with self.get_session_for_read() as session:
+ # query = session.query(ObjectCategory)
+ # query = query.filter_by(intra_extension_id=intra_extension_id)
+ # ref_list = query.all()
+ # return {_ref.id: _ref.object_category for _ref in ref_list}
+ #
+ # def set_object_category_dict(self, intra_extension_id, object_category_id, object_category_dict):
+ # with self.get_session_for_write() as session:
+ # query = session.query(ObjectCategory)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, id=object_category_id)
+ # ref = query.first()
+ # new_ref = ObjectCategory.from_dict(
+ # {
+ # "id": object_category_id,
+ # 'object_category': object_category_dict,
+ # 'intra_extension_id': intra_extension_id
+ # }
+ # )
+ # if not ref:
+ # session.add(new_ref)
+ # ref = new_ref
+ # else:
+ # for attr in ObjectCategory.attributes:
+ # if attr != 'id':
+ # setattr(ref, attr, getattr(new_ref, attr))
+ # # session.flush()
+ # return {object_category_id: ObjectCategory.to_dict(ref)['object_category']}
+ #
+ # def del_object_category(self, intra_extension_id, object_category_id):
+ # with self.get_session_for_write() as session:
+ # query = session.query(ObjectCategory)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, id=object_category_id)
+ # ref = query.first()
+ # self.del_object_assignment(intra_extension_id, None, None, None)
+ # session.delete(ref)
+ #
+ # # Getter and Setter for action_category
+ #
+ # def get_action_categories_dict(self, intra_extension_id):
+ # with self.get_session_for_read() as session:
+ # query = session.query(ActionCategory)
+ # query = query.filter_by(intra_extension_id=intra_extension_id)
+ # ref_list = query.all()
+ # return {_ref.id: _ref.action_category for _ref in ref_list}
+ #
+ # def set_action_category_dict(self, intra_extension_id, action_category_id, action_category_dict):
+ # with self.get_session_for_write() as session:
+ # query = session.query(ActionCategory)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, id=action_category_id)
+ # ref = query.first()
+ # new_ref = ActionCategory.from_dict(
+ # {
+ # "id": action_category_id,
+ # 'action_category': action_category_dict,
+ # 'intra_extension_id': intra_extension_id
+ # }
+ # )
+ # if not ref:
+ # session.add(new_ref)
+ # ref = new_ref
+ # else:
+ # for attr in ActionCategory.attributes:
+ # if attr != 'id':
+ # setattr(ref, attr, getattr(new_ref, attr))
+ # # session.flush()
+ # return {action_category_id: ActionCategory.to_dict(ref)['action_category']}
+ #
+ # def del_action_category(self, intra_extension_id, action_category_id):
+ # with self.get_session_for_write() as session:
+ # query = session.query(ActionCategory)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, id=action_category_id)
+ # ref = query.first()
+ # self.del_action_assignment(intra_extension_id, None, None, None)
+ # session.delete(ref)
+
+ # Perimeter
+
+ # def get_subjects_dict(self, intra_extension_id):
+ # with self.get_session_for_read() as session:
+ # query = session.query(Subject)
+ # query = query.filter_by(intra_extension_id=intra_extension_id)
+ # ref_list = query.all()
+ # return {_ref.id: _ref.subject for _ref in ref_list}
+ #
+ # def set_subject_dict(self, intra_extension_id, subject_id, subject_dict):
+ # with self.get_session_for_write() as session:
+ # query = session.query(Subject)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, id=subject_id)
+ # ref = query.first()
+ # # if 'id' in subject_dict:
+ # # subject_dict['id'] = subject_id
+ # new_ref = Subject.from_dict(
+ # {
+ # "id": subject_id,
+ # 'subject': subject_dict,
+ # 'intra_extension_id': intra_extension_id
+ # }
+ # )
+ # if not ref:
+ # session.add(new_ref)
+ # ref = new_ref
+ # else:
+ # for attr in Subject.attributes:
+ # if attr != 'id':
+ # setattr(ref, attr, getattr(new_ref, attr))
+ # # session.flush()
+ # return {subject_id: Subject.to_dict(ref)['subject']}
+ #
+ # def del_subject(self, intra_extension_id, subject_id):
+ # with self.get_session_for_write() as session:
+ # query = session.query(Subject)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, id=subject_id)
+ # ref = query.first()
+ # session.delete(ref)
+ #
+ # def get_objects_dict(self, intra_extension_id):
+ # with self.get_session_for_read() as session:
+ # query = session.query(Object)
+ # query = query.filter_by(intra_extension_id=intra_extension_id)
+ # ref_list = query.all()
+ # return {_ref.id: _ref.object for _ref in ref_list}
+ #
+ # def set_object_dict(self, intra_extension_id, object_id, object_dict):
+ # with self.get_session_for_write() as session:
+ # query = session.query(Object)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, id=object_id)
+ # ref = query.first()
+ # new_ref = Object.from_dict(
+ # {
+ # "id": object_id,
+ # 'object': object_dict,
+ # 'intra_extension_id': intra_extension_id
+ # }
+ # )
+ # if not ref:
+ # session.add(new_ref)
+ # ref = new_ref
+ # else:
+ # for attr in Object.attributes:
+ # if attr != 'id':
+ # setattr(ref, attr, getattr(new_ref, attr))
+ # # session.flush()
+ # return {object_id: Object.to_dict(ref)['object']}
+ #
+ # def del_object(self, intra_extension_id, object_id):
+ # with self.get_session_for_write() as session:
+ # query = session.query(Object)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, id=object_id)
+ # ref = query.first()
+ # session.delete(ref)
+ #
+ # def get_actions_dict(self, intra_extension_id):
+ # with self.get_session_for_read() as session:
+ # query = session.query(Action)
+ # query = query.filter_by(intra_extension_id=intra_extension_id)
+ # ref_list = query.all()
+ # return {_ref.id: _ref.action for _ref in ref_list}
+ #
+ # def set_action_dict(self, intra_extension_id, action_id, action_dict):
+ # with self.get_session_for_write() as session:
+ # query = session.query(Action)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, id=action_id)
+ # ref = query.first()
+ # new_ref = Action.from_dict(
+ # {
+ # "id": action_id,
+ # 'action': action_dict,
+ # 'intra_extension_id': intra_extension_id
+ # }
+ # )
+ # if not ref:
+ # session.add(new_ref)
+ # ref = new_ref
+ # else:
+ # for attr in Action.attributes:
+ # if attr != 'id':
+ # setattr(ref, attr, getattr(new_ref, attr))
+ # # session.flush()
+ # return {action_id: Action.to_dict(ref)['action']}
+ #
+ # def del_action(self, intra_extension_id, action_id):
+ # with self.get_session_for_write() as session:
+ # query = session.query(Action)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, id=action_id)
+ # ref = query.first()
+ # session.delete(ref)
+
+ # Getter and Setter for subject_scope
+
+ # def get_subject_scopes_dict(self, intra_extension_id, subject_category_id):
+ # with self.get_session_for_read() as session:
+ # query = session.query(SubjectScope)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, subject_category_id=subject_category_id)
+ # ref_list = query.all()
+ # return {_ref.id: _ref.subject_scope for _ref in ref_list}
+ #
+ # def set_subject_scope_dict(self, intra_extension_id, subject_category_id, subject_scope_id, subject_scope_dict):
+ # with self.get_session_for_write() as session:
+ # query = session.query(SubjectScope)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, subject_category_id=subject_category_id, id=subject_scope_id)
+ # ref = query.first()
+ # new_ref = SubjectScope.from_dict(
+ # {
+ # "id": subject_scope_id,
+ # 'subject_scope': subject_scope_dict,
+ # 'intra_extension_id': intra_extension_id,
+ # 'subject_category_id': subject_category_id
+ # }
+ # )
+ # if not ref:
+ # session.add(new_ref)
+ # ref = new_ref
+ # else:
+ # for attr in Subject.attributes:
+ # if attr != 'id':
+ # setattr(ref, attr, getattr(new_ref, attr))
+ # # session.flush()
+ # return {subject_scope_id: SubjectScope.to_dict(ref)['subject_scope']}
+ #
+ # def del_subject_scope(self, intra_extension_id, subject_category_id, subject_scope_id):
+ # with self.get_session_for_write() as session:
+ # query = session.query(SubjectScope)
+ # if not subject_category_id or not subject_scope_id:
+ # query = query.filter_by(intra_extension_id=intra_extension_id)
+ # for ref in query.all():
+ # session.delete(ref)
+ # else:
+ # query = query.filter_by(intra_extension_id=intra_extension_id, subject_category_id=subject_category_id, id=subject_scope_id)
+ # ref = query.first()
+ # session.delete(ref)
+ #
+ # # Getter and Setter for object_category_scope
+ #
+ # def get_object_scopes_dict(self, intra_extension_id, object_category_id):
+ # with self.get_session_for_read() as session:
+ # query = session.query(ObjectScope)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, object_category_id=object_category_id)
+ # ref_list = query.all()
+ # return {_ref.id: _ref.object_scope for _ref in ref_list}
+ #
+ # def set_object_scope_dict(self, intra_extension_id, object_category_id, object_scope_id, object_scope_dict):
+ # with self.get_session_for_write() as session:
+ # query = session.query(ObjectScope)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, object_category_id=object_category_id, id=object_scope_id)
+ # ref = query.first()
+ # new_ref = ObjectScope.from_dict(
+ # {
+ # "id": object_scope_id,
+ # 'object_scope': object_scope_dict,
+ # 'intra_extension_id': intra_extension_id,
+ # 'object_category_id': object_category_id
+ # }
+ # )
+ # if not ref:
+ # session.add(new_ref)
+ # ref = new_ref
+ # else:
+ # for attr in Object.attributes:
+ # if attr != 'id':
+ # setattr(ref, attr, getattr(new_ref, attr))
+ # # session.flush()
+ # return {object_scope_id: ObjectScope.to_dict(ref)['object_scope']}
+ #
+ # def del_object_scope(self, intra_extension_id, object_category_id, object_scope_id):
+ # with self.get_session_for_write() as session:
+ # query = session.query(ObjectScope)
+ # if not object_category_id or not object_scope_id:
+ # query = query.filter_by(intra_extension_id=intra_extension_id)
+ # for ref in query.all():
+ # session.delete(ref)
+ # else:
+ # query = query.filter_by(intra_extension_id=intra_extension_id, object_category_id=object_category_id, id=object_scope_id)
+ # ref = query.first()
+ # session.delete(ref)
+ #
+ # # Getter and Setter for action_scope
+ #
+ # def get_action_scopes_dict(self, intra_extension_id, action_category_id):
+ # with self.get_session_for_read() as session:
+ # query = session.query(ActionScope)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, action_category_id=action_category_id)
+ # ref_list = query.all()
+ # return {_ref.id: _ref.action_scope for _ref in ref_list}
+ #
+ # def set_action_scope_dict(self, intra_extension_id, action_category_id, action_scope_id, action_scope_dict):
+ # with self.get_session_for_write() as session:
+ # query = session.query(ActionScope)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, action_category_id=action_category_id, id=action_scope_id)
+ # ref = query.first()
+ # new_ref = ActionScope.from_dict(
+ # {
+ # "id": action_scope_id,
+ # 'action_scope': action_scope_dict,
+ # 'intra_extension_id': intra_extension_id,
+ # 'action_category_id': action_category_id
+ # }
+ # )
+ # if not ref:
+ # session.add(new_ref)
+ # ref = new_ref
+ # else:
+ # for attr in Action.attributes:
+ # if attr != 'id':
+ # setattr(ref, attr, getattr(new_ref, attr))
+ # # session.flush()
+ # return {action_scope_id: ActionScope.to_dict(ref)['action_scope']}
+ #
+ # def del_action_scope(self, intra_extension_id, action_category_id, action_scope_id):
+ # with self.get_session_for_write() as session:
+ # query = session.query(ActionScope)
+ # if not action_category_id or not action_scope_id:
+ # query = query.filter_by(intra_extension_id=intra_extension_id)
+ # for ref in query.all():
+ # session.delete(ref)
+ # else:
+ # query = query.filter_by(intra_extension_id=intra_extension_id, action_category_id=action_category_id, id=action_scope_id)
+ # ref = query.first()
+ # session.delete(ref)
+ #
+ # # Getter and Setter for subject_category_assignment
+ #
+ # def get_subject_assignment_list(self, intra_extension_id, subject_id, subject_category_id):
+ # with self.get_session_for_read() as session:
+ # query = session.query(SubjectAssignment)
+ # if not subject_id or not subject_category_id or not subject_category_id:
+ # query = query.filter_by(intra_extension_id=intra_extension_id)
+ # ref = query.all()
+ # return ref
+ # else:
+ # query = query.filter_by(intra_extension_id=intra_extension_id, subject_id=subject_id, subject_category_id=subject_category_id)
+ # ref = query.first()
+ # if not ref:
+ # return list()
+ # LOG.info("get_subject_assignment_list {}".format(ref.subject_assignment))
+ # return list(ref.subject_assignment)
+ #
+ # def set_subject_assignment_list(self, intra_extension_id, subject_id, subject_category_id, subject_assignment_list=[]):
+ # with self.get_session_for_write() as session:
+ # query = session.query(SubjectAssignment)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, subject_id=subject_id, subject_category_id=subject_category_id)
+ # ref = query.first()
+ # new_ref = SubjectAssignment.from_dict(
+ # {
+ # "id": uuid4().hex,
+ # 'subject_assignment': subject_assignment_list,
+ # 'intra_extension_id': intra_extension_id,
+ # 'subject_id': subject_id,
+ # 'subject_category_id': subject_category_id
+ # }
+ # )
+ # if not ref:
+ # session.add(new_ref)
+ # ref = new_ref
+ # else:
+ # for attr in SubjectAssignment.attributes:
+ # if attr != 'id':
+ # setattr(ref, attr, getattr(new_ref, attr))
+ # # session.flush()
+ # return subject_assignment_list
+ #
+ # def add_subject_assignment_list(self, intra_extension_id, subject_id, subject_category_id, subject_scope_id):
+ # new_subject_assignment_list = self.get_subject_assignment_list(intra_extension_id, subject_id, subject_category_id)
+ # if subject_scope_id not in new_subject_assignment_list:
+ # new_subject_assignment_list.append(subject_scope_id)
+ # return self.set_subject_assignment_list(intra_extension_id, subject_id, subject_category_id, new_subject_assignment_list)
+ #
+ # def del_subject_assignment(self, intra_extension_id, subject_id, subject_category_id, subject_scope_id):
+ # if not subject_id or not subject_category_id or not subject_category_id:
+ # with self.get_session_for_write() as session:
+ # for ref in self.get_subject_assignment_list(intra_extension_id, None, None):
+ # session.delete(ref)
+ # session.flush()
+ # return
+ # new_subject_assignment_list = self.get_subject_assignment_list(intra_extension_id, subject_id, subject_category_id)
+ # new_subject_assignment_list.remove(subject_scope_id)
+ # return self.set_subject_assignment_list(intra_extension_id, subject_id, subject_category_id, new_subject_assignment_list)
+ #
+ # # Getter and Setter for object_category_assignment
+ #
+ # def get_object_assignment_list(self, intra_extension_id, object_id, object_category_id):
+ # with self.get_session_for_read() as session:
+ # query = session.query(ObjectAssignment)
+ # if not object_id or not object_category_id or not object_category_id:
+ # query = query.filter_by(intra_extension_id=intra_extension_id)
+ # ref = query.all()
+ # return ref
+ # else:
+ # query = query.filter_by(intra_extension_id=intra_extension_id, object_id=object_id, object_category_id=object_category_id)
+ # ref = query.first()
+ # if not ref:
+ # return list()
+ # return list(ref.object_assignment)
+ #
+ # def set_object_assignment_list(self, intra_extension_id, object_id, object_category_id, object_assignment_list=[]):
+ # with self.get_session_for_write() as session:
+ # query = session.query(ObjectAssignment)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, object_id=object_id, object_category_id=object_category_id)
+ # ref = query.first()
+ # new_ref = ObjectAssignment.from_dict(
+ # {
+ # "id": uuid4().hex,
+ # 'object_assignment': object_assignment_list,
+ # 'intra_extension_id': intra_extension_id,
+ # 'object_id': object_id,
+ # 'object_category_id': object_category_id
+ # }
+ # )
+ # if not ref:
+ # session.add(new_ref)
+ # else:
+ # for attr in ObjectAssignment.attributes:
+ # if attr != 'id':
+ # setattr(ref, attr, getattr(new_ref, attr))
+ # # session.flush()
+ # return self.get_object_assignment_list(intra_extension_id, object_id, object_category_id)
+ #
+ # def add_object_assignment_list(self, intra_extension_id, object_id, object_category_id, object_scope_id):
+ # new_object_assignment_list = self.get_object_assignment_list(intra_extension_id, object_id, object_category_id)
+ # if object_scope_id not in new_object_assignment_list:
+ # new_object_assignment_list.append(object_scope_id)
+ # return self.set_object_assignment_list(intra_extension_id, object_id, object_category_id, new_object_assignment_list)
+ #
+ # def del_object_assignment(self, intra_extension_id, object_id, object_category_id, object_scope_id):
+ # if not object_id or not object_category_id or not object_category_id:
+ # with self.get_session_for_write() as session:
+ # for ref in self.get_object_assignment_list(intra_extension_id, None, None):
+ # session.delete(ref)
+ # session.flush()
+ # return
+ # new_object_assignment_list = self.get_object_assignment_list(intra_extension_id, object_id, object_category_id)
+ # new_object_assignment_list.remove(object_scope_id)
+ # return self.set_object_assignment_list(intra_extension_id, object_id, object_category_id, new_object_assignment_list)
+ #
+ # # Getter and Setter for action_category_assignment
+ #
+ # def get_action_assignment_list(self, intra_extension_id, action_id, action_category_id):
+ # with self.get_session_for_read() as session:
+ # query = session.query(ActionAssignment)
+ # if not action_id or not action_category_id or not action_category_id:
+ # query = query.filter_by(intra_extension_id=intra_extension_id)
+ # ref = query.all()
+ # return ref
+ # else:
+ # query = query.filter_by(intra_extension_id=intra_extension_id, action_id=action_id, action_category_id=action_category_id)
+ # ref = query.first()
+ # if not ref:
+ # return list()
+ # return list(ref.action_assignment)
+ #
+ # def set_action_assignment_list(self, intra_extension_id, action_id, action_category_id, action_assignment_list=[]):
+ # with self.get_session_for_write() as session:
+ # query = session.query(ActionAssignment)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, action_id=action_id, action_category_id=action_category_id)
+ # ref = query.first()
+ # new_ref = ActionAssignment.from_dict(
+ # {
+ # "id": uuid4().hex,
+ # 'action_assignment': action_assignment_list,
+ # 'intra_extension_id': intra_extension_id,
+ # 'action_id': action_id,
+ # 'action_category_id': action_category_id
+ # }
+ # )
+ # if not ref:
+ # session.add(new_ref)
+ # else:
+ # for attr in ActionAssignment.attributes:
+ # if attr != 'id':
+ # setattr(ref, attr, getattr(new_ref, attr))
+ # # session.flush()
+ # return self.get_action_assignment_list(intra_extension_id, action_id, action_category_id)
+ #
+ # def add_action_assignment_list(self, intra_extension_id, action_id, action_category_id, action_scope_id):
+ # new_action_assignment_list = self.get_action_assignment_list(intra_extension_id, action_id, action_category_id)
+ # if action_scope_id not in new_action_assignment_list:
+ # new_action_assignment_list.append(action_scope_id)
+ # return self.set_action_assignment_list(intra_extension_id, action_id, action_category_id, new_action_assignment_list)
+ #
+ # def del_action_assignment(self, intra_extension_id, action_id, action_category_id, action_scope_id):
+ # if not action_id or not action_category_id or not action_category_id:
+ # with self.get_session_for_write() as session:
+ # for ref in self.get_action_assignment_list(intra_extension_id, None, None):
+ # session.delete(ref)
+ # session.flush()
+ # return
+ # new_action_assignment_list = self.get_action_assignment_list(intra_extension_id, action_id, action_category_id)
+ # new_action_assignment_list.remove(action_scope_id)
+ # return self.set_action_assignment_list(intra_extension_id, action_id, action_category_id, new_action_assignment_list)
+ #
+ # # Getter and Setter for sub_meta_rule
+ #
+ # def get_aggregation_algorithm_id(self, intra_extension_id):
+ # with self.get_session_for_read() as session:
+ # query = session.query(IntraExtension)
+ # query = query.filter_by(id=intra_extension_id)
+ # ref = query.first()
+ # try:
+ # return {"aggregation_algorithm": ref.intra_extension["aggregation_algorithm"]}
+ # except KeyError:
+ # return ""
+ #
+ # def set_aggregation_algorithm_id(self, intra_extension_id, aggregation_algorithm_id):
+ # with self.get_session_for_write() as session:
+ # query = session.query(IntraExtension)
+ # query = query.filter_by(id=intra_extension_id)
+ # ref = query.first()
+ # intra_extension_dict = dict(ref.intra_extension)
+ # intra_extension_dict["aggregation_algorithm"] = aggregation_algorithm_id
+ # setattr(ref, "intra_extension", intra_extension_dict)
+ # # session.flush()
+ # return {"aggregation_algorithm": ref.intra_extension["aggregation_algorithm"]}
+ #
+ # def del_aggregation_algorithm(self, intra_extension_id):
+ # with self.get_session_for_write() as session:
+ # query = session.query(IntraExtension)
+ # query = query.filter_by(id=intra_extension_id)
+ # ref = query.first()
+ # intra_extension_dict = dict(ref.intra_extension)
+ # intra_extension_dict["aggregation_algorithm"] = ""
+ # setattr(ref, "intra_extension", intra_extension_dict)
+ # return self.get_aggregation_algorithm_id(intra_extension_id)
+ #
+ # # Getter and Setter for sub_meta_rule
+ #
+ # def get_sub_meta_rules_dict(self, intra_extension_id):
+ # with self.get_session_for_read() as session:
+ # query = session.query(SubMetaRule)
+ # query = query.filter_by(intra_extension_id=intra_extension_id)
+ # ref_list = query.all()
+ # return {_ref.id: _ref.sub_meta_rule for _ref in ref_list}
+ #
+ # def set_sub_meta_rule_dict(self, intra_extension_id, sub_meta_rule_id, sub_meta_rule_dict):
+ # with self.get_session_for_write() as session:
+ # query = session.query(SubMetaRule)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, id=sub_meta_rule_id)
+ # ref = query.first()
+ # new_ref = SubMetaRule.from_dict(
+ # {
+ # "id": sub_meta_rule_id,
+ # 'sub_meta_rule': sub_meta_rule_dict,
+ # 'intra_extension_id': intra_extension_id
+ # }
+ # )
+ # if not ref:
+ # session.add(new_ref)
+ # else:
+ # _sub_meta_rule_dict = dict(ref.sub_meta_rule)
+ # _sub_meta_rule_dict.update(sub_meta_rule_dict)
+ # setattr(new_ref, "sub_meta_rule", _sub_meta_rule_dict)
+ # for attr in SubMetaRule.attributes:
+ # if attr != 'id':
+ # setattr(ref, attr, getattr(new_ref, attr))
+ # # session.flush()
+ # return self.get_sub_meta_rules_dict(intra_extension_id)
+ #
+ # def del_sub_meta_rule(self, intra_extension_id, sub_meta_rule_id):
+ # with self.get_session_for_write() as session:
+ # query = session.query(SubMetaRule)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, id=sub_meta_rule_id)
+ # ref = query.first()
+ # session.delete(ref)
+ #
+ # # Getter and Setter for rules
+ #
+ # def get_rules_dict(self, intra_extension_id, sub_meta_rule_id):
+ # with self.get_session_for_read() as session:
+ # query = session.query(Rule)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, sub_meta_rule_id=sub_meta_rule_id)
+ # ref_list = query.all()
+ # return {_ref.id: _ref.rule for _ref in ref_list}
+ #
+ # def set_rule_dict(self, intra_extension_id, sub_meta_rule_id, rule_id, rule_list):
+ # with self.get_session_for_write() as session:
+ # query = session.query(Rule)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, sub_meta_rule_id=sub_meta_rule_id, id=rule_id)
+ # ref = query.first()
+ # new_ref = Rule.from_dict(
+ # {
+ # "id": rule_id,
+ # 'rule': rule_list,
+ # 'intra_extension_id': intra_extension_id,
+ # 'sub_meta_rule_id': sub_meta_rule_id
+ # }
+ # )
+ # if not ref:
+ # session.add(new_ref)
+ # ref = new_ref
+ # else:
+ # for attr in Rule.attributes:
+ # if attr != 'id':
+ # setattr(ref, attr, getattr(new_ref, attr))
+ # # session.flush()
+ # return {rule_id: ref.rule}
+ #
+ # def del_rule(self, intra_extension_id, sub_meta_rule_id, rule_id):
+ # with self.get_session_for_write() as session:
+ # query = session.query(Rule)
+ # query = query.filter_by(intra_extension_id=intra_extension_id, sub_meta_rule_id=sub_meta_rule_id, id=rule_id)
+ # ref = query.first()
+ # session.delete(ref)
+
+
+class SQLConnector(PDPConnector, PolicyConnector, ModelConnector):
+ pass
diff --git a/old/python_moondb/python_moondb/core.py b/old/python_moondb/python_moondb/core.py
new file mode 100644
index 00000000..3fee146b
--- /dev/null
+++ b/old/python_moondb/python_moondb/core.py
@@ -0,0 +1,228 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import logging
+from stevedore.driver import DriverManager
+from python_moonutilities import configuration
+from python_moondb.api import model, policy, pdp, keystone
+
+logger = logging.getLogger("moon.db")
+
+
+class Driver(DriverManager):
+
+ def __init__(self, driver_name, engine_name):
+ logger.info("initialization of Driver {}".format(driver_name))
+ super(Driver, self).__init__(
+ namespace='moon_db.driver',
+ name=driver_name,
+ invoke_on_load=True,
+ invoke_args=(engine_name,),
+ )
+
+
+class ModelDriver(Driver):
+
+ def __init__(self, driver_name, engine_name):
+ super(ModelDriver, self).__init__(driver_name, engine_name)
+
+ def update_model(self, model_id, value):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_model(self, model_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def add_model(self, model_id=None, value=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_models(self, model_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def set_meta_rule(self, meta_rule_id, value):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_meta_rules(self, meta_rule_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_meta_rule(self, meta_rule_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_subject_categories(self, category_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def add_subject_category(self, name, description):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_subject_category(self, category_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_object_categories(self, category_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def add_object_category(self, category_id, value):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_object_category(self, category_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_action_categories(self, category_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def add_action_category(self, category_id, value):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_action_category(self, category_id):
+ raise NotImplementedError() # pragma: no cover
+
+
+class PolicyDriver(Driver):
+
+ def __init__(self, driver_name, engine_name):
+ super(PolicyDriver, self).__init__(driver_name, engine_name)
+
+ def update_policy(self, policy_id, value):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_policy(self, policy_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def add_policy(self, policy_id=None, value=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_policies(self, policy_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_subjects(self, policy_id, perimeter_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def set_subject(self, policy_id, perimeter_id=None, value=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_subject(self, policy_id, perimeter_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_objects(self, policy_id, perimeter_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def set_object(self, policy_id, perimeter_id=None, value=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_object(self, policy_id, perimeter_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_actions(self, policy_id, perimeter_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def set_action(self, policy_id, perimeter_id=None, value=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_action(self, policy_id, perimeter_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_subject_data(self, policy_id, data_id=None, category_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def set_subject_data(self, policy_id, data_id=None, category_id=None, value=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_subject_data(self, policy_id, data_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_object_data(self, policy_id, data_id=None, category_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def set_object_data(self, policy_id, data_id=None, category_id=None, value=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_object_data(self, policy_id, data_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_action_data(self, policy_id, data_id=None, category_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def set_action_data(self, policy_id, data_id=None, category_id=None, value=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_action_data(self, policy_id, data_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_subject_assignments(self, policy_id, subject_id=None, category_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def add_subject_assignment(self, policy_id, subject_id, category_id, data_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_subject_assignment(self, policy_id, subject_id, category_id, data_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_object_assignments(self, policy_id, assignment_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def add_object_assignment(self, policy_id, subject_id, category_id, data_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_object_assignment(self, policy_id, object_id, category_id, data_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_action_assignments(self, policy_id, assignment_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def add_action_assignment(self, policy_id, action_id, category_id, data_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_action_assignment(self, policy_id, action_id, category_id, data_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_rules(self, policy_id, rule_id=None, meta_rule_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def add_rule(self, policy_id, meta_rule_id, value):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_rule(self, policy_id, rule_id):
+ raise NotImplementedError() # pragma: no cover
+
+
+class PDPDriver(Driver):
+
+ def __init__(self, driver_name, engine_name):
+ super(PDPDriver, self).__init__(driver_name, engine_name)
+
+ def update_pdp(self, pdp_id, value):
+ raise NotImplementedError() # pragma: no cover
+
+ def delete_pdp(self, pdp_id):
+ raise NotImplementedError() # pragma: no cover
+
+ def add_pdp(self, pdp_id=None, value=None):
+ raise NotImplementedError() # pragma: no cover
+
+ def get_pdp(self, pdp_id=None):
+ raise NotImplementedError() # pragma: no cover
+
+
+class KeystoneDriver(Driver):
+
+ def __init__(self, driver_name, engine_name):
+ super(KeystoneDriver, self).__init__(driver_name, engine_name)
+
+
+conf = configuration.get_configuration("database")['database']
+
+KeystoneManager = keystone.KeystoneManager(
+ KeystoneDriver(conf['driver'], conf['url'])
+)
+
+ModelManager = model.ModelManager(
+ ModelDriver(conf['driver'], conf['url'])
+)
+
+PolicyManager = policy.PolicyManager(
+ PolicyDriver(conf['driver'], conf['url'])
+)
+
+PDPManager = pdp.PDPManager(
+ PDPDriver(conf['driver'], conf['url'])
+)
diff --git a/old/python_moondb/python_moondb/db_manager.py b/old/python_moondb/python_moondb/db_manager.py
new file mode 100644
index 00000000..c251afbb
--- /dev/null
+++ b/old/python_moondb/python_moondb/db_manager.py
@@ -0,0 +1,82 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+"""
+"""
+
+import os
+import glob
+import importlib
+import argparse
+import logging
+from sqlalchemy import create_engine
+from python_moonutilities import configuration
+from python_moondb.migrate_repo import versions
+
+
+def init_args():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('command', help='command (upgrade or downgrade)',
+ nargs=1)
+ parser.add_argument("--verbose", "-v", action='store_true',
+ help="verbose mode")
+ parser.add_argument("--debug", "-d", action='store_true',
+ help="debug mode")
+ args = parser.parse_args()
+
+ FORMAT = '%(asctime)-15s %(levelname)s %(message)s'
+ if args.debug:
+ logging.basicConfig(
+ format=FORMAT,
+ level=logging.DEBUG)
+ elif args.verbose:
+ logging.basicConfig(
+ format=FORMAT,
+ level=logging.INFO)
+ else:
+ logging.basicConfig(
+ format=FORMAT,
+ level=logging.WARNING)
+
+ requests_log = logging.getLogger("requests.packages.urllib3")
+ requests_log.setLevel(logging.WARNING)
+ requests_log.propagate = True
+
+ logger = logging.getLogger("moon.db.manager")
+ return args, logger
+
+
+def init_engine():
+ db_conf = configuration.get_configuration("database")["database"]
+ return create_engine(db_conf['url'])
+
+
+def main(command, logger, engine):
+ files = glob.glob(versions.__path__[0] + "/[0-9][0-9][0-9]*.py")
+ for filename in files:
+ filename = os.path.basename(filename).replace(".py", "")
+ o = importlib.import_module(
+ "python_moondb.migrate_repo.versions.{}".format(filename))
+ logger.info("Command is {}".format(command))
+ if command in ("upgrade", "u", "up"):
+ logger.info(
+ "upgrading python_moondb.migrate_repo.versions.{}".format(filename))
+ o.upgrade(engine)
+ elif command in ("downgrade", "d", "down"):
+ logger.info(
+ "downgrading python_moondb.migrate_repo.versions.{}".format(
+ filename))
+ o.downgrade(engine)
+ else:
+ logger.critical("Cannot understand the command!")
+
+
+def run():
+ args, logger = init_args()
+ engine = init_engine()
+ main(args.command[0], logger, engine)
+
+
+if __name__ == "__main__":
+ run()
diff --git a/old/python_moondb/python_moondb/migrate_repo/__init__.py b/old/python_moondb/python_moondb/migrate_repo/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/python_moondb/python_moondb/migrate_repo/__init__.py
diff --git a/old/python_moondb/python_moondb/migrate_repo/versions/001_moon.py b/old/python_moondb/python_moondb/migrate_repo/versions/001_moon.py
new file mode 100644
index 00000000..13670b91
--- /dev/null
+++ b/old/python_moondb/python_moondb/migrate_repo/versions/001_moon.py
@@ -0,0 +1,267 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import json
+import sqlalchemy as sql
+from sqlalchemy import types as sql_types
+
+
+class JsonBlob(sql_types.TypeDecorator):
+ impl = sql.Text
+
+ def process_bind_param(self, value, dialect):
+ return json.dumps(value)
+
+ def process_result_value(self, value, dialect):
+ return json.loads(value)
+
+
+def upgrade(migrate_engine):
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ table = sql.Table(
+ 'pdp',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('name', sql.String(256), nullable=False),
+ sql.Column('keystone_project_id', sql.String(64), nullable=True, default=""),
+ sql.Column('value', JsonBlob(), nullable=True),
+ sql.UniqueConstraint('name', 'keystone_project_id', name='unique_constraint_models'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ table.create(migrate_engine, checkfirst=True)
+
+ table = sql.Table(
+ 'policies',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('name', sql.String(256), nullable=False),
+ sql.Column('model_id', sql.String(64), nullable=True, default=""),
+ sql.Column('value', JsonBlob(), nullable=True),
+ sql.UniqueConstraint('name', 'model_id', name='unique_constraint_models'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ table.create(migrate_engine, checkfirst=True)
+
+ table = sql.Table(
+ 'models',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('name', sql.String(256), nullable=False),
+ sql.Column('value', JsonBlob(), nullable=True),
+ sql.UniqueConstraint('name', name='unique_constraint_models'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ table.create(migrate_engine, checkfirst=True)
+
+ subject_categories_table = sql.Table(
+ 'subject_categories',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('name', sql.String(256), nullable=False),
+ sql.Column('description', sql.String(256), nullable=True),
+
+ sql.UniqueConstraint('name', name='unique_constraint_subject_categories'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ subject_categories_table.create(migrate_engine, checkfirst=True)
+
+ object_categories_table = sql.Table(
+ 'object_categories',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('name', sql.String(256), nullable=False),
+ sql.Column('description', sql.String(256), nullable=True),
+
+ sql.UniqueConstraint('name', name='unique_constraint_object_categories'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ object_categories_table.create(migrate_engine, checkfirst=True)
+
+ action_categories_table = sql.Table(
+ 'action_categories',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('name', sql.String(256), nullable=False),
+ sql.Column('description', sql.String(256), nullable=True),
+
+ sql.UniqueConstraint('name', name='unique_constraint_action_categories'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ action_categories_table.create(migrate_engine, checkfirst=True)
+
+ subjects_table = sql.Table(
+ 'subjects',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('name', sql.String(256), nullable=False),
+ sql.Column('value', JsonBlob(), nullable=True),
+ sql.UniqueConstraint('name', name='unique_constraint_subjects'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ subjects_table.create(migrate_engine, checkfirst=True)
+
+ objects_table = sql.Table(
+ 'objects',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('name', sql.String(256), nullable=False),
+ sql.Column('value', JsonBlob(), nullable=True),
+ sql.UniqueConstraint('name', name='unique_constraint_objects'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ objects_table.create(migrate_engine, checkfirst=True)
+
+ actions_table = sql.Table(
+ 'actions',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('name', sql.String(256), nullable=False),
+ sql.Column('value', JsonBlob(), nullable=True),
+ sql.UniqueConstraint('name', name='unique_constraint_actions'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ actions_table.create(migrate_engine, checkfirst=True)
+
+ subject_data_table = sql.Table(
+ 'subject_data',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('name', sql.String(256), nullable=False),
+ sql.Column('value', JsonBlob(), nullable=True),
+ sql.Column('category_id', sql.ForeignKey("subject_categories.id"), nullable=False),
+ sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False),
+ sql.UniqueConstraint('name', 'category_id', 'policy_id',
+ name='unique_constraint_subject_data'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ subject_data_table.create(migrate_engine, checkfirst=True)
+
+ object_data_table = sql.Table(
+ 'object_data',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('name', sql.String(256), nullable=False),
+ sql.Column('value', JsonBlob(), nullable=True),
+ sql.Column('category_id', sql.ForeignKey("object_categories.id"), nullable=False),
+ sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False),
+ sql.UniqueConstraint('name', 'category_id', 'policy_id',
+ name='unique_constraint_object_data'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ object_data_table.create(migrate_engine, checkfirst=True)
+
+ action_data_table = sql.Table(
+ 'action_data',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('name', sql.String(256), nullable=False),
+ sql.Column('value', JsonBlob(), nullable=True),
+ sql.Column('category_id', sql.ForeignKey("action_categories.id"), nullable=False),
+ sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False),
+ sql.UniqueConstraint('name', 'category_id', 'policy_id',
+ name='unique_constraint_action_data'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ action_data_table.create(migrate_engine, checkfirst=True)
+
+ subject_assignments_table = sql.Table(
+ 'subject_assignments',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('assignments', sql.String(256), nullable=True),
+ sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False),
+ sql.Column('subject_id', sql.ForeignKey("subjects.id"), nullable=False),
+ sql.Column('category_id', sql.ForeignKey("subject_categories.id"), nullable=False),
+ sql.UniqueConstraint('policy_id', 'subject_id', 'category_id',
+ name='unique_constraint_subject_assignment'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ subject_assignments_table.create(migrate_engine, checkfirst=True)
+
+ object_assignments_table = sql.Table(
+ 'object_assignments',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('assignments', sql.String(256), nullable=True),
+ sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False),
+ sql.Column('object_id', sql.ForeignKey("objects.id"), nullable=False),
+ sql.Column('category_id', sql.ForeignKey("object_categories.id"), nullable=False),
+ sql.UniqueConstraint('policy_id', 'object_id', 'category_id',
+ name='unique_constraint_object_assignment'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ object_assignments_table.create(migrate_engine, checkfirst=True)
+
+ action_assignments_table = sql.Table(
+ 'action_assignments',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('assignments', sql.String(256), nullable=True),
+ sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False),
+ sql.Column('action_id', sql.ForeignKey("actions.id"), nullable=False),
+ sql.Column('category_id', sql.ForeignKey("action_categories.id"), nullable=False),
+ sql.UniqueConstraint('policy_id', 'action_id', 'category_id',
+ name='unique_constraint_action_assignment'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ action_assignments_table.create(migrate_engine, checkfirst=True)
+
+ meta_rules_table = sql.Table(
+ 'meta_rules',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('name', sql.String(256), nullable=False),
+ sql.Column('subject_categories', JsonBlob(), nullable=False),
+ sql.Column('object_categories', JsonBlob(), nullable=False),
+ sql.Column('action_categories', JsonBlob(), nullable=False),
+ sql.Column('value', JsonBlob(), nullable=True),
+ sql.UniqueConstraint('name', name='unique_constraint_meta_rule_name'),
+ # sql.UniqueConstraint('subject_categories', 'object_categories', 'action_categories', name='unique_constraint_meta_rule_def'),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ meta_rules_table.create(migrate_engine, checkfirst=True)
+
+ rules_table = sql.Table(
+ 'rules',
+ meta,
+ sql.Column('id', sql.String(64), primary_key=True),
+ sql.Column('rule', JsonBlob(), nullable=True),
+ sql.Column('policy_id', sql.ForeignKey("policies.id"), nullable=False),
+ sql.Column('meta_rule_id', sql.ForeignKey("meta_rules.id"), nullable=False),
+ mysql_engine='InnoDB',
+ mysql_charset='utf8')
+ rules_table.create(migrate_engine, checkfirst=True)
+
+
+def downgrade(migrate_engine):
+ meta = sql.MetaData()
+ meta.bind = migrate_engine
+
+ for _table in (
+ 'rules',
+ 'meta_rules',
+ 'action_assignments',
+ 'object_assignments',
+ 'subject_assignments',
+ 'action_data',
+ 'object_data',
+ 'subject_data',
+ 'actions',
+ 'objects',
+ 'subjects',
+ 'action_categories',
+ 'object_categories',
+ 'subject_categories',
+ 'models',
+ 'policies',
+ 'pdp'
+ ):
+ try:
+ table = sql.Table(_table, meta, autoload=True)
+ table.drop(migrate_engine, checkfirst=True)
+ except Exception as e:
+ print(e)
diff --git a/old/python_moondb/python_moondb/migrate_repo/versions/__init__.py b/old/python_moondb/python_moondb/migrate_repo/versions/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/python_moondb/python_moondb/migrate_repo/versions/__init__.py
diff --git a/old/python_moondb/requirements.txt b/old/python_moondb/requirements.txt
new file mode 100644
index 00000000..a205666f
--- /dev/null
+++ b/old/python_moondb/requirements.txt
@@ -0,0 +1,4 @@
+stevedore
+sqlalchemy
+pymysql
+requests
diff --git a/old/python_moondb/setup.py b/old/python_moondb/setup.py
new file mode 100644
index 00000000..e34369d4
--- /dev/null
+++ b/old/python_moondb/setup.py
@@ -0,0 +1,54 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from setuptools import setup, find_packages
+import python_moondb
+
+
+with open('requirements.txt') as f:
+ required = f.read().splitlines()
+
+setup(
+
+ name='python-moondb',
+
+ version=python_moondb.__version__,
+
+ packages=find_packages(),
+
+ author="Thomas Duval",
+
+ author_email="thomas.duval@orange.com",
+
+ description="This library is a helper to interact with the Moon database.",
+
+ long_description=open('README.md').read(),
+
+ install_requires=required,
+
+ include_package_data=True,
+
+ url='https://git.opnfv.org/cgit/moon/',
+
+ classifiers=[
+ "Programming Language :: Python",
+ "Development Status :: 1 - Planning",
+ "License :: OSI Approved",
+ "Natural Language :: English",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python :: 3",
+ ],
+
+ entry_points={
+ "moon_db.driver":
+ [
+ "sql = python_moondb.backends.sql:SQLConnector",
+ ],
+ 'console_scripts': [
+ 'moon_db_manager = python_moondb.db_manager:run',
+ ],
+ }
+
+)
diff --git a/old/python_moondb/tests/unit_python/conftest.py b/old/python_moondb/tests/unit_python/conftest.py
new file mode 100644
index 00000000..a1057907
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/conftest.py
@@ -0,0 +1,145 @@
+import base64
+import json
+import logging
+import os
+import pytest
+import requests_mock
+import mock_components
+import mock_keystone
+
+CONF = {
+ "openstack": {
+ "keystone": {
+ "url": "http://keystone:5000/v3",
+ "user": "admin",
+ "check_token": False,
+ "password": "p4ssw0rd",
+ "domain": "default",
+ "certificate": False,
+ "project": "admin"
+ }
+ },
+ "components": {
+ "wrapper": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_wrapper:v4.3",
+ "timeout": 5,
+ "hostname": "wrapper"
+ },
+ "manager": {
+ "bind": "0.0.0.0",
+ "port": 8082,
+ "container": "wukongsun/moon_manager:v4.3",
+ "hostname": "manager"
+ },
+ "port_start": 31001,
+ "orchestrator": {
+ "bind": "0.0.0.0",
+ "port": 8083,
+ "container": "wukongsun/moon_orchestrator:v4.3",
+ "hostname": "interface"
+ },
+ "interface": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_interface:v4.3",
+ "hostname": "interface"
+ }
+ },
+ "plugins": {
+ "session": {
+ "port": 8082,
+ "container": "asteroide/session:latest"
+ },
+ "authz": {
+ "port": 8081,
+ "container": "wukongsun/moon_authz:v4.3"
+ }
+ },
+ "logging": {
+ "handlers": {
+ "file": {
+ "filename": "/tmp/moon.log",
+ "class": "logging.handlers.RotatingFileHandler",
+ "level": "DEBUG",
+ "formatter": "custom",
+ "backupCount": 3,
+ "maxBytes": 1048576
+ },
+ "console": {
+ "class": "logging.StreamHandler",
+ "formatter": "brief",
+ "level": "INFO",
+ "stream": "ext://sys.stdout"
+ }
+ },
+ "formatters": {
+ "brief": {
+ "format": "%(levelname)s %(name)s %(message)-30s"
+ },
+ "custom": {
+ "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s"
+ }
+ },
+ "root": {
+ "handlers": [
+ "console"
+ ],
+ "level": "ERROR"
+ },
+ "version": 1,
+ "loggers": {
+ "moon": {
+ "handlers": [
+ "console",
+ "file"
+ ],
+ "propagate": False,
+ "level": "DEBUG"
+ }
+ }
+ },
+ "slave": {
+ "name": None,
+ "master": {
+ "url": None,
+ "login": None,
+ "password": None
+ }
+ },
+ "docker": {
+ "url": "tcp://172.88.88.1:2376",
+ "network": "moon"
+ },
+ "database": {
+ "url": "sqlite:///database.db",
+ # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon",
+ "driver": "sql"
+ },
+ "messenger": {
+ "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon"
+ }
+}
+
+
+@pytest.fixture
+def db():
+ return CONF['database']
+
+
+@pytest.fixture(autouse=True)
+def set_consul_and_db(monkeypatch):
+ """ Modify the response from Requests module
+ """
+ with requests_mock.Mocker(real_http=True) as m:
+ mock_components.register_components(m)
+ mock_keystone.register_keystone(m)
+
+ from python_moondb.db_manager import init_engine, main
+ engine = init_engine()
+ main("upgrade", logging.getLogger("db_manager"), engine)
+ yield m
+ os.unlink(CONF['database']['url'].replace("sqlite:///", ""))
+
+
diff --git a/old/python_moondb/tests/unit_python/helpers/__init__.py b/old/python_moondb/tests/unit_python/helpers/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/helpers/__init__.py
diff --git a/old/python_moondb/tests/unit_python/helpers/assignment_helper.py b/old/python_moondb/tests/unit_python/helpers/assignment_helper.py
new file mode 100644
index 00000000..22a56e38
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/helpers/assignment_helper.py
@@ -0,0 +1,49 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+def get_action_assignments(policy_id, action_id=None, category_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_action_assignments("", policy_id, action_id, category_id)
+
+
+def add_action_assignment(policy_id, action_id, category_id, data_id):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_action_assignment("", policy_id, action_id, category_id, data_id)
+
+
+def delete_action_assignment(policy_id, action_id, category_id, data_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_action_assignment("", policy_id, action_id, category_id, data_id)
+
+
+def get_object_assignments(policy_id, object_id=None, category_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_object_assignments("", policy_id, object_id, category_id)
+
+
+def add_object_assignment(policy_id, object_id, category_id, data_id):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_object_assignment("", policy_id, object_id, category_id, data_id)
+
+
+def delete_object_assignment(policy_id, object_id, category_id, data_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_object_assignment("", policy_id, object_id, category_id, data_id)
+
+
+def get_subject_assignments(policy_id, subject_id=None, category_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_subject_assignments("", policy_id, subject_id, category_id)
+
+
+def add_subject_assignment(policy_id, subject_id, category_id, data_id):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_subject_assignment("", policy_id, subject_id, category_id, data_id)
+
+
+def delete_subject_assignment(policy_id, subject_id, category_id, data_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_subject_assignment("", policy_id, subject_id, category_id, data_id)
+
diff --git a/old/python_moondb/tests/unit_python/helpers/category_helper.py b/old/python_moondb/tests/unit_python/helpers/category_helper.py
new file mode 100644
index 00000000..55e95d91
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/helpers/category_helper.py
@@ -0,0 +1,54 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+def add_subject_category(cat_id=None, value=None):
+ from python_moondb.core import ModelManager
+ category = ModelManager.add_subject_category(user_id=None, category_id=cat_id, value=value)
+ return category
+
+
+def get_subject_category(cat_id=None):
+ from python_moondb.core import ModelManager
+ category = ModelManager.get_subject_categories(user_id=None, category_id=cat_id)
+ return category
+
+
+def add_object_category(cat_id=None, value=None):
+ from python_moondb.core import ModelManager
+ category = ModelManager.add_object_category(user_id=None, category_id=cat_id, value=value)
+ return category
+
+
+def get_object_category(cat_id=None):
+ from python_moondb.core import ModelManager
+ category = ModelManager.get_object_categories(user_id=None, category_id=cat_id)
+ return category
+
+
+def add_action_category(cat_id=None, value=None):
+ from python_moondb.core import ModelManager
+ category = ModelManager.add_action_category(user_id=None, category_id=cat_id, value=value)
+ return category
+
+
+def get_action_category(cat_id=None):
+ from python_moondb.core import ModelManager
+ category = ModelManager.get_action_categories(user_id=None, category_id=cat_id)
+ return category
+
+
+def delete_subject_category(category_id=None):
+ from python_moondb.core import ModelManager
+ return ModelManager.delete_subject_category("", category_id=category_id)
+
+
+def delete_object_category(category_id=None):
+ from python_moondb.core import ModelManager
+ return ModelManager.delete_object_category("", category_id=category_id)
+
+
+def delete_action_category(category_id=None):
+ from python_moondb.core import ModelManager
+ return ModelManager.delete_action_category("", category_id=category_id)
diff --git a/old/python_moondb/tests/unit_python/helpers/data_helper.py b/old/python_moondb/tests/unit_python/helpers/data_helper.py
new file mode 100644
index 00000000..8a8238f5
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/helpers/data_helper.py
@@ -0,0 +1,98 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+def get_action_data(policy_id, data_id=None, category_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_action_data("", policy_id, data_id, category_id)
+
+
+def add_action_data(policy_id, data_id=None, category_id=None, value=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_action_data("", policy_id, data_id, category_id, value)
+
+
+def delete_action_data(policy_id, data_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_action_data("",policy_id=policy_id, data_id=data_id)
+
+
+def get_object_data(policy_id, data_id=None, category_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_object_data("", policy_id, data_id, category_id)
+
+
+def add_object_data(policy_id, data_id=None, category_id=None, value=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_object_data("", policy_id, data_id, category_id, value)
+
+
+def delete_object_data(policy_id, data_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_object_data("", policy_id=policy_id, data_id=data_id)
+
+
+def get_subject_data(policy_id, data_id=None, category_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_subject_data("", policy_id, data_id, category_id)
+
+
+def add_subject_data(policy_id, data_id=None, category_id=None, value=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.set_subject_data("", policy_id, data_id, category_id, value)
+
+
+def delete_subject_data(policy_id, data_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_subject_data("", policy_id=policy_id, data_id=data_id)
+
+
+def get_actions(policy_id, perimeter_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_actions("", policy_id, perimeter_id)
+
+
+def add_action(policy_id, perimeter_id=None, value=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_action("", policy_id, perimeter_id, value)
+
+
+def delete_action(policy_id, perimeter_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_action("", policy_id, perimeter_id)
+
+
+def get_objects(policy_id, perimeter_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_objects("", policy_id, perimeter_id)
+
+
+def add_object(policy_id, perimeter_id=None, value=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_object("", policy_id, perimeter_id, value)
+
+
+def delete_object(policy_id, perimeter_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_object("", policy_id, perimeter_id)
+
+
+def get_subjects(policy_id, perimeter_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_subjects("", policy_id, perimeter_id)
+
+
+def add_subject(policy_id, perimeter_id=None, value=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.add_subject("", policy_id, perimeter_id, value)
+
+
+def delete_subject(policy_id, perimeter_id):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_subject("", policy_id, perimeter_id)
+
+
+def get_available_metadata(policy_id):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_available_metadata("", policy_id)
diff --git a/old/python_moondb/tests/unit_python/helpers/meta_rule_helper.py b/old/python_moondb/tests/unit_python/helpers/meta_rule_helper.py
new file mode 100644
index 00000000..87af250a
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/helpers/meta_rule_helper.py
@@ -0,0 +1,48 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from helpers import mock_data
+
+
+def update_meta_rule(meta_rule_id, value=None):
+ from python_moondb.core import ModelManager
+ if not value:
+ action_category_id = mock_data.create_action_category("action_category_id1")
+ subject_category_id = mock_data.create_subject_category("subject_category_id1")
+ object_category_id = mock_data.create_object_category("object_category_id1")
+ value = {
+ "name": "MLS_meta_rule",
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ return ModelManager.update_meta_rule(user_id=None, meta_rule_id=meta_rule_id, value=value)
+
+
+def add_meta_rule(meta_rule_id=None, value=None):
+ from python_moondb.core import ModelManager
+ if not value:
+ action_category_id = mock_data.create_action_category("action_category_id1")
+ subject_category_id = mock_data.create_subject_category("subject_category_id1")
+ object_category_id = mock_data.create_object_category("object_category_id1")
+ value = {
+ "name": "MLS_meta_rule",
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ return ModelManager.add_meta_rule(user_id=None, meta_rule_id=meta_rule_id, value=value)
+
+
+def get_meta_rules(meta_rule_id=None):
+ from python_moondb.core import ModelManager
+ return ModelManager.get_meta_rules(user_id=None, meta_rule_id=meta_rule_id)
+
+
+def delete_meta_rules(meta_rule_id=None):
+ from python_moondb.core import ModelManager
+ ModelManager.delete_meta_rule(user_id=None, meta_rule_id=meta_rule_id)
diff --git a/old/python_moondb/tests/unit_python/helpers/mock_data.py b/old/python_moondb/tests/unit_python/helpers/mock_data.py
new file mode 100644
index 00000000..0d65ea02
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/helpers/mock_data.py
@@ -0,0 +1,156 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from .category_helper import *
+from .policy_helper import *
+from .data_helper import *
+from .model_helper import *
+from .meta_rule_helper import *
+from uuid import uuid4
+
+
+def create_subject_category(name):
+ subject_category = add_subject_category(
+ value={"name": name, "description": "description 1"})
+ return list(subject_category.keys())[0]
+
+
+def create_object_category(name):
+ object_category = add_object_category(
+ value={"name": name, "description": "description 1"})
+ return list(object_category.keys())[0]
+
+
+def create_action_category(name):
+ action_category = add_action_category(
+ value={"name": name, "description": "description 1"})
+ return list(action_category.keys())[0]
+
+
+def create_model(meta_rule_id, model_name="test_model"):
+ value = {
+ "name": model_name,
+ "description": "test",
+ "meta_rules": [meta_rule_id]
+
+ }
+ return value
+
+
+def create_policy(model_id, policy_name="policy_1"):
+ value = {
+ "name": policy_name,
+ "model_id": model_id,
+ "genre": "authz",
+ "description": "test",
+ }
+ return value
+
+
+def create_pdp(policies_ids):
+ value = {
+ "name": "test_pdp",
+ "security_pipeline": policies_ids,
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+ return value
+
+
+def create_new_policy(subject_category_name="subjectCategory", object_category_name="objectCategory",
+ action_category_name="actionCategory",
+ model_name="test_model", policy_name="policy_name",
+ meta_rule_name="meta_rule_"):
+ if policy_name == "policy_name":
+ policy_name = "policy_name_" + uuid4().hex
+
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = create_new_meta_rule(
+ subject_category_name=subject_category_name + uuid4().hex,
+ object_category_name=object_category_name + uuid4().hex,
+ action_category_name=action_category_name + uuid4().hex,
+ meta_rule_name=meta_rule_name + uuid4().hex
+ )
+ model = add_model(value=create_model(meta_rule_id, model_name))
+ model_id = list(model.keys())[0]
+ value = create_policy(model_id, policy_name)
+ policy = add_policies(value=value)
+ assert policy
+ policy_id = list(policy.keys())[0]
+ return subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id
+
+
+def create_new_meta_rule(subject_category_name="subject_category" + uuid4().hex,
+ object_category_name="object_category" + uuid4().hex,
+ action_category_name="action_category" + uuid4().hex,
+ meta_rule_name="meta_rule" + uuid4().hex):
+ from python_moondb.core import ModelManager
+
+ subject_category_id = create_subject_category(subject_category_name)
+ object_category_id = create_object_category(object_category_name)
+ action_category_id = create_action_category(action_category_name)
+ value = {"name": meta_rule_name,
+ "algorithm": "name of the meta rule algorithm",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ # meta_rule = add_meta_rule(value=value)
+ meta_rule = ModelManager.add_meta_rule(user_id=None, meta_rule_id=None, value=value)
+ return subject_category_id, object_category_id, action_category_id, list(meta_rule.keys())[0]
+
+
+def create_subject(policy_id):
+ value = {
+ "name": "testuser",
+ "description": "test",
+ }
+ subject = add_subject(policy_id=policy_id, value=value)
+ return list(subject.keys())[0]
+
+
+def create_object(policy_id):
+ value = {
+ "name": "testobject",
+ "description": "test",
+ }
+ object = add_object(policy_id=policy_id, value=value)
+ return list(object.keys())[0]
+
+
+def create_action(policy_id):
+ value = {
+ "name": "testaction",
+ "description": "test",
+ }
+ action = add_action(policy_id=policy_id, value=value)
+ return list(action.keys())[0]
+
+
+def create_subject_data(policy_id, category_id):
+ value = {
+ "name": uuid4().hex,
+ "description": {uuid4().hex: "", uuid4().hex: "", uuid4().hex: ""},
+ }
+ subject_data = add_subject_data(policy_id=policy_id, category_id=category_id, value=value).get('data')
+ assert subject_data
+ return list(subject_data.keys())[0]
+
+
+def create_object_data(policy_id, category_id):
+ value = {
+ "name": uuid4().hex,
+ "description": {uuid4().hex: "", uuid4().hex: "", uuid4().hex: ""},
+ }
+ object_data = add_object_data(policy_id=policy_id, category_id=category_id, value=value).get('data')
+ return list(object_data.keys())[0]
+
+
+def create_action_data(policy_id, category_id):
+ value = {
+ "name": uuid4().hex,
+ "description": {uuid4().hex: "", uuid4().hex: "", uuid4().hex: ""},
+ }
+ action_data = add_action_data(policy_id=policy_id, category_id=category_id, value=value).get('data')
+ return list(action_data.keys())[0]
diff --git a/old/python_moondb/tests/unit_python/helpers/model_helper.py b/old/python_moondb/tests/unit_python/helpers/model_helper.py
new file mode 100644
index 00000000..98a6271d
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/helpers/model_helper.py
@@ -0,0 +1,47 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from helpers import mock_data
+from uuid import uuid4
+
+def get_models(model_id=None):
+ from python_moondb.core import ModelManager
+ return ModelManager.get_models(user_id=None, model_id=model_id)
+
+
+def add_model(model_id=None, value=None):
+ from python_moondb.core import ModelManager
+ if not value:
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = mock_data.create_new_meta_rule()
+ name = "MLS" if model_id is None else "MLS " + model_id
+ value = {
+ "name": name,
+ "description": "test",
+ "meta_rules": [meta_rule_id]
+ }
+ return ModelManager.add_model(user_id=None, model_id=model_id, value=value)
+
+
+def delete_models(uuid=None, name=None):
+ from python_moondb.core import ModelManager
+ if not uuid:
+ for model_id, model_value in get_models():
+ if name == model_value['name']:
+ uuid = model_id
+ break
+ ModelManager.delete_model(user_id=None, model_id=uuid)
+
+
+def delete_all_models():
+ from python_moondb.core import ModelManager
+ models_values = get_models()
+ print(models_values)
+ for model_id, model_value in models_values.items():
+ ModelManager.delete_model(user_id=None, model_id=model_id)
+
+
+def update_model(model_id=None, value=None):
+ from python_moondb.core import ModelManager
+ return ModelManager.update_model(user_id=None, model_id=model_id, value=value)
diff --git a/old/python_moondb/tests/unit_python/helpers/pdp_helper.py b/old/python_moondb/tests/unit_python/helpers/pdp_helper.py
new file mode 100644
index 00000000..3d169b06
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/helpers/pdp_helper.py
@@ -0,0 +1,23 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+def update_pdp(pdp_id, value):
+ from python_moondb.core import PDPManager
+ return PDPManager.update_pdp("", pdp_id, value)
+
+
+def delete_pdp(pdp_id):
+ from python_moondb.core import PDPManager
+ PDPManager.delete_pdp("", pdp_id)
+
+
+def add_pdp(pdp_id=None, value=None):
+ from python_moondb.core import PDPManager
+ return PDPManager.add_pdp("", pdp_id, value)
+
+
+def get_pdp(pdp_id=None):
+ from python_moondb.core import PDPManager
+ return PDPManager.get_pdp("", pdp_id)
diff --git a/old/python_moondb/tests/unit_python/helpers/policy_helper.py b/old/python_moondb/tests/unit_python/helpers/policy_helper.py
new file mode 100644
index 00000000..93d81c62
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/helpers/policy_helper.py
@@ -0,0 +1,72 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+from helpers import mock_data as mock_data
+from helpers import meta_rule_helper
+
+def get_policies():
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_policies("admin")
+
+
+def add_policies(policy_id=None, value=None):
+ from python_moondb.core import PolicyManager
+ if not value:
+ value = {
+ "name": "test_policy",
+ "model_id": "",
+ "genre": "authz",
+ "description": "test",
+ }
+ return PolicyManager.add_policy("admin", policy_id=policy_id, value=value)
+
+
+def delete_policies(uuid=None, name=None):
+ from python_moondb.core import PolicyManager
+ if not uuid:
+ for policy_id, policy_value in get_policies():
+ if name == policy_value['name']:
+ uuid = policy_id
+ break
+ PolicyManager.delete_policy("admin", uuid)
+
+
+def update_policy(policy_id, value):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.update_policy("admin", policy_id, value)
+
+
+def get_policy_from_meta_rules(meta_rule_id):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_policy_from_meta_rules("admin", meta_rule_id)
+
+
+def get_rules(policy_id=None, meta_rule_id=None, rule_id=None):
+ from python_moondb.core import PolicyManager
+ return PolicyManager.get_rules("", policy_id, meta_rule_id, rule_id)
+
+
+def add_rule(policy_id, meta_rule_id, value=None):
+ from python_moondb.core import PolicyManager
+ if not value:
+ meta_rule = meta_rule_helper.get_meta_rules(meta_rule_id)
+ sub_cat_id = meta_rule[meta_rule_id]['subject_categories'][0]
+ ob_cat_id = meta_rule[meta_rule_id]['object_categories'][0]
+ act_cat_id = meta_rule[meta_rule_id]['action_categories'][0]
+
+ subject_data_id = mock_data.create_subject_data(policy_id=policy_id, category_id=sub_cat_id)
+ object_data_id = mock_data.create_object_data(policy_id=policy_id, category_id=ob_cat_id)
+ action_data_id = mock_data.create_action_data(policy_id=policy_id, category_id=act_cat_id)
+
+ value = {
+ "rule": (subject_data_id, object_data_id, action_data_id),
+ "instructions": ({"decision": "grant"}),
+ "enabled": "",
+ }
+ return PolicyManager.add_rule("", policy_id, meta_rule_id, value)
+
+
+def delete_rule(policy_id=None, rule_id=None):
+ from python_moondb.core import PolicyManager
+ PolicyManager.delete_rule("", policy_id, rule_id)
diff --git a/old/python_moondb/tests/unit_python/mock_components.py b/old/python_moondb/tests/unit_python/mock_components.py
new file mode 100644
index 00000000..a0319e1a
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/mock_components.py
@@ -0,0 +1,27 @@
+import utilities
+
+COMPONENTS = (
+ "logging",
+ "openstack/keystone",
+ "database",
+ "slave",
+ "components/manager",
+ "components/orchestrator",
+ "components/interface",
+)
+
+
+def register_components(m):
+ for component in COMPONENTS:
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/{}'.format(component),
+ json=[{'Key': component, 'Value': utilities.get_b64_conf(component)}]
+ )
+
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/components?recurse=true',
+ json=[
+ {"Key": key, "Value": utilities.get_b64_conf(key)} for key in COMPONENTS
+ ],
+ # json={'Key': "components", 'Value': get_b64_conf("components")}
+ ) \ No newline at end of file
diff --git a/old/python_moondb/tests/unit_python/mock_keystone.py b/old/python_moondb/tests/unit_python/mock_keystone.py
new file mode 100644
index 00000000..3f262538
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/mock_keystone.py
@@ -0,0 +1,33 @@
+def register_keystone(m):
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/auth/tokens',
+ headers={'X-Subject-Token': "111111111"}
+ )
+ m.register_uri(
+ 'DELETE', 'http://keystone:5000/v3/auth/tokens',
+ headers={'X-Subject-Token': "111111111"}
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default',
+ json={"users": {}}
+ )
+ m.register_uri(
+ 'GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default',
+ json={"users": {}}
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/users/',
+ json={"users": [{
+ "id": "1111111111111"
+ }]}
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/projects/',
+ json={
+ "description": "test_project",
+ "domain_id": ['domain_id_1'],
+ "enabled": True,
+ "is_domain": False,
+ "name": 'project_1'
+ }
+ )
diff --git a/old/python_moondb/tests/unit_python/models/__init__.py b/old/python_moondb/tests/unit_python/models/__init__.py
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/models/__init__.py
diff --git a/old/python_moondb/tests/unit_python/models/test_categories.py b/old/python_moondb/tests/unit_python/models/test_categories.py
new file mode 100644
index 00000000..39dc4c71
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/models/test_categories.py
@@ -0,0 +1,111 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import pytest
+import logging
+from python_moonutilities.exceptions import *
+from helpers import category_helper
+
+logger = logging.getLogger("moon.db.tests.models.test_categories")
+
+
+def test_add_subject_category_twice():
+ category = category_helper.add_subject_category(
+ value={"name": "category name", "description": "description 1"})
+ category_id = list(category.keys())[0]
+ assert category is not None
+ with pytest.raises(SubjectCategoryExisting):
+ category_helper.add_subject_category(category_id,
+ value={"name": "category name",
+ "description": "description 2"})
+
+
+def test_add_subject_category_name_space():
+ with pytest.raises(CategoryNameInvalid) as exp:
+ category = category_helper.add_subject_category(value={"name": " ", "description":
+ "description 1"})
+ assert exp.value.code == 400
+ assert exp.value.description == 'The given category name is invalid.'
+
+
+def test_get_subject_categories():
+ added_category = category_helper.add_subject_category(
+ value={"name": "category name", "description": "description 1"})
+ category_id = list(added_category.keys())[0]
+ subject_category = category_helper.get_subject_category(category_id)
+ assert subject_category == added_category
+
+
+def test_get_subject_categories_with_invalid_id():
+ category_id = "invalid_id"
+ subject_category = category_helper.get_subject_category(category_id)
+ assert len(subject_category) == 0
+
+
+def test_add_object_category_twice():
+ category = category_helper.add_object_category(
+ value={"name": "category name", "description": "description 1"})
+ category_id = list(category.keys())[0]
+ assert category is not None
+ with pytest.raises(ObjectCategoryExisting):
+ category_helper.add_object_category(category_id,
+ value={"name": "category name",
+ "description": "description 2"})
+
+
+def test_add_object_category_name_space():
+ with pytest.raises(CategoryNameInvalid) as exp:
+ category = category_helper.add_object_category(value={"name": " ", "description":
+ "description 1"})
+ assert exp.value.code == 400
+ assert exp.value.description == 'The given category name is invalid.'
+
+
+def test_get_object_categories():
+ added_category = category_helper.add_object_category(
+ value={"name": "category name", "description": "description 1"})
+ category_id = list(added_category.keys())[0]
+ object_category = category_helper.get_object_category(category_id)
+ assert object_category == added_category
+
+
+def test_get_object_categories_with_invalid_id():
+ category_id = "invalid_id"
+ object_category = category_helper.get_object_category(category_id)
+ assert len(object_category) == 0
+
+
+def test_add_action_category_twice():
+ category = category_helper.add_action_category(
+ value={"name": "category name", "description": "description 1"})
+ category_id = list(category.keys())[0]
+ assert category is not None
+ with pytest.raises(ActionCategoryExisting) as exp_info:
+ category_helper.add_action_category(category_id,
+ value={"name": "category name",
+ "description": "description 2"})
+ assert str(exp_info.value)=='409: Action Category Existing'
+
+
+def test_add_action_category_name_space():
+ with pytest.raises(CategoryNameInvalid) as exp:
+ category = category_helper.add_action_category(value={"name": " ", "description":
+ "description 1"})
+ assert exp.value.code == 400
+ assert exp.value.description == 'The given category name is invalid.'
+
+
+def test_get_action_categories():
+ added_category = category_helper.add_action_category(
+ value={"name": "category name", "description": "description 1"})
+ category_id = list(added_category.keys())[0]
+ action_category = category_helper.get_action_category(category_id)
+ assert action_category == added_category
+
+
+def test_get_action_categories_with_invalid_id():
+ category_id = "invalid_id"
+ action_category = category_helper.get_action_category(category_id)
+ assert len(action_category) == 0
diff --git a/old/python_moondb/tests/unit_python/models/test_meta_rules.py b/old/python_moondb/tests/unit_python/models/test_meta_rules.py
new file mode 100644
index 00000000..3b2b5b0e
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/models/test_meta_rules.py
@@ -0,0 +1,403 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import pytest
+from helpers import meta_rule_helper
+from helpers import policy_helper
+import helpers.mock_data as mock_data
+import helpers.model_helper as model_helper
+from python_moonutilities.exceptions import *
+from uuid import uuid4
+
+
+def test_update_not_exist_meta_rule_error(db):
+ # set not existing meta rule and expect to raise and error
+ with pytest.raises(MetaRuleUnknown) as exception_info:
+ meta_rule_helper.update_meta_rule(meta_rule_id=None)
+ assert str(exception_info.value) == '400: Meta Rule Unknown'
+
+
+def test_update_meta_rule_connected_with_policy_and_rule():
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ subject_data_id = mock_data.create_subject_data(policy_id=policy_id,
+ category_id=subject_category_id)
+ object_data_id = mock_data.create_object_data(policy_id=policy_id,
+ category_id=object_category_id)
+ action_data_id = mock_data.create_action_data(policy_id=policy_id,
+ category_id=action_category_id)
+
+ value = {
+ "rule": (subject_data_id, object_data_id, action_data_id),
+ "instructions": ({"decision": "grant"}),
+ "enabled": "",
+ }
+
+ rules = policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value)
+ assert rules
+ assert len(rules) == 1
+
+ action_category_id = mock_data.create_action_category("action_category_id2")
+ subject_category_id = mock_data.create_subject_category("subject_category_id2")
+ object_category_id = mock_data.create_object_category("object_category_id2")
+
+ updated_value = {
+ "name": "MLS_meta_rule",
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ with pytest.raises(MetaRuleUpdateError) as exception_info:
+ updated_meta_rule = meta_rule_helper.update_meta_rule(meta_rule_id, updated_value)
+ assert str(exception_info.value) == '400: Meta_Rule Update Error'
+
+
+def test_update_meta_rule_connected_with_policy(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ action_category_id = mock_data.create_action_category("action_category_id2")
+ subject_category_id = mock_data.create_subject_category("subject_category_id2")
+ object_category_id = mock_data.create_object_category("object_category_id2")
+ value = {
+ "name": "MLS_meta_rule",
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ meta_rules = meta_rule_helper.add_meta_rule(value=value)
+ assert isinstance(meta_rules, dict)
+ assert meta_rules
+ assert len(meta_rules) is 1
+ meta_rule_id = list(meta_rules.keys())[0]
+ for key in (
+ "name", "description", "subject_categories", "object_categories", "action_categories"):
+ assert key in meta_rules[meta_rule_id]
+ assert meta_rules[meta_rule_id][key] == value[key]
+
+
+def test_add_new_meta_rule_success(db):
+ action_category_id = mock_data.create_action_category("action_category_id1")
+ subject_category_id = mock_data.create_subject_category("subject_category_id1")
+ object_category_id = mock_data.create_object_category("object_category_id1")
+ value = {
+ "name": "MLS_meta_rule",
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ meta_rules = meta_rule_helper.add_meta_rule(value=value)
+ assert isinstance(meta_rules, dict)
+ assert meta_rules
+ assert len(meta_rules) is 1
+ meta_rule_id = list(meta_rules.keys())[0]
+ for key in (
+ "name", "description", "subject_categories", "object_categories", "action_categories"):
+ assert key in meta_rules[meta_rule_id]
+ assert meta_rules[meta_rule_id][key] == value[key]
+
+
+def test_meta_rule_with_blank_name(db):
+ action_category_id = mock_data.create_action_category(uuid4().hex)
+ subject_category_id = mock_data.create_subject_category(uuid4().hex)
+ object_category_id = mock_data.create_object_category(uuid4().hex)
+ value = {
+ "name": "",
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ with pytest.raises(MetaRuleContentError) as exception_info:
+ meta_rule_helper.add_meta_rule(value=value)
+ assert str(exception_info.value) == '400: Meta Rule Error'
+
+
+def test_update_meta_rule_success(db):
+ # arrange
+ meta_rules = meta_rule_helper.add_meta_rule()
+ meta_rule_id = list(meta_rules.keys())[0]
+ action_category_id = mock_data.create_action_category("action_category_id2")
+ subject_category_id = mock_data.create_subject_category("subject_category_id2")
+ object_category_id = mock_data.create_object_category("object_category_id2")
+ updated_value = {
+ "name": "MLS_meta_rule",
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ # action
+ updated_meta_rule = meta_rule_helper.update_meta_rule(meta_rule_id, updated_value)
+ # assert
+ updated_meta_rule_id = list(updated_meta_rule.keys())[0]
+ assert updated_meta_rule_id == meta_rule_id
+ assert updated_meta_rule[updated_meta_rule_id]["subject_categories"] == updated_value[
+ "subject_categories"]
+
+
+def test_update_meta_rule_with_existed_categories_combination(db):
+ action_category_id1 = mock_data.create_action_category(uuid4().hex)
+ subject_category_id1 = mock_data.create_subject_category(uuid4().hex)
+ object_category_id1 = mock_data.create_object_category(uuid4().hex)
+ meta_rule_name1=uuid4().hex
+ value1 = {
+ "name": meta_rule_name1,
+ "description": "test",
+ "subject_categories": [subject_category_id1],
+ "object_categories": [object_category_id1],
+ "action_categories": [action_category_id1]
+ }
+ meta_rules = meta_rule_helper.add_meta_rule(value=value1)
+
+ action_category_id2 = mock_data.create_action_category(uuid4().hex)
+ subject_category_id2 = mock_data.create_subject_category(uuid4().hex)
+ object_category_id2 = mock_data.create_object_category(uuid4().hex)
+ meta_rule_name2 = uuid4().hex
+ value2 = {
+ "name": meta_rule_name2,
+ "description": "test",
+ "subject_categories": [subject_category_id2],
+ "object_categories": [object_category_id2],
+ "action_categories": [action_category_id2]
+ }
+ meta_rules = meta_rule_helper.add_meta_rule(value=value2)
+ meta_rule_id2 = list(meta_rules.keys())[0]
+ value1['name']=value2['name']
+ with pytest.raises(MetaRuleExisting) as exception_info:
+ updated_meta_rule = meta_rule_helper.update_meta_rule(meta_rule_id2, value1)
+ assert str(exception_info.value) == '409: Meta Rule Existing'
+ assert exception_info.value.description=="Same categories combination existed"
+
+
+def test_update_meta_rule_with_different_categories_combination_but_same_data(db):
+ action_category_id1 = mock_data.create_action_category(uuid4().hex)
+ subject_category_id1 = mock_data.create_subject_category(uuid4().hex)
+ object_category_id1 = mock_data.create_object_category(uuid4().hex)
+ meta_rule_name1=uuid4().hex
+ value1 = {
+ "name": meta_rule_name1,
+ "description": "test",
+ "subject_categories": [subject_category_id1],
+ "object_categories": [object_category_id1],
+ "action_categories": [action_category_id1]
+ }
+ meta_rules = meta_rule_helper.add_meta_rule(value=value1)
+
+ action_category_id2 = mock_data.create_action_category(uuid4().hex)
+ subject_category_id2 = mock_data.create_subject_category(uuid4().hex)
+ object_category_id2 = mock_data.create_object_category(uuid4().hex)
+ meta_rule_name2 = uuid4().hex
+ value2 = {
+ "name": meta_rule_name2,
+ "description": "test",
+ "subject_categories": [subject_category_id2],
+ "object_categories": [object_category_id2],
+ "action_categories": [action_category_id2]
+ }
+ meta_rules = meta_rule_helper.add_meta_rule(value=value2)
+ meta_rule_id2 = list(meta_rules.keys())[0]
+ value1['name']=value2['name']
+ value1['object_categories']+=[object_category_id1]
+ updated_meta_rule = meta_rule_helper.update_meta_rule(meta_rule_id2, value1)
+ assert meta_rule_id2 in updated_meta_rule
+
+
+def test_add_existing_meta_rule_error(db):
+ action_category_id = mock_data.create_action_category("action_category_id3")
+ subject_category_id = mock_data.create_subject_category("subject_category_id3")
+ object_category_id = mock_data.create_object_category("object_category_id3")
+ value = {
+ "name": "MLS_meta_rule",
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ meta_rules = meta_rule_helper.add_meta_rule(value=value)
+ meta_rule_id = list(meta_rules.keys())[0]
+ with pytest.raises(MetaRuleExisting) as exception_info:
+ meta_rule_helper.add_meta_rule(meta_rule_id=meta_rule_id)
+ assert str(exception_info.value) == '409: Meta Rule Existing'
+
+
+def test_add_meta_rule_with_existing_name_error(db):
+ action_category_id = mock_data.create_action_category(uuid4().hex)
+ subject_category_id = mock_data.create_subject_category(uuid4().hex)
+ object_category_id = mock_data.create_object_category(uuid4().hex)
+ name = uuid4().hex
+ value = {
+ "name": name,
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ meta_rule_helper.add_meta_rule(value=value)
+ action_category_id = mock_data.create_action_category(uuid4().hex)
+ subject_category_id = mock_data.create_subject_category(uuid4().hex)
+ object_category_id = mock_data.create_object_category(uuid4().hex)
+ value = {
+ "name": name,
+ "description": 'test',
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ with pytest.raises(MetaRuleExisting) as exception_info:
+ meta_rule_helper.add_meta_rule(value=value)
+ assert str(exception_info.value) == '409: Meta Rule Existing'
+ assert exception_info.value.description == 'The meta rule already exists.'
+
+
+def test_add_meta_rule_with_existing_categories_combination(db):
+ action_category_id = mock_data.create_action_category(uuid4().hex)
+ subject_category_id = mock_data.create_subject_category(uuid4().hex)
+ object_category_id = mock_data.create_object_category(uuid4().hex)
+ name = uuid4().hex
+ value = {
+ "name": name,
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ meta_rule_helper.add_meta_rule(value=value)
+ value['name'] = uuid4().hex
+ with pytest.raises(MetaRuleExisting) as exception_info:
+ meta_rule_helper.add_meta_rule(value=value)
+ assert str(exception_info.value) == '409: Meta Rule Existing'
+ assert exception_info.value.description == "Same categories combination existed"
+
+
+def test_add_meta_rule_with_different_categories_combination_but_same_data(db):
+ action_category_id = mock_data.create_action_category(uuid4().hex)
+ subject_category_id = mock_data.create_subject_category(uuid4().hex)
+ object_category_id1 = mock_data.create_object_category(uuid4().hex)
+ object_category_id2 = mock_data.create_object_category(uuid4().hex)
+
+ name1 = uuid4().hex
+ value = {
+ "name": name1,
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id1],
+ "action_categories": [action_category_id]
+ }
+ meta_rule_helper.add_meta_rule(value=value)
+ name2 = uuid4().hex
+ value['name'] = name2
+ value['object_categories'] += [object_category_id2]
+ meta_rules = meta_rule_helper.add_meta_rule(value=value)
+ bool_found_meta_rule = 0
+ for meta_rule_id in meta_rules:
+ if meta_rules[meta_rule_id]['name'] == name2:
+ bool_found_meta_rule = 1
+ break
+ assert bool_found_meta_rule
+
+
+def test_get_meta_rule_success(db):
+ # arrange
+ action_category_id = mock_data.create_action_category("action_type")
+ subject_category_id = mock_data.create_subject_category("user_security_level")
+ object_category_id = mock_data.create_object_category("vm_security_level")
+ values = {}
+ value1 = {
+ "name": "MLS_meta_rule",
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ meta_rules1 = meta_rule_helper.add_meta_rule(value=value1)
+ meta_rule_id1 = list(meta_rules1.keys())[0]
+ values[meta_rule_id1] = value1
+ action_category_id = mock_data.create_action_category("action_type2")
+ subject_category_id = mock_data.create_subject_category("user_security_level2")
+ object_category_id = mock_data.create_object_category("vm_security_level2")
+ value2 = {
+ "name": "rbac_meta_rule",
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ meta_rules2 = meta_rule_helper.add_meta_rule(value=value2)
+ meta_rule_id2 = list(meta_rules2.keys())[0]
+ values[meta_rule_id2] = value2
+
+ # action
+ meta_rules = meta_rule_helper.get_meta_rules()
+ # assert
+ assert isinstance(meta_rules, dict)
+ assert meta_rules
+ assert len(meta_rules) is 2
+ for meta_rule_id in meta_rules:
+ for key in (
+ "name", "description", "subject_categories", "object_categories", "action_categories"):
+ assert key in meta_rules[meta_rule_id]
+ assert meta_rules[meta_rule_id][key] == values[meta_rule_id][key]
+
+
+def test_get_specific_meta_rule_success(db):
+ # arrange
+ added_meta_rules = meta_rule_helper.add_meta_rule()
+ added_meta_rule_id = list(added_meta_rules.keys())[0]
+ # action
+ meta_rules = meta_rule_helper.get_meta_rules(meta_rule_id=added_meta_rule_id)
+ meta_rule_id = list(meta_rules.keys())[0]
+ # assert
+ assert meta_rule_id == added_meta_rule_id
+ for key in (
+ "name", "description", "subject_categories", "object_categories", "action_categories"):
+ assert key in meta_rules[meta_rule_id]
+ assert meta_rules[meta_rule_id][key] == added_meta_rules[added_meta_rule_id][key]
+
+
+def test_delete_meta_rules_success(db):
+ action_category_id = mock_data.create_action_category("action_type")
+ subject_category_id = mock_data.create_subject_category("user_security_level")
+ object_category_id = mock_data.create_object_category("vm_security_level")
+ # arrange
+ value1 = {
+ "name": "MLS_meta_rule",
+ "description": "test",
+ "subject_categories": [subject_category_id],
+ "object_categories": [object_category_id],
+ "action_categories": [action_category_id]
+ }
+ meta_rules1 = meta_rule_helper.add_meta_rule(value=value1)
+ meta_rule_id1 = list(meta_rules1.keys())[0]
+
+ # action
+ meta_rule_helper.delete_meta_rules(meta_rule_id1)
+ # assert
+ meta_rules = meta_rule_helper.get_meta_rules()
+ assert meta_rule_id1 not in meta_rules
+
+
+def test_delete_meta_rules_with_model(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+
+ with pytest.raises(DeleteMetaRuleWithModel) as exception_info:
+ meta_rule_helper.delete_meta_rules(meta_rule_id)
+ assert str(exception_info.value) == '400: Meta rule With Model Error'
+
+
+def test_delete_invalid_meta_rules_error(db):
+ with pytest.raises(MetaRuleUnknown) as exception_info:
+ meta_rule_helper.delete_meta_rules("INVALID_META_RULE_ID")
+ assert str(exception_info.value) == '400: Meta Rule Unknown'
diff --git a/old/python_moondb/tests/unit_python/models/test_models.py b/old/python_moondb/tests/unit_python/models/test_models.py
new file mode 100644
index 00000000..1b171069
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/models/test_models.py
@@ -0,0 +1,622 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import pytest
+from python_moonutilities.exceptions import *
+import logging
+import helpers.mock_data as mock_data
+import helpers.model_helper as model_helper
+import helpers.category_helper as category_helper
+import helpers.policy_helper as policy_helper
+import helpers.assignment_helper as assignment_helper
+from uuid import uuid4
+
+logger = logging.getLogger("moon.db.tests.test_model")
+
+
+def test_get_models_empty(db):
+ # act
+ models = model_helper.get_models()
+ # assert
+ assert isinstance(models, dict)
+ assert not models
+
+
+def test_get_model(db):
+ # prepare
+ model_helper.add_model(model_id="mls_model_id")
+ # act
+ models = model_helper.get_models()
+ # assert
+ assert isinstance(models, dict)
+ assert models # assert model is not empty
+ assert len(models) is 1
+ model_helper.delete_all_models()
+
+
+def test_get_specific_model(db):
+ # prepare
+ model_helper.add_model(model_id="mls_model_id")
+ # act
+ models = model_helper.get_models(model_id="mls_model_id")
+ # assert
+ assert isinstance(models, dict)
+ assert models # assert model is not empty
+ assert len(models) is 1
+ model_helper.delete_all_models()
+
+
+def test_add_model(db):
+ # act
+ model = model_helper.add_model()
+ # assert
+ assert isinstance(model, dict)
+ assert model # assert model is not empty
+ assert len(model) is 1
+ model_helper.delete_all_models()
+
+
+def test_add_same_model_twice(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = mock_data.create_new_meta_rule(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "model1",
+ "description": "test",
+ "meta_rules": [meta_rule_id]
+ }
+ # prepare
+ model_helper.add_model(model_id="model_1", value=value) # add model twice
+ # act
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = mock_data.create_new_meta_rule(
+ subject_category_name="subject_category2",
+ object_category_name="object_category2",
+ action_category_name="action_category2",
+ meta_rule_name="meta_rule_2")
+ value = {
+ "name": "model2",
+ "description": "test",
+ "meta_rules": [meta_rule_id]
+ }
+ with pytest.raises(ModelExisting) as exception_info:
+ model_helper.add_model(model_id="model_1", value=value)
+ model_helper.delete_all_models()
+ assert str(exception_info.value) == '409: Model Error'
+
+
+def test_add_model_generate_new_uuid(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id1 = mock_data.create_new_meta_rule(
+ subject_category_name="subject_category3",
+ object_category_name="object_category3",
+ action_category_name="action_category3",
+ meta_rule_name="meta_rule_3")
+ model_value1 = {
+ "name": "MLS",
+ "description": "test",
+ "meta_rules": [meta_rule_id1]
+ }
+ model1 = model_helper.add_model(value=model_value1)
+ subject_category_id, object_category_id, action_category_id, meta_rule_id2 = mock_data.create_new_meta_rule(
+ subject_category_name="subject_category4",
+ object_category_name="object_category4",
+ action_category_name="action_category4",
+ meta_rule_name="meta_rule_4")
+ model_value2 = {
+ "name": "rbac",
+ "description": "test",
+ "meta_rules": [meta_rule_id2]
+ }
+ model2 = model_helper.add_model(value=model_value2)
+
+ assert list(model1)[0] != list(model2)[0]
+ model_helper.delete_all_models()
+
+
+def test_add_models(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = mock_data.create_new_meta_rule(
+ subject_category_name="subject_category5",
+ object_category_name="object_category5",
+ action_category_name="action_category5")
+ model_value1 = {
+ "name": "MLS",
+ "description": "test",
+ "meta_rules": [meta_rule_id]
+ }
+ models = model_helper.add_model(value=model_value1)
+ assert isinstance(models, dict)
+ assert models
+ assert len(models.keys()) == 1
+ model_id = list(models.keys())[0]
+ for key in ("name", "meta_rules", "description"):
+ assert key in models[model_id]
+ assert models[model_id][key] == model_value1[key]
+ model_helper.delete_all_models()
+
+
+def test_add_models_with_same_name_twice(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = mock_data.create_new_meta_rule(
+ subject_category_name="subject_category5",
+ object_category_name="object_category5",
+ action_category_name="action_category5")
+ model_value1 = {
+ "name": "MLS",
+ "description": "test",
+ "meta_rules": [meta_rule_id]
+ }
+ models = model_helper.add_model(value=model_value1)
+ assert isinstance(models, dict)
+ assert models
+ with pytest.raises(Exception) as exception_info:
+ model_helper.add_model(value=model_value1)
+ model_helper.delete_all_models()
+ assert str(exception_info.value) == '409: Model Error'
+
+def test_add_model_with_existed_meta_rules_list(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id = mock_data.create_new_meta_rule(
+ subject_category_name=uuid4().hex,
+ object_category_name=uuid4().hex,
+ action_category_name=uuid4().hex)
+ model_value1 = {
+ "name": uuid4().hex,
+ "description": "test",
+ "meta_rules": [meta_rule_id]
+ }
+ models = model_helper.add_model(value=model_value1)
+ assert isinstance(models, dict)
+ assert models
+ model_value1 = {
+ "name": uuid4().hex,
+ "description": "test",
+ "meta_rules": [meta_rule_id]
+ }
+ with pytest.raises(Exception) as exception_info:
+ model_helper.add_model(value=model_value1)
+ model_helper.delete_all_models()
+ assert str(exception_info.value) == '409: Model Error'
+ assert str(exception_info.value.description)=='Meta Rules List Existed in another Model'
+
+
+def test_delete_models(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id1 = mock_data.create_new_meta_rule(
+ subject_category_name="subject_category6",
+ object_category_name="object_category6",
+ action_category_name="action_category6",
+ meta_rule_name="meta_rule_6")
+ model_value1 = {
+ "name": "MLS",
+ "description": "test",
+ "meta_rules": [meta_rule_id1]
+ }
+ model1 = model_helper.add_model(value=model_value1)
+ subject_category_id, object_category_id, action_category_id, meta_rule_id2 = mock_data.create_new_meta_rule(
+ subject_category_name="subject_category7",
+ object_category_name="object_category7",
+ action_category_name="action_category7",
+ meta_rule_name="meta_rule_7")
+ model_value2 = {
+ "name": "rbac",
+ "description": "test",
+ "meta_rules": [meta_rule_id2]
+ }
+ model_helper.add_model(value=model_value2)
+
+ id = list(model1)[0]
+ model_helper.delete_models(id)
+ # assert
+ models = model_helper.get_models()
+ assert id not in models
+ model_helper.delete_all_models()
+
+
+def test_update_model(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id1 = mock_data.create_new_meta_rule(
+ subject_category_name="subject_category8",
+ object_category_name="object_category8",
+ action_category_name="action_category8",
+ meta_rule_name="meta_rule_8")
+ # prepare
+ model_value = {
+ "name": "MLS",
+ "description": "test",
+ "meta_rules": [meta_rule_id1]
+ }
+ model = model_helper.add_model(value=model_value)
+ model_id = list(model)[0]
+ subject_category_id, object_category_id, action_category_id, meta_rule_id2 = mock_data.create_new_meta_rule(
+ subject_category_name="subject_category9",
+ object_category_name="object_category9",
+ action_category_name="action_category9",
+ meta_rule_name="meta_rule_9")
+ new_model_value = {
+ "name": "MLS2",
+ "description": "test",
+ "meta_rules": [meta_rule_id2]
+ }
+ # act
+ model_helper.update_model(model_id=model_id, value=new_model_value)
+ # assert
+ model = model_helper.get_models(model_id)
+
+ for key in ("name", "meta_rules", "description"):
+ assert key in model[model_id]
+ assert model[model_id][key] == new_model_value[key]
+ model_helper.delete_all_models()
+
+
+def test_delete_model_assigned_to_policy(db):
+ model_value1 = {
+ "name": "MLS",
+ "description": "test",
+ "meta_rules": []
+ }
+ models = model_helper.add_model(value=model_value1)
+ assert isinstance(models, dict)
+ assert models
+ assert len(models.keys()) == 1
+ model_id = list(models.keys())[0]
+ value = {
+ "name": "test_policy",
+ "model_id": model_id,
+ "genre": "authz",
+ "description": "test",
+ }
+ policy_helper.add_policies(value=value)
+ with pytest.raises(DeleteModelWithPolicy) as exception_info:
+ model_helper.delete_models(uuid=model_id)
+ assert str(exception_info.value) == '400: Model With Policy Error'
+
+
+def test_add_subject_category(db):
+ category_id = "category_id1"
+ value = {
+ "name": "subject_category",
+ "description": "description subject_category"
+ }
+ subject_category = category_helper.add_subject_category(category_id, value)
+ assert subject_category
+ assert len(subject_category) == 1
+
+
+def test_add_subject_categories_with_existed_name(db):
+ name = uuid4().hex
+ value = {
+ "name": name,
+ "description": "description subject_category"
+ }
+ subject_category = category_helper.add_subject_category(value=value)
+ assert subject_category
+ assert len(subject_category) == 1
+
+ value = {
+ "name": name,
+ "description": "description subject_category"
+ }
+ with pytest.raises(SubjectCategoryExisting) as exception_info:
+ category_helper.add_subject_category(value=value)
+ assert str(exception_info.value) == '409: Subject Category Existing'
+
+
+def test_add_subject_category_with_empty_name(db):
+ category_id = "category_id1"
+ value = {
+ "name": "",
+ "description": "description subject_category"
+ }
+ with pytest.raises(CategoryNameInvalid) as exception_info:
+ category_helper.add_subject_category(category_id, value)
+ assert str(exception_info.value) == '400: Category Name Invalid'
+
+
+def test_add_subject_category_with_same_category_id(db):
+ category_id = "category_id1"
+ value = {
+ "name": "subject_category",
+ "description": "description subject_category"
+ }
+ category_helper.add_subject_category(category_id, value)
+ with pytest.raises(SubjectCategoryExisting) as exception_info:
+ category_helper.add_subject_category(category_id, value)
+ assert str(exception_info.value) == '409: Subject Category Existing'
+
+
+def test_get_subject_category(db):
+ category_id = "category_id1"
+ value = {
+ "name": "subject_category",
+ "description": "description subject_category"
+ }
+ category_helper.add_subject_category(category_id, value)
+ subject_category = category_helper.get_subject_category(category_id)
+ assert subject_category
+ assert len(subject_category) == 1
+
+
+def test_delete_subject_category(db):
+ category_id = "category_id1"
+ value = {
+ "name": "subject_category",
+ "description": "description subject_category"
+ }
+ category_helper.add_subject_category(category_id, value)
+ subject_category = category_helper.delete_subject_category(category_id)
+ assert not subject_category
+
+
+def test_delete_subject_category_with_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+
+ mock_data.create_subject_data(policy_id, subject_category_id)
+
+ with pytest.raises(DeleteSubjectCategoryWithMetaRule) as exception_info:
+ category_helper.delete_subject_category(subject_category_id)
+ assert str(exception_info.value) == '400: Subject Category With Meta Rule Error'
+
+
+def test_delete_subject_category_with_assignment(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+
+ subject_id = mock_data.create_subject(policy_id)
+ data_id = mock_data.create_subject_data(policy_id, subject_category_id)
+ assignment_helper.add_subject_assignment(policy_id, subject_id, subject_category_id, data_id)
+
+ with pytest.raises(DeleteSubjectCategoryWithMetaRule) as exception_info:
+ category_helper.delete_subject_category(subject_category_id)
+ assert str(exception_info.value) == '400: Subject Category With Meta Rule Error'
+
+
+def test_delete_subject_category_with_rule(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+ policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id)
+
+ with pytest.raises(DeleteSubjectCategoryWithMetaRule) as exception_info:
+ category_helper.delete_subject_category(subject_category_id)
+ assert str(exception_info.value) == '400: Subject Category With Meta Rule Error'
+
+
+def test_delete_subject_category_with_unkown_category_id(db):
+ category_id = "invalid_category_id"
+
+ with pytest.raises(SubjectCategoryUnknown) as exception_info:
+ category_helper.delete_subject_category(category_id)
+ assert str(exception_info.value) == '400: Subject Category Unknown'
+
+
+def test_add_object_category(db):
+ category_id = "category_id1"
+ value = {
+ "name": "object_category",
+ "description": "description object_category"
+ }
+ object_category = category_helper.add_object_category(category_id, value)
+ assert object_category
+ assert len(object_category) == 1
+
+
+def test_add_object_categories_with_existed_name(db):
+ name = uuid4().hex
+ value = {
+ "name": name,
+ "description": "description object_category"
+ }
+ object_category = category_helper.add_object_category(value=value)
+ assert object_category
+ assert len(object_category) == 1
+ with pytest.raises(ObjectCategoryExisting) as exception_info:
+ category_helper.add_object_category(value=value)
+ assert str(exception_info.value) == '409: Object Category Existing'
+
+
+def test_add_object_category_with_same_category_id(db):
+ category_id = "category_id1"
+ value = {
+ "name": "object_category",
+ "description": "description object_category"
+ }
+ category_helper.add_object_category(category_id, value)
+ with pytest.raises(ObjectCategoryExisting) as exception_info:
+ category_helper.add_object_category(category_id, value)
+ assert str(exception_info.value) == '409: Object Category Existing'
+
+
+def test_add_object_category_with_empty_name(db):
+ category_id = "category_id1"
+ value = {
+ "name": "",
+ "description": "description object_category"
+ }
+ with pytest.raises(CategoryNameInvalid) as exception_info:
+ category_helper.add_object_category(category_id, value)
+ assert str(exception_info.value) == '400: Category Name Invalid'
+
+
+def test_get_object_category(db):
+ category_id = "category_id1"
+ value = {
+ "name": "object_category",
+ "description": "description object_category"
+ }
+ category_helper.add_object_category(category_id, value)
+ object_category = category_helper.get_object_category(category_id)
+ assert object_category
+ assert len(object_category) == 1
+
+
+def test_delete_object_category(db):
+ category_id = "category_id1"
+ value = {
+ "name": "object_category",
+ "description": "description object_category"
+ }
+ category_helper.add_object_category(category_id, value)
+ object_category = category_helper.delete_object_category(category_id)
+ assert not object_category
+
+
+def test_delete_object_category_with_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+ mock_data.create_subject_data(policy_id, subject_category_id)
+
+ mock_data.create_object_data(policy_id, object_category_id)
+
+ with pytest.raises(DeleteObjectCategoryWithMetaRule) as exception_info:
+ category_helper.delete_object_category(object_category_id)
+ assert str(exception_info.value) == '400: Object Category With Meta Rule Error'
+
+
+def test_delete_object_category_with_assignment(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+
+ object_id = mock_data.create_object(policy_id)
+ data_id = mock_data.create_object_data(policy_id, object_category_id)
+ assignment_helper.add_object_assignment(policy_id, object_id, object_category_id, data_id)
+
+ with pytest.raises(DeleteObjectCategoryWithMetaRule) as exception_info:
+ category_helper.delete_object_category(object_category_id)
+ assert str(exception_info.value) == '400: Object Category With Meta Rule Error'
+
+
+def test_delete_object_category_with_rule(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+ policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id)
+
+ with pytest.raises(DeleteObjectCategoryWithMetaRule) as exception_info:
+ category_helper.delete_object_category(object_category_id)
+ assert str(exception_info.value) == '400: Object Category With Meta Rule Error'
+
+
+def test_delete_object_category_with_unkown_category_id(db):
+ category_id = "invalid_category_id"
+
+ with pytest.raises(ObjectCategoryUnknown) as exception_info:
+ category_helper.delete_object_category(category_id)
+ assert str(exception_info.value) == '400: Object Category Unknown'
+
+
+def test_add_action_category(db):
+ category_id = "category_id1"
+ value = {
+ "name": "action_category",
+ "description": "description action_category"
+ }
+ action_category = category_helper.add_action_category(category_id, value)
+ assert action_category
+ assert len(action_category) == 1
+
+
+def test_add_action_categories_with_existed_name(db):
+ name = uuid4().hex
+ value = {
+ "name": name,
+ "description": "description action_category"
+ }
+ action_category = category_helper.add_action_category(value=value)
+ assert action_category
+ assert len(action_category) == 1
+ with pytest.raises(ActionCategoryExisting) as exception_info:
+ category_helper.add_action_category(value=value)
+ assert str(exception_info.value) == '409: Action Category Existing'
+
+
+def test_add_action_category_with_same_category_id(db):
+ category_id = "category_id1"
+ value = {
+ "name": "action_category",
+ "description": "description action_category"
+ }
+ category_helper.add_action_category(category_id, value)
+ with pytest.raises(ActionCategoryExisting) as exception_info:
+ category_helper.add_action_category(category_id, value)
+ assert str(exception_info.value) == '409: Action Category Existing'
+
+
+def test_add_action_category_with_empty_name(db):
+ category_id = "category_id1"
+ value = {
+ "name": "",
+ "description": "description action_category"
+ }
+ with pytest.raises(CategoryNameInvalid) as exception_info:
+ category_helper.add_action_category(category_id, value)
+ assert str(exception_info.value) == '400: Category Name Invalid'
+
+
+def test_get_action_category(db):
+ category_id = "category_id1"
+ value = {
+ "name": "action_category",
+ "description": "description action_category"
+ }
+ category_helper.add_action_category(category_id, value)
+ action_category = category_helper.get_action_category(category_id)
+ assert action_category
+ assert len(action_category) == 1
+
+
+def test_delete_action_category(db):
+ category_id = "category_id1"
+ value = {
+ "name": "action_category",
+ "description": "description action_category"
+ }
+ category_helper.add_action_category(category_id, value)
+ action_category = category_helper.delete_action_category(category_id)
+ assert not action_category
+
+
+def test_delete_action_category_with_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+ mock_data.create_subject_data(policy_id, subject_category_id)
+
+ mock_data.create_action_data(policy_id, action_category_id)
+
+ with pytest.raises(DeleteActionCategoryWithMetaRule) as exception_info:
+ category_helper.delete_action_category(action_category_id)
+ assert str(exception_info.value) == '400: Action Category With Meta Rule Error'
+
+
+def test_delete_action_category_with_assignment(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+
+ action_id = mock_data.create_action(policy_id)
+ data_id = mock_data.create_action_data(policy_id, action_category_id)
+ assignment_helper.add_action_assignment(policy_id, action_id, action_category_id, data_id)
+
+ with pytest.raises(DeleteActionCategoryWithMetaRule) as exception_info:
+ category_helper.delete_action_category(action_category_id)
+ assert str(exception_info.value) == '400: Action Category With Meta Rule Error'
+
+
+def test_delete_action_category_with_rule(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+ policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id)
+
+ with pytest.raises(DeleteActionCategoryWithMetaRule) as exception_info:
+ category_helper.delete_action_category(action_category_id)
+ assert str(exception_info.value) == '400: Action Category With Meta Rule Error'
+
+
+def test_delete_action_category_with_unkown_category_id(db):
+ category_id = "invalid_category_id"
+
+ with pytest.raises(ActionCategoryUnknown) as exception_info:
+ category_helper.delete_action_category(category_id)
+ assert str(exception_info.value) == '400: Action Category Unknown'
+
+
+def test_delete_data_categories_connected_to_meta_rule(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+ with pytest.raises(DeleteSubjectCategoryWithMetaRule) as exception_info:
+ category_helper.delete_subject_category(subject_category_id)
+ assert str(exception_info.value) == '400: Subject Category With Meta Rule Error'
+
+ with pytest.raises(DeleteObjectCategoryWithMetaRule) as exception_info:
+ category_helper.delete_object_category(object_category_id)
+ assert str(exception_info.value) == '400: Object Category With Meta Rule Error'
+
+ with pytest.raises(DeleteActionCategoryWithMetaRule) as exception_info:
+ category_helper.delete_action_category(action_category_id)
+ assert str(exception_info.value) == '400: Action Category With Meta Rule Error'
diff --git a/old/python_moondb/tests/unit_python/policies/__init__.py b/old/python_moondb/tests/unit_python/policies/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/policies/__init__.py
diff --git a/old/python_moondb/tests/unit_python/policies/mock_data.py b/old/python_moondb/tests/unit_python/policies/mock_data.py
new file mode 100644
index 00000000..47fc9f9e
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/policies/mock_data.py
@@ -0,0 +1,74 @@
+import helpers.model_helper as model_helper
+import helpers.meta_rule_helper as meta_rule_helper
+import helpers.policy_helper as policy_helper
+import helpers.category_helper as category_helper
+
+
+def create_meta_rule(meta_rule_name="meta_rule1", category_prefix=""):
+ meta_rule_value = {
+ "name": meta_rule_name,
+ "algorithm": "name of the meta rule algorithm",
+ "subject_categories": [category_prefix + "subject_category_id1",
+ category_prefix + "subject_category_id2"],
+ "object_categories": [category_prefix + "object_category_id1"],
+ "action_categories": [category_prefix + "action_category_id1"]
+ }
+ return meta_rule_value
+
+
+def create_model(meta_rule_id, model_name="test_model"):
+ value = {
+ "name": model_name,
+ "description": "test",
+ "meta_rules": [meta_rule_id]
+
+ }
+ return value
+
+
+def create_policy(model_id, policy_name="policy_1"):
+ value = {
+ "name": policy_name,
+ "model_id": model_id,
+ "genre": "authz",
+ "description": "test",
+ }
+ return value
+
+
+def create_pdp(pdp_ids):
+ value = {
+ "name": "test_pdp",
+ "security_pipeline": pdp_ids,
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+ return value
+
+
+def get_policy_id(model_name="test_model", policy_name="policy_1", meta_rule_name="meta_rule1", category_prefix=""):
+ category_helper.add_subject_category(
+ category_prefix + "subject_category_id1",
+ value={"name": category_prefix + "subject_category_id1",
+ "description": "description 1"})
+ category_helper.add_subject_category(
+ category_prefix + "subject_category_id2",
+ value={"name": category_prefix + "subject_category_id2",
+ "description": "description 1"})
+ category_helper.add_object_category(
+ category_prefix + "object_category_id1",
+ value={"name": category_prefix + "object_category_id1",
+ "description": "description 1"})
+ category_helper.add_action_category(
+ category_prefix + "action_category_id1",
+ value={"name": category_prefix + "action_category_id1",
+ "description": "description 1"})
+ meta_rule = meta_rule_helper.add_meta_rule(value=create_meta_rule(meta_rule_name, category_prefix))
+ meta_rule_id = list(meta_rule.keys())[0]
+ model = model_helper.add_model(value=create_model(meta_rule_id, model_name))
+ model_id = list(model.keys())[0]
+ value = create_policy(model_id, policy_name)
+ policy = policy_helper.add_policies(value=value)
+ assert policy
+ policy_id = list(policy.keys())[0]
+ return policy_id
diff --git a/old/python_moondb/tests/unit_python/policies/test_assignments.py b/old/python_moondb/tests/unit_python/policies/test_assignments.py
new file mode 100755
index 00000000..24a3a7b0
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/policies/test_assignments.py
@@ -0,0 +1,235 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import helpers.mock_data as mock_data
+import helpers.assignment_helper as assignment_helper
+from python_moonutilities.exceptions import *
+import pytest
+
+
+def test_get_action_assignments(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ action_id = mock_data.create_action(policy_id)
+ data_id = mock_data.create_action_data(policy_id=policy_id, category_id=action_category_id)
+
+ assignment_helper.add_action_assignment(policy_id, action_id, action_category_id, data_id)
+ act_assignments = assignment_helper.get_action_assignments(policy_id, action_id,
+ action_category_id)
+ action_id_1 = list(act_assignments.keys())[0]
+ assert act_assignments[action_id_1]["policy_id"] == policy_id
+ assert act_assignments[action_id_1]["action_id"] == action_id
+ assert act_assignments[action_id_1]["category_id"] == action_category_id
+ assert len(act_assignments[action_id_1].get("assignments")) == 1
+ assert data_id in act_assignments[action_id_1].get("assignments")
+
+
+def test_add_action_assignments(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ action_id = mock_data.create_action(policy_id)
+ data_id = mock_data.create_action_data(policy_id=policy_id, category_id=action_category_id)
+ action_assignments = assignment_helper.add_action_assignment(policy_id, action_id,
+ action_category_id, data_id)
+ assert action_assignments
+ action_id_1 = list(action_assignments.keys())[0]
+ assert action_assignments[action_id_1]["policy_id"] == policy_id
+ assert action_assignments[action_id_1]["action_id"] == action_id
+ assert action_assignments[action_id_1]["category_id"] == action_category_id
+ assert len(action_assignments[action_id_1].get("assignments")) == 1
+ assert data_id in action_assignments[action_id_1].get("assignments")
+
+ with pytest.raises(ActionAssignmentExisting) as exception_info:
+ assignment_helper.add_action_assignment(policy_id, action_id, action_category_id, data_id)
+ assert str(exception_info.value) == '409: Action Assignment Existing'
+ assert str(exception_info.value.description) == 'The given action assignment value is existing.'
+
+
+def test_delete_action_assignment(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ action_id = mock_data.create_action(policy_id)
+ data_id = mock_data.create_action_data(policy_id=policy_id, category_id=action_category_id)
+ assignment_helper.add_action_assignment(policy_id, action_id, action_category_id, data_id)
+ assignment_helper.delete_action_assignment(policy_id, "", "", "")
+ assignments = assignment_helper.get_action_assignments(policy_id, )
+ assert len(assignments) == 1
+
+
+def test_delete_action_assignment_with_invalid_policy_id(db):
+ policy_id = "invalid_id"
+ assignment_helper.delete_action_assignment(policy_id, "", "", "")
+ assignments = assignment_helper.get_action_assignments(policy_id, )
+ assert len(assignments) == 0
+
+
+def test_get_object_assignments(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ object_id = mock_data.create_object(policy_id)
+ data_id = mock_data.create_object_data(policy_id=policy_id, category_id=object_category_id)
+ assignment_helper.add_object_assignment(policy_id, object_id, object_category_id, data_id)
+ obj_assignments = assignment_helper.get_object_assignments(policy_id, object_id,
+ object_category_id)
+ object_id_1 = list(obj_assignments.keys())[0]
+ assert obj_assignments[object_id_1]["policy_id"] == policy_id
+ assert obj_assignments[object_id_1]["object_id"] == object_id
+ assert obj_assignments[object_id_1]["category_id"] == object_category_id
+ assert len(obj_assignments[object_id_1].get("assignments")) == 1
+ assert data_id in obj_assignments[object_id_1].get("assignments")
+
+
+def test_get_object_assignments_by_policy_id(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ object_id = mock_data.create_object(policy_id)
+ data_id = mock_data.create_object_data(policy_id=policy_id, category_id=object_category_id)
+ assignment_helper.add_object_assignment(policy_id, object_id, object_category_id, data_id)
+ obj_assignments = assignment_helper.get_object_assignments(policy_id)
+ assert len(obj_assignments) == 1
+
+
+def test_add_object_assignments(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ object_id = mock_data.create_object(policy_id)
+ data_id = mock_data.create_object_data(policy_id=policy_id, category_id=object_category_id)
+ object_assignments = assignment_helper.add_object_assignment(policy_id, object_id,
+ object_category_id, data_id)
+ assert object_assignments
+ object_id_1 = list(object_assignments.keys())[0]
+ assert object_assignments[object_id_1]["policy_id"] == policy_id
+ assert object_assignments[object_id_1]["object_id"] == object_id
+ assert object_assignments[object_id_1]["category_id"] == object_category_id
+ assert len(object_assignments[object_id_1].get("assignments")) == 1
+ assert data_id in object_assignments[object_id_1].get("assignments")
+
+ with pytest.raises(ObjectAssignmentExisting) as exception_info:
+ assignment_helper.add_object_assignment(policy_id, object_id, object_category_id, data_id)
+ assert str(exception_info.value) == '409: Object Assignment Existing'
+ assert str(exception_info.value.description) == 'The given object assignment value is existing.'
+
+
+def test_delete_object_assignment(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ object_id = mock_data.create_object(policy_id)
+ data_id = mock_data.create_object_data(policy_id=policy_id, category_id=object_category_id)
+ assignment_helper.add_object_assignment(policy_id, object_id, object_category_id, data_id)
+
+ assignment_helper.delete_object_assignment(policy_id, object_id, object_category_id,
+ data_id=data_id)
+ assignments = assignment_helper.get_object_assignments(policy_id)
+ assert len(assignments) == 0
+
+
+def test_delete_object_assignment_with_invalid_policy_id(db):
+ policy_id = "invalid_id"
+ assignment_helper.delete_object_assignment(policy_id, "", "", "")
+ assignments = assignment_helper.get_object_assignments(policy_id, )
+ assert len(assignments) == 0
+
+
+def test_get_subject_assignments(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ subject_id = mock_data.create_subject(policy_id)
+ data_id = mock_data.create_subject_data(policy_id=policy_id, category_id=subject_category_id)
+
+ assignment_helper.add_subject_assignment(policy_id, subject_id, subject_category_id, data_id)
+ subj_assignments = assignment_helper.get_subject_assignments(policy_id, subject_id,
+ subject_category_id)
+ subject_id_1 = list(subj_assignments.keys())[0]
+ assert subj_assignments[subject_id_1]["policy_id"] == policy_id
+ assert subj_assignments[subject_id_1]["subject_id"] == subject_id
+ assert subj_assignments[subject_id_1]["category_id"] == subject_category_id
+ assert len(subj_assignments[subject_id_1].get("assignments")) == 1
+ assert data_id in subj_assignments[subject_id_1].get("assignments")
+
+
+def test_get_subject_assignments_by_policy_id(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ subject_id = mock_data.create_subject(policy_id)
+ data_id = mock_data.create_subject_data(policy_id=policy_id, category_id=subject_category_id)
+
+ assignment_helper.add_subject_assignment(policy_id, subject_id, subject_category_id, data_id)
+ subj_assignments = assignment_helper.get_subject_assignments(policy_id)
+ assert len(subj_assignments) == 1
+
+
+def test_add_subject_assignments(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ subject_id = mock_data.create_subject(policy_id)
+ data_id = mock_data.create_subject_data(policy_id=policy_id, category_id=subject_category_id)
+
+ subject_assignments = assignment_helper.add_subject_assignment(policy_id, subject_id,
+ subject_category_id, data_id)
+ assert subject_assignments
+ subject_id_1 = list(subject_assignments.keys())[0]
+ assert subject_assignments[subject_id_1]["policy_id"] == policy_id
+ assert subject_assignments[subject_id_1]["subject_id"] == subject_id
+ assert subject_assignments[subject_id_1]["category_id"] == subject_category_id
+ assert len(subject_assignments[subject_id_1].get("assignments")) == 1
+ assert data_id in subject_assignments[subject_id_1].get("assignments")
+
+ with pytest.raises(SubjectAssignmentExisting) as exception_info:
+ assignment_helper.add_subject_assignment(policy_id, subject_id, subject_category_id,
+ data_id)
+ assert str(exception_info.value) == '409: Subject Assignment Existing'
+ assert str(
+ exception_info.value.description) == 'The given subject assignment value is existing.'
+
+
+def test_delete_subject_assignment(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ subject_id = mock_data.create_subject(policy_id)
+ data_id = mock_data.create_subject_data(policy_id=policy_id, category_id=subject_category_id)
+ assignment_helper.add_subject_assignment(policy_id, subject_id, subject_category_id, data_id)
+ assignment_helper.delete_subject_assignment(policy_id, subject_id, subject_category_id, data_id)
+ assignments = assignment_helper.get_subject_assignments(policy_id)
+ assert len(assignments) == 0
+
+
+def test_delete_subject_assignment_with_invalid_policy_id(db):
+ policy_id = "invalid_id"
+ assignment_helper.delete_subject_assignment(policy_id, "", "", "")
+ assignments = assignment_helper.get_subject_assignments(policy_id, )
+ assert len(assignments) == 0
diff --git a/old/python_moondb/tests/unit_python/policies/test_data.py b/old/python_moondb/tests/unit_python/policies/test_data.py
new file mode 100755
index 00000000..8ce1ac00
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/policies/test_data.py
@@ -0,0 +1,707 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import helpers.mock_data as mock_data
+import policies.mock_data
+import helpers.data_helper as data_helper
+import helpers.assignment_helper as assignment_helper
+import pytest
+from uuid import uuid4
+import logging
+from python_moonutilities.exceptions import *
+
+logger = logging.getLogger("python_moondb.tests.api.test_data")
+
+
+def test_get_action_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "action-type",
+ "description": {"vm-action": "", "storage-action": "", },
+ }
+ action_data = data_helper.add_action_data(policy_id=policy_id, category_id=action_category_id, value=value)
+ data_id = list(action_data["data"])[0]
+ found_action_data = data_helper.get_action_data(policy_id=policy_id, data_id=data_id,
+ category_id=action_category_id)
+ assert found_action_data
+ assert len(found_action_data[0]["data"]) == 1
+
+
+def test_get_action_data_with_invalid_category_id(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ action_data = data_helper.get_action_data(policy_id=policy_id, category_id="invalid")
+ assert len(action_data) == 0
+
+
+def test_add_action_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "action-type",
+ "description": {"vm-action": "", "storage-action": "", },
+ }
+ action_data = data_helper.add_action_data(policy_id=policy_id, category_id=action_category_id, value=value)
+ assert action_data
+ assert len(action_data['data']) == 1
+
+
+def test_add_action_data_duplicate(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "action-type",
+ "description": {"vm-action": "", "storage-action": "", },
+ }
+ action_data = data_helper.add_action_data(policy_id=policy_id, category_id=action_category_id, value=value)
+ with pytest.raises(ActionScopeExisting) as exception_info:
+ action_data = data_helper.add_action_data(policy_id=policy_id, category_id=action_category_id, value=value)
+ assert str(exception_info.value) == '409: Action Scope Existing'
+
+def test_add_action_data_with_invalid_category_id(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "action-type",
+ "description": {"vm-action": "", "storage-action": "", },
+ }
+ with pytest.raises(ActionCategoryUnknown) as exception_info:
+ data_helper.add_action_data(policy_id=policy_id, value=value).get('data')
+ assert str(exception_info.value) == '400: Action Category Unknown'
+
+
+def test_delete_action_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ data_helper.get_available_metadata(policy_id)
+ value = {
+ "name": "action-type",
+ "description": {"vm-action": "", "storage-action": "", },
+ }
+ action_data = data_helper.add_action_data(policy_id=policy_id, category_id=action_category_id, value=value)
+ data_id = list(action_data["data"])[0]
+ data_helper.delete_action_data(policy_id=policy_id, data_id=data_id)
+ new_action_data = data_helper.get_action_data(policy_id)
+ assert len(new_action_data[0]['data']) == 0
+
+
+def test_get_object_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "object-security-level",
+ "description": {"low": "", "medium": "", "high": ""},
+ }
+ object_data = data_helper.add_object_data(policy_id=policy_id, category_id=object_category_id, value=value)
+ data_id = list(object_data["data"])[0]
+ found_object_data = data_helper.get_object_data(policy_id=policy_id, data_id=data_id,
+ category_id=object_category_id)
+ assert found_object_data
+ assert len(found_object_data[0]['data']) == 1
+
+
+def test_get_object_data_with_invalid_category_id(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ object_data = data_helper.get_object_data(policy_id=policy_id, category_id="invalid")
+ assert len(object_data) == 0
+
+
+def test_add_object_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "object-security-level",
+ "description": {"low": "", "medium": "", "high": ""},
+ }
+ object_data = data_helper.add_object_data(policy_id=policy_id, category_id=object_category_id, value=value).get(
+ 'data')
+ assert object_data
+ object_data_id = list(object_data.keys())[0]
+ assert object_data[object_data_id].get('policy_id') == policy_id
+
+
+def test_add_object_data_with_invalid_category_id(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "object-security-level",
+ "description": {"low": "", "medium": "", "high": ""},
+ }
+ with pytest.raises(ObjectCategoryUnknown) as exception_info:
+ data_helper.add_object_data(policy_id=policy_id, category_id="invalid", value=value).get('data')
+ assert str(exception_info.value) == '400: Object Category Unknown'
+
+
+def test_add_object_data_duplicate(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "object-security-level",
+ "description": {"low": "", "medium": "", "high": ""},
+ }
+ object_data = data_helper.add_object_data(policy_id=policy_id, category_id=object_category_id, value=value).get(
+ 'data')
+ with pytest.raises(ObjectScopeExisting) as exception_info:
+ data_helper.add_object_data(policy_id=policy_id, category_id=object_category_id, value=value).get(
+ 'data')
+ assert str(exception_info.value) == '409: Object Scope Existing'
+
+
+def test_delete_object_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "object-security-level",
+ "description": {"low": "", "medium": "", "high": ""},
+ }
+ object_data = data_helper.add_object_data(policy_id=policy_id, category_id=object_category_id, value=value).get(
+ 'data')
+ object_data_id = list(object_data.keys())[0]
+ data_helper.delete_object_data(policy_id=object_data[object_data_id].get('policy_id'), data_id=object_data_id)
+ new_object_data = data_helper.get_object_data(policy_id)
+ assert len(new_object_data[0]['data']) == 0
+
+
+def test_get_subject_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "subject-security-level",
+ "description": {"low": "", "medium": "", "high": ""},
+ }
+ subject_data = data_helper.add_subject_data(policy_id=policy_id, category_id=subject_category_id, value=value).get(
+ 'data')
+ subject_data_id = list(subject_data.keys())[0]
+ subject_data = data_helper.get_subject_data(policy_id, subject_data_id, subject_category_id)
+ assert subject_data
+ assert len(subject_data[0]['data']) == 1
+
+
+def test_get_subject_data_with_invalid_category_id(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "subject-security-level",
+ "description": {"low": "", "medium": "", "high": ""},
+ }
+ subject_data = data_helper.add_subject_data(policy_id=policy_id, category_id=subject_category_id, value=value).get(
+ 'data')
+ subject_data_id = list(subject_data.keys())[0]
+ found_subject_data = data_helper.get_subject_data(policy_id, subject_data_id, "invalid")
+ assert len(found_subject_data) == 0
+
+
+def test_add_subject_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "subject-security-level",
+ "description": {"low": "", "medium": "", "high": ""},
+ }
+ subject_data = data_helper.add_subject_data(policy_id=policy_id, category_id=subject_category_id, value=value).get(
+ 'data')
+ assert subject_data
+ subject_data_id = list(subject_data.keys())[0]
+ assert subject_data[subject_data_id].get('policy_id') == policy_id
+
+
+def test_add_subject_data_with_no_category_id(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "subject-security-level",
+ "description": {"low": "", "medium": "", "high": ""},
+ }
+ with pytest.raises(SubjectCategoryUnknown) as exception_info:
+ data_helper.add_subject_data(policy_id=policy_id, data_id=subject_category_id, value=value).get('data')
+ assert str(exception_info.value) == '400: Subject Category Unknown'
+
+
+def test_add_subject_data_duplicate(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "subject-security-level",
+ "description": {"low": "", "medium": "", "high": ""},
+ }
+ subject_data = data_helper.add_subject_data(policy_id=policy_id, category_id=subject_category_id, value=value).get(
+ 'data')
+
+ with pytest.raises(SubjectScopeExisting) as exception_info:
+ subject_data = data_helper.add_subject_data(policy_id=policy_id, category_id=subject_category_id,
+ value=value).get('data')
+ assert str(exception_info.value) == '409: Subject Scope Existing'
+
+
+def test_delete_subject_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "subject-security-level",
+ "description": {"low": "", "medium": "", "high": ""},
+ }
+ subject_data = data_helper.add_subject_data(policy_id=policy_id, category_id=subject_category_id, value=value).get(
+ 'data')
+ subject_data_id = list(subject_data.keys())[0]
+ data_helper.delete_subject_data(policy_id=subject_data[subject_data_id].get('policy_id'), data_id=subject_data_id)
+ new_subject_data = data_helper.get_subject_data(policy_id)
+ assert len(new_subject_data[0]['data']) == 0
+
+
+def test_get_actions(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "test_action",
+ "description": "test",
+ }
+ data_helper.add_action(policy_id=policy_id, value=value)
+ actions = data_helper.get_actions(policy_id, )
+ assert actions
+ assert len(actions) == 1
+ action_id = list(actions.keys())[0]
+ assert actions[action_id].get('policy_list')[0] == policy_id
+
+
+def test_add_action(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "test_action",
+ "description": "test",
+ }
+ action = data_helper.add_action(policy_id=policy_id, value=value)
+ assert action
+ action_id = list(action.keys())[0]
+ assert len(action[action_id].get('policy_list')) == 1
+
+
+def test_add_action_twice(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "test_action",
+ "description": "test",
+ }
+ data_helper.add_action(policy_id=policy_id, value=value)
+ with pytest.raises(PolicyExisting) as exception_info:
+ data_helper.add_action(policy_id=policy_id, value=value)
+ assert str(exception_info.value) == '409: Policy Already Exists'
+
+
+def test_add_action_blank_name(db):
+ policy_id = policies.mock_data.get_policy_id()
+ value = {
+ "name": "",
+ "description": "test",
+ }
+ with pytest.raises(PerimeterContentError) as exception_info:
+ data_helper.add_action(policy_id=policy_id, value=value)
+ assert str(exception_info.value) == '400: Perimeter content is invalid.'
+
+
+def test_add_action_with_name_space(db):
+ policy_id = policies.mock_data.get_policy_id()
+ value = {
+ "name": " ",
+ "description": "test",
+ }
+ with pytest.raises(PerimeterContentError) as exception_info:
+ data_helper.add_action(policy_id=policy_id, value=value)
+ assert str(exception_info.value) == '400: Perimeter content is invalid.'
+
+
+def test_add_action_multiple_times(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id1 = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ value = {
+ "name": "test_action",
+ "description": "test",
+ }
+ action = data_helper.add_action(policy_id=policy_id1, value=value)
+ logger.info("action : {}".format(action))
+ action_id = list(action.keys())[0]
+ perimeter_id = action[action_id].get('id')
+ assert action
+ value = {
+ "name": "test_action",
+ "description": "test",
+ "policy_list": ['policy_id_3', 'policy_id_4']
+ }
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id2 = mock_data.create_new_policy(
+ subject_category_name="subject_category2",
+ object_category_name="object_category2",
+ action_category_name="action_category2",
+ meta_rule_name="meta_rule_2",
+ model_name="model2")
+ action = data_helper.add_action(policy_id=policy_id2, perimeter_id=perimeter_id, value=value)
+ logger.info("action : {}".format(action))
+ assert action
+ action_id = list(action.keys())[0]
+ assert len(action[action_id].get('policy_list')) == 2
+
+
+def test_delete_action(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "test_action",
+ "description": "test",
+ }
+ action = data_helper.add_action(policy_id=policy_id, value=value)
+ action_id = list(action.keys())[0]
+ data_helper.delete_action(policy_id, action_id)
+ actions = data_helper.get_actions(policy_id, )
+ assert not actions
+
+
+def test_delete_action_with_invalid_perimeter_id(db):
+ policy_id = "invalid"
+ perimeter_id = "invalid"
+ with pytest.raises(PolicyUnknown) as exception_info:
+ data_helper.delete_action(policy_id, perimeter_id)
+ assert str(exception_info.value) == '400: Policy Unknown'
+
+
+def test_get_objects(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "test_object",
+ "description": "test",
+ }
+ data_helper.add_object(policy_id=policy_id, value=value)
+ objects = data_helper.get_objects(policy_id, )
+ assert objects
+ assert len(objects) == 1
+ object_id = list(objects.keys())[0]
+ assert objects[object_id].get('policy_list')[0] == policy_id
+
+
+def test_add_object_with_same_policy_twice(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "test_object",
+ "description": "test",
+ }
+ added_object = data_helper.add_object(policy_id=policy_id, value=value)
+ assert added_object
+ object_id = list(added_object.keys())[0]
+ assert len(added_object[object_id].get('policy_list')) == 1
+
+ with pytest.raises(PolicyExisting) as exception_info:
+ data_helper.add_object(policy_id=policy_id, value=value)
+ assert str(exception_info.value) == '409: Policy Already Exists'
+
+
+def test_add_objects_multiple_times(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ value = {
+ "name": "test_object",
+ "description": "test",
+ }
+ added_object = data_helper.add_object(policy_id=policy_id, value=value)
+ object_id = list(added_object.keys())[0]
+ perimeter_id = added_object[object_id].get('id')
+ assert added_object
+ value = {
+ "name": "test_object",
+ "description": "test",
+ }
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category2",
+ object_category_name="object_category2",
+ action_category_name="action_category2",
+ meta_rule_name="meta_rule_2",
+ model_name="model2")
+ added_object = data_helper.add_object(policy_id=policy_id, perimeter_id=perimeter_id, value=value)
+ assert added_object
+ object_id = list(added_object.keys())[0]
+ assert len(added_object[object_id].get('policy_list')) == 2
+
+
+def test_delete_object(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "test_object",
+ "description": "test",
+ }
+ added_object = data_helper.add_object(policy_id=policy_id, value=value)
+ object_id = list(added_object.keys())[0]
+ data_helper.delete_object(policy_id, object_id)
+ objects = data_helper.get_objects(policy_id, )
+ assert not objects
+
+
+def test_delete_object_with_invalid_perimeter_id(db):
+ policy_id = "invalid"
+ perimeter_id = "invalid"
+ with pytest.raises(PolicyUnknown) as exception_info:
+ data_helper.delete_object(policy_id, perimeter_id)
+ assert str(exception_info.value) == '400: Policy Unknown'
+
+
+def test_get_subjects(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "testuser",
+ "description": "test",
+ }
+ data_helper.add_subject(policy_id=policy_id, value=value)
+ subjects = data_helper.get_subjects(policy_id=policy_id)
+ assert subjects
+ assert len(subjects) == 1
+ subject_id = list(subjects.keys())[0]
+ assert subjects[subject_id].get('policy_list')[0] == policy_id
+
+
+def test_get_subjects_with_invalid_policy_id(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "testuser",
+ "description": "test",
+ }
+ data_helper.add_subject(policy_id=policy_id, value=value)
+ with pytest.raises(PolicyUnknown) as exception_info:
+ data_helper.get_subjects(policy_id="invalid")
+ assert str(exception_info.value) == '400: Policy Unknown'
+
+
+def test_add_subject_with_same_policy_twice(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "testuser",
+ "description": "test",
+ }
+ subject = data_helper.add_subject(policy_id=policy_id, value=value)
+ assert subject
+ subject_id = list(subject.keys())[0]
+ assert len(subject[subject_id].get('policy_list')) == 1
+ with pytest.raises(PolicyExisting) as exception_info:
+ data_helper.add_subject(policy_id=policy_id, value=value)
+ assert str(exception_info.value) == '409: Policy Already Exists'
+
+
+def test_add_subjects_multiple_times(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ value = {
+ "name": "testuser",
+ "description": "test",
+ }
+ subject = data_helper.add_subject(policy_id=policy_id, value=value)
+ subject_id = list(subject.keys())[0]
+ perimeter_id = subject[subject_id].get('id')
+ assert subject
+ value = {
+ "name": "testuser",
+ "description": "test",
+ }
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category2",
+ object_category_name="object_category2",
+ action_category_name="action_category2",
+ meta_rule_name="meta_rule_2",
+ model_name="model2")
+ subject = data_helper.add_subject(policy_id=policy_id, perimeter_id=perimeter_id, value=value)
+ assert subject
+ subject_id = list(subject.keys())[0]
+ assert len(subject[subject_id].get('policy_list')) == 2
+
+
+def test_delete_subject(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ value = {
+ "name": "testuser",
+ "description": "test",
+ }
+ subject = data_helper.add_subject(policy_id=policy_id, value=value)
+ subject_id = list(subject.keys())[0]
+ data_helper.delete_subject(policy_id, subject_id)
+ subjects = data_helper.get_subjects(policy_id, )
+ assert not subjects
+
+
+def test_delete_subject_with_invalid_perimeter_id(db):
+ policy_id = "invalid"
+ perimeter_id = "invalid"
+ with pytest.raises(PolicyUnknown) as exception_info:
+ data_helper.delete_subject(policy_id, perimeter_id)
+ assert str(exception_info.value) == '400: Policy Unknown'
+
+
+def test_delete_subject_with_assignment(db):
+
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category"+uuid4().hex,
+ object_category_name="object_category"+uuid4().hex,
+ action_category_name="action_category"+uuid4().hex,
+ meta_rule_name="meta_rule_"+uuid4().hex)
+
+ subject_id = mock_data.create_subject(policy_id)
+ data_id = mock_data.create_subject_data(policy_id=policy_id, category_id=subject_category_id)
+ assignment_helper.add_subject_assignment(policy_id, subject_id, subject_category_id, data_id)
+
+ with pytest.raises(DeletePerimeterWithAssignment) as exception_info:
+ data_helper.delete_subject(policy_id, subject_id)
+ assert '400: Perimeter With Assignment Error' == str(exception_info.value)
+
+
+def test_delete_object_with_assignment(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category" + uuid4().hex,
+ object_category_name="object_category" + uuid4().hex,
+ action_category_name="action_category" + uuid4().hex,
+ meta_rule_name="meta_rule_" + uuid4().hex)
+
+ object_id = mock_data.create_object(policy_id)
+ data_id = mock_data.create_object_data(policy_id=policy_id, category_id=object_category_id)
+ assignment_helper.add_object_assignment(policy_id, object_id, object_category_id, data_id)
+
+ with pytest.raises(DeletePerimeterWithAssignment) as exception_info:
+ data_helper.delete_object(policy_id, object_id)
+ assert '400: Perimeter With Assignment Error' == str(exception_info.value)
+
+def test_delete_action_with_assignment(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category" + uuid4().hex,
+ object_category_name="object_category" + uuid4().hex,
+ action_category_name="action_category" + uuid4().hex,
+ meta_rule_name="meta_rule_" + uuid4().hex)
+
+ action_id = mock_data.create_action(policy_id)
+ data_id = mock_data.create_action_data(policy_id=policy_id, category_id=action_category_id)
+ assignment_helper.add_action_assignment(policy_id, action_id, action_category_id, data_id)
+
+ with pytest.raises(DeletePerimeterWithAssignment) as exception_info:
+ data_helper.delete_action(policy_id, action_id)
+ assert '400: Perimeter With Assignment Error' == str(exception_info.value)
+
+
+def test_get_available_metadata(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1")
+ metadata = data_helper.get_available_metadata(policy_id=policy_id)
+ assert metadata
+ assert metadata['object'][0] == object_category_id
+ assert metadata['subject'][0] == subject_category_id
+ assert metadata['action'][0] == action_category_id
+
+
+def test_get_available_metadata_with_invalid_policy_id(db):
+ with pytest.raises(PolicyUnknown) as exception_info:
+ data_helper.get_available_metadata(policy_id='invalid')
+ assert '400: Policy Unknown' == str(exception_info.value)
diff --git a/old/python_moondb/tests/unit_python/policies/test_policies.py b/old/python_moondb/tests/unit_python/policies/test_policies.py
new file mode 100755
index 00000000..b2394203
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/policies/test_policies.py
@@ -0,0 +1,643 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import pytest
+import helpers.mock_data as mock_data
+import helpers.policy_helper as policy_helper
+import helpers.model_helper as model_helper
+import helpers.model_helper as model_helper
+from python_moonutilities.exceptions import *
+import helpers.pdp_helper as pdp_helper
+import helpers.data_helper as data_helper
+import helpers.assignment_helper as assignment_helper
+from uuid import uuid4
+
+
+def test_get_policies(db):
+ policies = policy_helper.get_policies()
+ assert isinstance(policies, dict)
+ assert not policies
+
+
+def test_add_policies(db):
+ model = model_helper.add_model(model_id=uuid4().hex)
+ model_id = next(iter(model))
+ value = {
+ "name": "test_policy",
+ "model_id": model_id,
+ "genre": "authz",
+ "description": "test",
+ }
+ policies = policy_helper.add_policies(value=value)
+ assert isinstance(policies, dict)
+ assert policies
+ assert len(policies.keys()) == 1
+ policy_id = list(policies.keys())[0]
+ for key in ("genre", "name", "model_id", "description"):
+ assert key in policies[policy_id]
+ assert policies[policy_id][key] == value[key]
+
+
+def test_add_policies_twice_with_same_id(db):
+ policy_id = 'policy_id_1'
+ model = model_helper.add_model(model_id=uuid4().hex)
+ model_id = next(iter(model))
+ value = {
+ "name": "test_policy",
+ "model_id": model_id,
+ "genre": "authz",
+ "description": "test",
+ }
+ policy_helper.add_policies(policy_id, value)
+ with pytest.raises(PolicyExisting) as exception_info:
+ policy_helper.add_policies(policy_id, value)
+ assert str(exception_info.value) == '409: Policy Already Exists'
+
+
+def test_add_policies_twice_with_same_name(db):
+ model = model_helper.add_model(model_id=uuid4().hex)
+ model_id = next(iter(model))
+ policy_name=uuid4().hex
+ value = {
+ "name": policy_name,
+ "model_id": model_id,
+ "genre": "authz",
+ "description": "test",
+ }
+ policy_helper.add_policies(value=value)
+ with pytest.raises(Exception) as exception_info:
+ policy_helper.add_policies(value=value)
+ assert str(exception_info.value) == '409: Policy Already Exists'
+ assert str(exception_info.value.description)== 'Policy name Existed'
+
+
+def test_delete_policies(db):
+ model = model_helper.add_model(model_id=uuid4().hex)
+ model_id = next(iter(model))
+ policy_name1 = uuid4().hex
+ value = {
+ "name": policy_name1,
+ "model_id": model_id,
+ "genre": "authz",
+ "description": "test",
+ }
+ policies = policy_helper.add_policies(value=value)
+ policy_id1 = list(policies.keys())[0]
+ policy_name2 = uuid4().hex
+ value = {
+ "name": policy_name2,
+ "model_id": model_id,
+ "genre": "authz",
+ "description": "test",
+ }
+ policies = policy_helper.add_policies(value=value)
+ policy_id2 = list(policies.keys())[0]
+ assert policy_id1 != policy_id2
+ policy_helper.delete_policies(policy_id1)
+ policies = policy_helper.get_policies()
+ assert policy_id1 not in policies
+
+
+def test_delete_policies_with_invalid_id(db):
+ policy_id = 'policy_id_1'
+ with pytest.raises(PolicyUnknown) as exception_info:
+ policy_helper.delete_policies(policy_id)
+ # assert str(exception_info.value) == '400: Policy Unknown'
+
+
+def test_update_policy(db):
+ policies = policy_helper.add_policies()
+ policy_id = list(policies.keys())[0]
+ value = {
+ "name": "test_policy4",
+ "model_id": policies[policy_id]['model_id'],
+ "genre": "authz",
+ "description": "test-3",
+ }
+ updated_policy = policy_helper.update_policy(policy_id, value)
+ assert updated_policy
+ for key in ("genre", "name", "model_id", "description"):
+ assert key in updated_policy[policy_id]
+ assert updated_policy[policy_id][key] == value[key]
+
+
+def test_update_policy_name_with_existed_one(db):
+ policies = policy_helper.add_policies()
+ policy_id1 = list(policies.keys())[0]
+ policy_name = uuid4().hex
+ value = {
+ "name": policy_name,
+ "model_id": policies[policy_id1]['model_id'],
+ "genre": "authz",
+ "description": "test-3",
+ }
+ policy_helper.add_policies(value=value)
+ with pytest.raises(PolicyExisting) as exception_info:
+ policy_helper.update_policy(policy_id=policy_id1,value=value)
+
+ assert str(exception_info.value) == '409: Policy Already Exists'
+ assert str(exception_info.value.description)== 'Policy name Existed'
+
+
+def test_update_policy_with_invalid_id(db):
+ policy_id = 'invalid-id'
+ value = {
+ "name": "test_policy4",
+ "model_id": "",
+ "genre": "authz",
+ "description": "test-3",
+ }
+ with pytest.raises(PolicyUnknown) as exception_info:
+ policy_helper.update_policy(policy_id, value)
+ assert str(exception_info.value) == '400: Policy Unknown'
+
+
+def test_get_policy_from_meta_rules(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ security_pipeline = [policy_id]
+ pdp_obj = mock_data.create_pdp(security_pipeline)
+ pdp_helper.add_pdp(value=pdp_obj)
+ matched_policy_id = policy_helper.get_policy_from_meta_rules(meta_rule_id)
+ assert matched_policy_id
+ assert policy_id == matched_policy_id
+
+
+def test_get_policy_from_meta_rules_with_no_policy_ids(db):
+ meta_rule_id = 'meta_rule_id'
+ value = {
+ "name": "test_pdp",
+ "security_pipeline": [],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+ pdp_helper.add_pdp(value=value)
+ matched_policy_id = policy_helper.get_policy_from_meta_rules(meta_rule_id)
+ assert not matched_policy_id
+
+
+def test_get_rules(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category12",
+ object_category_name="object_category12",
+ action_category_name="action_category12",
+ meta_rule_name="meta_rule_12",
+ model_name="model12")
+
+ policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id)
+
+ policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id)
+ rules = policy_helper.get_rules(policy_id=policy_id, meta_rule_id=meta_rule_id)
+ assert isinstance(rules, dict)
+ assert rules
+ obj = rules.get('rules')
+ assert len(obj) == 2
+
+
+def test_get_rules_with_invalid_policy_id_failure(db):
+ rules = policy_helper.get_rules("invalid_policy_id", "meta_rule_id")
+ assert not rules.get('meta_rule-id')
+ assert len(rules.get('rules')) == 0
+
+
+def test_add_rule_existing(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ subject_data_id = mock_data.create_subject_data(policy_id=policy_id,
+ category_id=subject_category_id)
+ object_data_id = mock_data.create_object_data(policy_id=policy_id,
+ category_id=object_category_id)
+ action_data_id = mock_data.create_action_data(policy_id=policy_id,
+ category_id=action_category_id)
+
+ value = {
+ "rule": (subject_data_id, object_data_id, action_data_id),
+ "instructions": ({"decision": "grant"}),
+ "enabled": "",
+ }
+
+ rules = policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value)
+ assert rules
+ assert len(rules) == 1
+ assert isinstance(rules, dict)
+ rule_id = list(rules.keys())[0]
+ for key in ("rule", "instructions", "enabled"):
+ assert key in rules[rule_id]
+ assert rules[rule_id][key] == value[key]
+
+ with pytest.raises(RuleExisting) as exception_info:
+ policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value)
+ assert str(exception_info.value) == '409: Rule Existing'
+
+
+def test_check_existing_rule_valid_request(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ subject_data_id = mock_data.create_subject_data(policy_id=policy_id,
+ category_id=subject_category_id)
+ object_data_id = mock_data.create_object_data(policy_id=policy_id,
+ category_id=object_category_id)
+ action_data_id = mock_data.create_action_data(policy_id=policy_id,
+ category_id=action_category_id)
+ value = {
+ "rule": (subject_data_id, object_data_id, action_data_id),
+ "instructions": ({"decision": "grant"}),
+ "enabled": "",
+ }
+
+ rules = policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value)
+ assert rules
+ assert len(rules) == 1
+ assert isinstance(rules, dict)
+ rule_id = list(rules.keys())[0]
+ for key in ("rule", "instructions", "enabled"):
+ assert key in rules[rule_id]
+ assert rules[rule_id][key] == value[key]
+
+ with pytest.raises(RuleExisting) as exception_info:
+ policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value)
+ assert str(exception_info.value) == '409: Rule Existing'
+
+
+def test_check_existing_rule_valid_multiple__data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ subject_data_id1 = mock_data.create_subject_data(policy_id=policy_id,
+ category_id=subject_category_id)
+ subject_data_id2 = mock_data.create_subject_data(policy_id=policy_id,
+ category_id=subject_category_id)
+ object_data_id1 = mock_data.create_object_data(policy_id=policy_id,
+ category_id=object_category_id)
+ object_data_id2 = mock_data.create_object_data(policy_id=policy_id,
+ category_id=object_category_id)
+ action_data_id1 = mock_data.create_action_data(policy_id=policy_id,
+ category_id=action_category_id)
+ action_data_id2 = mock_data.create_action_data(policy_id=policy_id,
+ category_id=action_category_id)
+ value = {
+ "rule": (
+ subject_data_id1, object_data_id2, action_data_id1),
+ "instructions": ({"decision": "grant"}),
+ "enabled": "",
+ }
+
+ rules = policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value)
+ assert rules
+ assert len(rules) == 1
+ assert isinstance(rules, dict)
+ rule_id = list(rules.keys())[0]
+ for key in ("rule", "instructions", "enabled"):
+ assert key in rules[rule_id]
+ assert rules[rule_id][key] == value[key]
+
+ with pytest.raises(RuleExisting) as exception_info:
+ policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value)
+ assert str(exception_info.value) == '409: Rule Existing'
+
+
+def test_check_existing_rule_missing_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ subject_data_id = mock_data.create_subject_data(policy_id=policy_id,
+ category_id=subject_category_id)
+ object_data_id = mock_data.create_object_data(policy_id=policy_id,
+ category_id=object_category_id)
+ action_data_id = mock_data.create_action_data(policy_id=policy_id,
+ category_id=action_category_id)
+ value = {
+ "rule": (object_data_id, action_data_id),
+ "instructions": ({"decision": "grant"}),
+ "enabled": "",
+ }
+
+ with pytest.raises(RuleContentError) as exception_info:
+ policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value)
+ assert str(exception_info.value) == '400: Rule Error'
+ assert exception_info.value.description== "Missing Data"
+
+
+def test_check_existing_rule_meta_rule_missing_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ subject_data_id = mock_data.create_subject_data(policy_id=policy_id,
+ category_id=subject_category_id)
+ object_data_id = mock_data.create_object_data(policy_id=policy_id,
+ category_id=object_category_id)
+ action_data_id = mock_data.create_action_data(policy_id=policy_id,
+ category_id=action_category_id)
+ value = {
+ "rule": (subject_data_id, object_data_id, action_data_id, action_data_id),
+ "instructions": ({"decision": "grant"}),
+ "enabled": "",
+ }
+
+ with pytest.raises(MetaRuleContentError) as exception_info:
+ policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value)
+ assert str(exception_info.value) == '400: Meta Rule Error'
+ assert exception_info.value.description == "Missing Data"
+
+
+def test_check_existing_rule_invalid_data_id_order(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ subject_data_id = mock_data.create_subject_data(policy_id=policy_id,
+ category_id=subject_category_id)
+ object_data_id = mock_data.create_object_data(policy_id=policy_id,
+ category_id=object_category_id)
+ action_data_id = mock_data.create_action_data(policy_id=policy_id,
+ category_id=action_category_id)
+ value = {
+ "rule": (object_data_id, action_data_id, subject_data_id),
+ "instructions": ({"decision": "grant"}),
+ "enabled": "",
+ }
+
+ with pytest.raises(RuleContentError) as exception_info:
+ policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value)
+ assert str(exception_info.value) == '400: Rule Error'
+ assert "Missing Subject_category" in exception_info.value.description
+
+
+def test_check_existing_rule_invalid_data_id_order_scenrio_2(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ subject_data_id = mock_data.create_subject_data(policy_id=policy_id,
+ category_id=subject_category_id)
+ object_data_id = mock_data.create_object_data(policy_id=policy_id,
+ category_id=object_category_id)
+ action_data_id = mock_data.create_action_data(policy_id=policy_id,
+ category_id=action_category_id)
+ value = {
+ "rule": (subject_data_id, action_data_id, object_data_id),
+ "instructions": ({"decision": "grant"}),
+ "enabled": "",
+ }
+
+ with pytest.raises(RuleContentError) as exception_info:
+ policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value)
+ assert str(exception_info.value) == '400: Rule Error'
+ assert "Missing Object_category" in exception_info.value.description
+
+
+def test_check_existing_rule_wrong_subject_data_id(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ subject_data_id = mock_data.create_subject_data(policy_id=policy_id,
+ category_id=subject_category_id)
+ object_data_id = mock_data.create_object_data(policy_id=policy_id,
+ category_id=object_category_id)
+ action_data_id = mock_data.create_action_data(policy_id=policy_id,
+ category_id=action_category_id)
+ value = {
+ "rule": (uuid4().hex, object_data_id, action_data_id),
+ "instructions": ({"decision": "grant"}),
+ "enabled": "",
+ }
+
+ with pytest.raises(RuleContentError) as exception_info:
+ policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value)
+ assert str(exception_info.value) == '400: Rule Error'
+ assert "Missing Subject_category" in exception_info.value.description
+
+
+def test_check_existing_rule_wrong_object_data_id(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ subject_data_id = mock_data.create_subject_data(policy_id=policy_id,
+ category_id=subject_category_id)
+ object_data_id = mock_data.create_object_data(policy_id=policy_id,
+ category_id=object_category_id)
+ action_data_id = mock_data.create_action_data(policy_id=policy_id,
+ category_id=action_category_id)
+ value = {
+ "rule": (subject_data_id, uuid4().hex, action_data_id),
+ "instructions": ({"decision": "grant"}),
+ "enabled": "",
+ }
+
+ with pytest.raises(RuleContentError) as exception_info:
+ policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value)
+ assert str(exception_info.value) == '400: Rule Error'
+ assert "Missing Object_category" in exception_info.value.description
+
+
+def test_check_existing_rule_wrong_action_data_id(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ subject_data_id = mock_data.create_subject_data(policy_id=policy_id,
+ category_id=subject_category_id)
+ object_data_id = mock_data.create_object_data(policy_id=policy_id,
+ category_id=object_category_id)
+ action_data_id = mock_data.create_action_data(policy_id=policy_id,
+ category_id=action_category_id)
+ value = {
+ "rule": (subject_data_id, object_data_id, uuid4().hex),
+ "instructions": ({"decision": "grant"}),
+ "enabled": "",
+ }
+
+ with pytest.raises(RuleContentError) as exception_info:
+ policy_helper.add_rule(policy_id=policy_id, meta_rule_id=meta_rule_id, value=value)
+ assert str(exception_info.value) == '400: Rule Error'
+ assert "Missing Action_category" in exception_info.value.description
+
+
+def test_delete_rule(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+
+ rules = policy_helper.add_rule(policy_id, meta_rule_id)
+ rule_id = list(rules.keys())[0]
+ policy_helper.delete_rule(policy_id, rule_id)
+ rules = policy_helper.get_rules(policy_id, meta_rule_id)
+ assert not rules.get('rules')
+
+
+def test_delete_policies_with_pdp(db):
+ policies = policy_helper.add_policies()
+ policy_id1 = list(policies.keys())[0]
+ pdp_id = "pdp_id1"
+ value = {
+ "name": "test_pdp",
+ "security_pipeline": [policy_id1],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+ pdp_helper.add_pdp(pdp_id=pdp_id, value=value)
+ with pytest.raises(DeletePolicyWithPdp) as exception_info:
+ policy_helper.delete_policies(policy_id1)
+ assert str(exception_info.value) == '400: Policy With PDP Error'
+ assert 'Cannot delete policy with pdp' == exception_info.value.description
+
+
+def test_delete_policies_with_subject_perimeter(db):
+ policies = policy_helper.add_policies()
+ policy_id1 = list(policies.keys())[0]
+
+ value = {
+ "name": "testuser",
+ "security_pipeline": [policy_id1],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+ data_helper.add_subject(policy_id=policy_id1, value=value)
+ with pytest.raises(DeletePolicyWithPerimeter) as exception_info:
+ policy_helper.delete_policies(policy_id1)
+ assert str(exception_info.value) == '400: Policy With Perimeter Error'
+ assert 'Cannot delete policy with perimeter'== exception_info.value.description
+
+
+def test_delete_policies_with_object_perimeter(db):
+ policies = policy_helper.add_policies()
+ policy_id1 = list(policies.keys())[0]
+
+ value = {
+ "name": "test_obj",
+ "security_pipeline": [policy_id1],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+ data_helper.add_object(policy_id=policy_id1, value=value)
+ with pytest.raises(DeletePolicyWithPerimeter) as exception_info:
+ policy_helper.delete_policies(policy_id1)
+ assert str(exception_info.value) == '400: Policy With Perimeter Error'
+ assert 'Cannot delete policy with perimeter'== exception_info.value.description
+
+
+def test_delete_policies_with_action_perimeter(db):
+ policies = policy_helper.add_policies()
+ policy_id1 = list(policies.keys())[0]
+
+ value = {
+ "name": "test_act",
+ "security_pipeline": [policy_id1],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+ data_helper.add_action(policy_id=policy_id1, value=value)
+ with pytest.raises(DeletePolicyWithPerimeter) as exception_info:
+ policy_helper.delete_policies(policy_id1)
+ assert '400: Policy With Perimeter Error' == str(exception_info.value)
+
+
+def test_delete_policies_with_subject_assignment(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+
+ subject_id = mock_data.create_subject(policy_id)
+ data_id = mock_data.create_subject_data(policy_id=policy_id, category_id=subject_category_id)
+ assignment_helper.add_subject_assignment(policy_id, subject_id, subject_category_id, data_id)
+
+ with pytest.raises(DeletePolicyWithPerimeter) as exception_info:
+ policy_helper.delete_policies(policy_id)
+
+ assert '400: Policy With Perimeter Error' == str(exception_info.value)
+
+
+def test_delete_policies_with_object_assignment(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+
+ object_id = mock_data.create_object(policy_id)
+ data_id = mock_data.create_object_data(policy_id=policy_id, category_id=object_category_id)
+ assignment_helper.add_object_assignment(policy_id, object_id, object_category_id, data_id)
+
+ with pytest.raises(DeletePolicyWithPerimeter) as exception_info:
+ policy_helper.delete_policies(policy_id)
+ assert '400: Policy With Perimeter Error' == str(exception_info.value)
+
+
+def test_delete_policies_with_action_assignment(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+
+ action_id = mock_data.create_action(policy_id)
+ data_id = mock_data.create_action_data(policy_id=policy_id, category_id=action_category_id)
+ assignment_helper.add_action_assignment(policy_id, action_id, action_category_id, data_id)
+
+ with pytest.raises(DeletePolicyWithPerimeter) as exception_info:
+ policy_helper.delete_policies(policy_id)
+ assert '400: Policy With Perimeter Error' == str(exception_info.value)
+
+
+def test_delete_policies_with_subject_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+
+ data_id = mock_data.create_subject_data(policy_id=policy_id, category_id=subject_category_id)
+
+ with pytest.raises(DeletePolicyWithData) as exception_info:
+ policy_helper.delete_policies(policy_id)
+
+ assert '400: Policy With Data Error' == str(exception_info.value)
+
+
+def test_delete_policies_with_object_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+
+ data_id = mock_data.create_object_data(policy_id=policy_id, category_id=object_category_id)
+
+ with pytest.raises(DeletePolicyWithData) as exception_info:
+ policy_helper.delete_policies(policy_id)
+ assert '400: Policy With Data Error' == str(exception_info.value)
+
+
+def test_delete_policies_with_action_data(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+
+ data_id = mock_data.create_action_data(policy_id=policy_id, category_id=action_category_id)
+
+ with pytest.raises(DeletePolicyWithData) as exception_info:
+ policy_helper.delete_policies(policy_id)
+ assert '400: Policy With Data Error' == str(exception_info.value)
+
+
+def test_delete_policies_with_rule(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy()
+
+ rules = policy_helper.add_rule(policy_id, meta_rule_id)
+
+ with pytest.raises(DeletePolicyWithRules) as exception_info:
+ policy_helper.delete_policies(policy_id)
+ assert '400: Policy With Rule Error' == str(exception_info.value)
diff --git a/old/python_moondb/tests/unit_python/requirements.txt b/old/python_moondb/tests/unit_python/requirements.txt
new file mode 100644
index 00000000..aea8e3d5
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/requirements.txt
@@ -0,0 +1,4 @@
+sqlalchemy
+pymysql
+requests_mock
+python_moonutilities==1.4.20 \ No newline at end of file
diff --git a/old/python_moondb/tests/unit_python/test_keystone.py b/old/python_moondb/tests/unit_python/test_keystone.py
new file mode 100644
index 00000000..134bec0d
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/test_keystone.py
@@ -0,0 +1,53 @@
+import pytest
+
+
+def create_project(tenant_dict):
+ from python_moondb.core import KeystoneManager
+ return KeystoneManager.create_project(tenant_dict)
+
+
+def list_projects():
+ from python_moondb.core import KeystoneManager
+ return KeystoneManager.list_projects()
+
+
+def create_user(subject_dict):
+ from python_moondb.core import KeystoneManager
+ return KeystoneManager.create_user(subject_dict)
+
+
+def test_create_project():
+ tenant_dict = {
+ "description": "test_project",
+ "domain_id": ['domain_id_1'],
+ "enabled": True,
+ "is_domain": False,
+ "name": 'project_1'
+ }
+ project = create_project(tenant_dict)
+ assert project
+ assert project.get('name') == tenant_dict.get('name')
+
+
+def test_create_project_without_name():
+ tenant_dict = {
+ "description": "test_project",
+ "domain_id": ['domain_id_1'],
+ "enabled": True,
+ "is_domain": False,
+ }
+ with pytest.raises(Exception) as exception_info:
+ create_project(tenant_dict)
+ assert '400: Keystone project error' == str(exception_info.value)
+
+
+def test_create_user():
+ subject_dict = {
+ "password": "password",
+ "domain_id": ['domain_id_1'],
+ "enabled": True,
+ "project": 'test_project',
+ "name": 'user_id_1'
+ }
+ user = create_user(subject_dict)
+ assert user
diff --git a/old/python_moondb/tests/unit_python/test_pdp.py b/old/python_moondb/tests/unit_python/test_pdp.py
new file mode 100755
index 00000000..4d245e4d
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/test_pdp.py
@@ -0,0 +1,149 @@
+import pytest
+import helpers.mock_data as mock_data
+import helpers.pdp_helper as pdp_helper
+
+
+def test_update_pdp(db):
+ pdp_id = "pdp_id1"
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ value = {
+ "name": "test_pdp",
+ "security_pipeline": [policy_id],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+ pdp_helper.add_pdp(pdp_id, value)
+ pdp = pdp_helper.update_pdp(pdp_id, value)
+ assert pdp
+
+
+def test_update_pdp_with_invalid_id(db):
+ pdp_id = "pdp_id1"
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ value = {
+ "name": "test_pdp",
+ "security_pipeline": [policy_id],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+ with pytest.raises(Exception) as exception_info:
+ pdp_helper.update_pdp(pdp_id, value)
+ assert str(exception_info.value) == '400: Pdp Unknown'
+
+
+def test_delete_pdp(db):
+ pdp_id = "pdp_id1"
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ value = {
+ "name": "test_pdp",
+ "security_pipeline": [policy_id],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+ pdp_helper.add_pdp(pdp_id, value)
+ pdp_helper.delete_pdp(pdp_id)
+ assert len(pdp_helper.get_pdp(pdp_id)) == 0
+
+
+def test_delete_pdp_with_invalid_id(db):
+ pdp_id = "pdp_id1"
+ with pytest.raises(Exception) as exception_info:
+ pdp_helper.delete_pdp(pdp_id)
+ assert str(exception_info.value) == '400: Pdp Unknown'
+
+
+def test_add_pdp(db):
+ pdp_id = "pdp_id1"
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ value = {
+ "name": "test_pdp",
+ "security_pipeline": [policy_id],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+ pdp = pdp_helper.add_pdp(pdp_id, value)
+ assert pdp
+
+
+def test_add_pdp_twice_with_same_id(db):
+ pdp_id = "pdp_id1"
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ value = {
+ "name": "test_pdp",
+ "security_pipeline": [policy_id],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+ pdp_helper.add_pdp(pdp_id, value)
+ with pytest.raises(Exception) as exception_info:
+ pdp_helper.add_pdp(pdp_id, value)
+ assert str(exception_info.value) == '409: Pdp Error'
+
+
+def test_add_pdp_twice_with_same_name(db):
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ value = {
+ "name": "test_pdp",
+ "security_pipeline": [policy_id],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+ pdp_helper.add_pdp(value=value)
+ with pytest.raises(Exception) as exception_info:
+ pdp_helper.add_pdp(value=value)
+ assert str(exception_info.value) == '409: Pdp Error'
+
+
+def test_get_pdp(db):
+ pdp_id = "pdp_id1"
+ subject_category_id, object_category_id, action_category_id, meta_rule_id, policy_id = mock_data.create_new_policy(
+ subject_category_name="subject_category1",
+ object_category_name="object_category1",
+ action_category_name="action_category1",
+ meta_rule_name="meta_rule_1",
+ model_name="model1")
+ value = {
+ "name": "test_pdp",
+ "security_pipeline": [policy_id],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+ pdp_helper.add_pdp(pdp_id, value)
+ pdp = pdp_helper.get_pdp(pdp_id)
+ assert len(pdp) == 1
+
+
+def test_get_pdp_with_invalid_id(db):
+ pdp_id = "invalid"
+ pdp = pdp_helper.get_pdp(pdp_id)
+ assert len(pdp) == 0
diff --git a/old/python_moondb/tests/unit_python/utilities.py b/old/python_moondb/tests/unit_python/utilities.py
new file mode 100644
index 00000000..1d79d890
--- /dev/null
+++ b/old/python_moondb/tests/unit_python/utilities.py
@@ -0,0 +1,136 @@
+import base64
+import json
+
+
+CONF = {
+ "openstack": {
+ "keystone": {
+ "url": "http://keystone:5000/v3",
+ "user": "admin",
+ "check_token": False,
+ "password": "p4ssw0rd",
+ "domain": "default",
+ "certificate": False,
+ "project": "admin"
+ }
+ },
+ "components": {
+ "wrapper": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_wrapper:v4.3",
+ "timeout": 5,
+ "hostname": "wrapper"
+ },
+ "manager": {
+ "bind": "0.0.0.0",
+ "port": 8082,
+ "container": "wukongsun/moon_manager:v4.3",
+ "hostname": "manager"
+ },
+ "port_start": 31001,
+ "orchestrator": {
+ "bind": "0.0.0.0",
+ "port": 8083,
+ "container": "wukongsun/moon_orchestrator:v4.3",
+ "hostname": "interface"
+ },
+ "interface": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_interface:v4.3",
+ "hostname": "interface"
+ }
+ },
+ "plugins": {
+ "session": {
+ "port": 8082,
+ "container": "asteroide/session:latest"
+ },
+ "authz": {
+ "port": 8081,
+ "container": "wukongsun/moon_authz:v4.3"
+ }
+ },
+ "logging": {
+ "handlers": {
+ "file": {
+ "filename": "/tmp/moon.log",
+ "class": "logging.handlers.RotatingFileHandler",
+ "level": "DEBUG",
+ "formatter": "custom",
+ "backupCount": 3,
+ "maxBytes": 1048576
+ },
+ "console": {
+ "class": "logging.StreamHandler",
+ "formatter": "brief",
+ "level": "INFO",
+ "stream": "ext://sys.stdout"
+ }
+ },
+ "formatters": {
+ "brief": {
+ "format": "%(levelname)s %(name)s %(message)-30s"
+ },
+ "custom": {
+ "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s"
+ }
+ },
+ "root": {
+ "handlers": [
+ "console"
+ ],
+ "level": "ERROR"
+ },
+ "version": 1,
+ "loggers": {
+ "moon": {
+ "handlers": [
+ "console",
+ "file"
+ ],
+ "propagate": False,
+ "level": "DEBUG"
+ }
+ }
+ },
+ "slave": {
+ "name": None,
+ "master": {
+ "url": None,
+ "login": None,
+ "password": None
+ }
+ },
+ "docker": {
+ "url": "tcp://172.88.88.1:2376",
+ "network": "moon"
+ },
+ "database": {
+ "url": "sqlite:///database.db",
+ # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon",
+ "driver": "sql"
+ },
+ "messenger": {
+ "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon"
+ }
+}
+
+
+def get_b64_conf(component=None):
+ if component == "components":
+ return base64.b64encode(
+ json.dumps(CONF["components"]).encode('utf-8')+b"\n").decode('utf-8')
+ elif component in CONF:
+ return base64.b64encode(
+ json.dumps(
+ CONF[component]).encode('utf-8')+b"\n").decode('utf-8')
+ elif not component:
+ return base64.b64encode(
+ json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8')
+ elif "/" in component:
+ key1, _, key2 = component.partition("/")
+ return base64.b64encode(
+ json.dumps(
+ CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8')
diff --git a/old/python_moonutilities/.gitignore b/old/python_moonutilities/.gitignore
new file mode 100644
index 00000000..7bff7318
--- /dev/null
+++ b/old/python_moonutilities/.gitignore
@@ -0,0 +1,105 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+
diff --git a/old/python_moonutilities/Changelog b/old/python_moonutilities/Changelog
new file mode 100644
index 00000000..d001c892
--- /dev/null
+++ b/old/python_moonutilities/Changelog
@@ -0,0 +1,157 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+CHANGES
+=======
+
+0.1.0
+-----
+- First version of the moon_utilities library.
+
+1.0.0
+-----
+- First public version of the moon_utilities library.
+
+1.0.1
+-----
+- Update setup.py to force the installation of requirements.
+
+1.0.2
+-----
+- Test PyPi upload
+
+1.1.0
+-----
+- Add functions to get configuration from Consul
+
+1.1.1
+-----
+- Add a missing requirements
+
+1.2.0
+-----
+- Add authentication features for interface
+
+1.3.0
+-----
+- Add cache functionality
+
+1.3.1
+-----
+- Delete Oslo config possibilities
+
+1.3.2
+-----
+- Delete Oslo logging and config
+
+1.3.3
+-----
+- Update the cache
+
+1.3.4
+-----
+- Fix a bug on the connection between interface and authz
+
+1.4.0
+-----
+- Add a waiting loop when the Keystone server is not currently available
+
+1.4.1
+-----
+- Cleanup moon_utilities code
+
+1.4.2
+-----
+- Update the name of the library (from moon_utilities)
+
+1.4.3
+-----
+- Fix a bug in MANIFEST.in
+
+1.4.4
+-----
+- Code cleaning
+
+1.4.5
+-----
+- Add PdpKeystoneMappingConflict exception
+
+1.4.6
+-----
+- Add WrapperConflict, PipelineConflict, SlaveNameUnknown exceptions
+
+1.4.7
+-----
+- Delete the auth.py file to remove some code duplication
+
+1.4.8
+-----
+- Add SubjectScopeExisting, ObjectScopeExisting, ActionScopeExisting exceptions
+
+1.4.9
+-----
+- Add some exceptions when deletion of elements is impossible
+
+1.4.10
+-----
+- Add CategoryNameInvalid and PerimeterNameInvalid exceptions
+
+1.4.11
+-----
+- Add validate_data function
+
+1.4.12
+-----
+- Fix a bug for the authz component
+- updating Validation to be on mandatory keys only
+
+1.4.13
+-----
+- Adding InvalidKey , InvalidContent exception
+- fix error code of 'CategoryNameInvalid' to be 400
+- updating error of post/patch to mention key name
+
+1.4.14
+-----
+- Adding updates to log
+1.4.15
+-----
+- Delete the check on each key send in request body for POST /models
+
+1.4.15-1
+--------
+- Revert to the previous functionality
+
+1.4.16
+-----
+- Adding exceptions for MetaRuleNotLinkedWithPolicyModel , CategoryNotAssignedMetaRule
+
+1.4.17
+-----
+- Update the security verification on attributes
+
+1.4.18
+-----
+- Allow None values in input attributes (None is replaced by an empty string)
+
+1.4.19
+-----
+- Allow boolean values in input attributes
+
+1.4.20
+-----
+- Adding DeleteSubjectCategoryWithMetaRule exception
+- Adding MetaRuleUpdate , PolicyUpdateError, ModelContentError exception
+- Adding DeleteObjectCategoryWithMetaRule DeleteActionCategoryWithMetaRule exceptions
+
+1.4.21
+-----
+- Allow in the cache the search of a perimeter element by it ID
+
+1.4.22
+-----
+- Enable the target update in context manager
+- Fix assignments update in cache
diff --git a/old/python_moonutilities/Jenkinsfile b/old/python_moonutilities/Jenkinsfile
new file mode 100644
index 00000000..95939e9b
--- /dev/null
+++ b/old/python_moonutilities/Jenkinsfile
@@ -0,0 +1,10 @@
+pipeline {
+ agent { docker { image 'python:3.5.1' } }
+ stages {
+ stage('build') {
+ steps {
+ sh 'python --version'
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/old/python_moonutilities/LICENSE b/old/python_moonutilities/LICENSE
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/old/python_moonutilities/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/old/python_moonutilities/MANIFEST.in b/old/python_moonutilities/MANIFEST.in
new file mode 100644
index 00000000..2a5ac509
--- /dev/null
+++ b/old/python_moonutilities/MANIFEST.in
@@ -0,0 +1,10 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+include README.md
+include LICENSE
+include Changelog
+include setup.py
+include requirements.txt
diff --git a/old/python_moonutilities/README.md b/old/python_moonutilities/README.md
new file mode 100644
index 00000000..8e21966a
--- /dev/null
+++ b/old/python_moonutilities/README.md
@@ -0,0 +1,33 @@
+# python-moonutilities Package
+This package contains the core module for the Moon project.
+It is designed to provide authorization feature to all OpenStack components.
+
+For any other information, refer to the parent project:
+
+ https://git.opnfv.org/moon
+
+python-moonutilities is a common Python lib for other Moon Python packages
+
+## Build
+### Build Python Package
+```bash
+cd ${MOON_HOME}/python_moonutilities
+python3 setup.py sdist bdist_wheel
+```
+
+### Push Python Package to PIP
+```bash
+cd ${MOON_HOME}/python_moonutilities
+gpg --detach-sign -u "${GPG_ID}" -a dist/python_moonutilities-X.Y.Z-py3-none-any.whl
+gpg --detach-sign -u "${GPG_ID}" -a dist/python_moonutilities-X.Y.Z.tar.gz
+twine upload dist/python_moonutilities-X.Y.Z-py3-none-any.whl dist/python_moonutilities-X.Y.Z-py3-none-any.whl.asc
+twine upload dist/python_moonutilities-X.Y.Z.tar.gz dist/python_moonutilities-X.Y.Z.tar.gz.asc
+```
+
+## Test
+### Python Unit Test
+launch Docker for Python unit tests
+```bash
+cd ${MOON_HOME}/python_moonutilities
+docker run --rm --volume $(pwd):/data wukongsun/moon_python_unit_test:latest
+```
diff --git a/old/python_moonutilities/python_moonutilities/__init__.py b/old/python_moonutilities/python_moonutilities/__init__.py
new file mode 100644
index 00000000..6e924e93
--- /dev/null
+++ b/old/python_moonutilities/python_moonutilities/__init__.py
@@ -0,0 +1,6 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+__version__ = "1.4.22"
diff --git a/old/python_moonutilities/python_moonutilities/cache.py b/old/python_moonutilities/python_moonutilities/cache.py
new file mode 100644
index 00000000..49a3ef5b
--- /dev/null
+++ b/old/python_moonutilities/python_moonutilities/cache.py
@@ -0,0 +1,703 @@
+import logging
+import time
+import python_moonutilities.request_wrapper as requests
+from uuid import uuid4
+from python_moonutilities import configuration, exceptions
+
+logger = logging.getLogger("moon.utilities.cache")
+
+
+class Cache(object):
+ # TODO (asteroide): set cache integer in CONF file
+ '''
+ [NOTE] Propose to define the following variables inside the init method
+ as defining them out side the init, will be treated as private static variables
+ and keep tracks with any changes done anywhere
+ for more info : you can check https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables
+ '''
+ __UPDATE_INTERVAL = 10
+
+ __CONTAINERS = {}
+ __CONTAINERS_UPDATE = 0
+
+ __CONTAINER_CHAINING_UPDATE = 0
+ __CONTAINER_CHAINING = {}
+
+ __PDP = {}
+ __PDP_UPDATE = 0
+
+ __POLICIES = {}
+ __POLICIES_UPDATE = 0
+
+ __MODELS = {}
+ __MODELS_UPDATE = 0
+
+ __SUBJECTS = {}
+ __OBJECTS = {}
+ __ACTIONS = {}
+
+ __SUBJECT_ASSIGNMENTS = {}
+ __OBJECT_ASSIGNMENTS = {}
+ __ACTION_ASSIGNMENTS = {}
+
+ __SUBJECT_CATEGORIES = {}
+ __SUBJECT_CATEGORIES_UPDATE = 0
+ __OBJECT_CATEGORIES = {}
+ __OBJECT_CATEGORIES_UPDATE = 0
+ __ACTION_CATEGORIES = {}
+ __ACTION_CATEGORIES_UPDATE = 0
+
+ __META_RULES = {}
+ __META_RULES_UPDATE = 0
+
+ __RULES = {}
+ __RULES_UPDATE = 0
+
+ __AUTHZ_REQUESTS = {}
+
+ def __init__(self):
+ self.manager_url = "{}://{}:{}".format(
+ configuration.get_components()['manager'].get('protocol', 'http'),
+ configuration.get_components()['manager']['hostname'],
+ configuration.get_components()['manager']['port']
+ )
+ self.orchestrator_url = "{}://{}:{}".format(
+ configuration.get_components()['orchestrator'].get('protocol', 'http'),
+ configuration.get_components()['orchestrator']['hostname'],
+ configuration.get_components()['orchestrator']['port']
+ )
+
+ def update(self):
+ self.__update_container()
+ self.__update_pdp()
+ self.__update_policies()
+ self.__update_models()
+ for key, value in self.__PDP.items():
+ # LOG.info("Updating container_chaining with {}".format(value["keystone_project_id"]))
+ if "keystone_project_id" in value:
+ self.__update_container_chaining(value["keystone_project_id"])
+ else:
+ logger.warning("no 'keystone_project_id' found while Updating container_chaining")
+
+ @property
+ def authz_requests(self):
+ return self.__AUTHZ_REQUESTS
+
+ # perimeter functions
+
+ @property
+ def subjects(self):
+ return self.__SUBJECTS
+
+ def __update_subjects(self, policy_id):
+ response = requests.get("{}/policies/{}/subjects".format(self.manager_url, policy_id))
+ if 'subjects' in response.json():
+ self.__SUBJECTS[policy_id] = response.json()['subjects']
+ else:
+ raise exceptions.SubjectUnknown("Cannot find subject within policy_id {}".format(policy_id))
+
+ def get_subject(self, policy_id, name):
+ if not policy_id:
+ raise exceptions.PolicyUnknown("Cannot find policy within policy_id {}".format(policy_id))
+
+ if policy_id in self.subjects:
+ for _subject_id, _subject_dict in self.subjects[policy_id].items():
+ if _subject_id == name or _subject_dict.get("name") == name:
+ return _subject_id
+
+ self.__update_subjects(policy_id)
+
+ if policy_id in self.subjects:
+ for _subject_id, _subject_dict in self.subjects[policy_id].items():
+ if _subject_id == name or _subject_dict.get("name") == name:
+ return _subject_id
+
+ raise exceptions.SubjectUnknown("Cannot find subject {}".format(name))
+
+ @property
+ def objects(self):
+ return self.__OBJECTS
+
+ def __update_objects(self, policy_id):
+ response = requests.get("{}/policies/{}/objects".format(self.manager_url, policy_id))
+ if 'objects' in response.json():
+ self.__OBJECTS[policy_id] = response.json()['objects']
+ else:
+ raise exceptions.ObjectUnknown("Cannot find object within policy_id {}".format(policy_id))
+
+ def get_object(self, policy_id, name):
+ if not policy_id:
+ raise exceptions.PolicyUnknown("Cannot find policy within policy_id {}".format(policy_id))
+
+ if policy_id in self.objects:
+ for _object_id, _object_dict in self.__OBJECTS[policy_id].items():
+ if _object_id == name or _object_dict.get("name") == name:
+ return _object_id
+
+ self.__update_objects(policy_id)
+
+ if policy_id in self.objects:
+ for _object_id, _object_dict in self.__OBJECTS[policy_id].items():
+ if _object_id == name or _object_dict.get("name") == name:
+ return _object_id
+
+ raise exceptions.ObjectUnknown("Cannot find object {}".format(name))
+
+ @property
+ def actions(self):
+ return self.__ACTIONS
+
+ def __update_actions(self, policy_id):
+ response = requests.get("{}/policies/{}/actions".format(self.manager_url, policy_id))
+
+ if 'actions' in response.json():
+ self.__ACTIONS[policy_id] = response.json()['actions']
+ else:
+ raise exceptions.ActionUnknown("Cannot find action within policy_id {}".format(policy_id))
+
+ def get_action(self, policy_id, name):
+ if not policy_id:
+ raise exceptions.PolicyUnknown("Cannot find policy within policy_id {}".format(policy_id))
+
+ if policy_id in self.actions:
+ for _action_id, _action_dict in self.__ACTIONS[policy_id].items():
+ if _action_id == name or _action_dict.get("name") == name:
+ return _action_id
+
+ self.__update_actions(policy_id)
+
+ for _action_id, _action_dict in self.__ACTIONS[policy_id].items():
+ if _action_id == name or _action_dict.get("name") == name:
+ return _action_id
+
+ raise exceptions.ActionUnknown("Cannot find action {}".format(name))
+
+ # meta_rule functions
+
+ @property
+ def meta_rules(self):
+ current_time = time.time()
+ if self.__META_RULES_UPDATE + self.__UPDATE_INTERVAL < current_time:
+ self.__META_RULES_UPDATE = current_time
+ self.__update_meta_rules()
+ self.__META_RULES_UPDATE = current_time
+ return self.__META_RULES
+
+ def __update_meta_rules(self):
+ response = requests.get("{}/meta_rules".format(self.manager_url))
+
+ if 'meta_rules' in response.json():
+ self.__META_RULES = response.json()['meta_rules']
+ else:
+ raise exceptions.MetaRuleUnknown("Cannot find meta rules")
+
+ # rule functions
+
+ @property
+ def rules(self):
+ current_time = time.time()
+ if self.__RULES_UPDATE + self.__UPDATE_INTERVAL < current_time:
+ self.__RULES_UPDATE = current_time
+ self.__update_rules()
+ self.__RULES_UPDATE = current_time
+ return self.__RULES
+
+ def __update_rules(self):
+ for policy_id in self.policies:
+ logger.debug("Get {}".format("{}/policies/{}/rules".format(
+ self.manager_url, policy_id)))
+
+ response = requests.get("{}/policies/{}/rules".format(
+ self.manager_url, policy_id))
+ if 'rules' in response.json():
+ self.__RULES[policy_id] = response.json()['rules']
+ else:
+ logger.warning(" no 'rules' found within policy_id: {}".format(policy_id))
+
+ logger.debug("UPDATE RULES {}".format(self.__RULES))
+
+ # assignment functions
+
+ def update_assignments(self, policy_id=None, perimeter_id=None):
+ if policy_id:
+ self.__update_subject_assignments(policy_id=policy_id, perimeter_id=perimeter_id)
+ self.__update_object_assignments(policy_id=policy_id, perimeter_id=perimeter_id)
+ self.__update_action_assignments(policy_id=policy_id, perimeter_id=perimeter_id)
+ else:
+ for policy_id in self.__POLICIES:
+ self.__update_subject_assignments(policy_id=policy_id, perimeter_id=perimeter_id)
+ self.__update_object_assignments(policy_id=policy_id, perimeter_id=perimeter_id)
+ self.__update_action_assignments(policy_id=policy_id, perimeter_id=perimeter_id)
+
+ @property
+ def subject_assignments(self):
+ return self.__SUBJECT_ASSIGNMENTS
+
+ def __update_subject_assignments(self, policy_id, perimeter_id=None):
+ if perimeter_id:
+ response = requests.get("{}/policies/{}/subject_assignments/{}".format(
+ self.manager_url, policy_id, perimeter_id))
+ else:
+ response = requests.get("{}/policies/{}/subject_assignments".format(
+ self.manager_url, policy_id))
+
+ if 'subject_assignments' in response.json():
+ if policy_id not in self.subject_assignments:
+ self.__SUBJECT_ASSIGNMENTS[policy_id] = {}
+ self.__SUBJECT_ASSIGNMENTS[policy_id] = response.json()['subject_assignments']
+ else:
+ raise exceptions.SubjectAssignmentUnknown(
+ "Cannot find subject assignment within policy_id {}".format(policy_id))
+
+ def get_subject_assignments(self, policy_id, perimeter_id, category_id):
+ if not policy_id:
+ raise exceptions.PolicyUnknown("Cannot find policy within policy_id {}".format(policy_id))
+
+ if policy_id not in self.subject_assignments:
+ self.__update_subject_assignments(policy_id, perimeter_id)
+
+ for key, value in self.subject_assignments[policy_id].items():
+ if all(k in value for k in ("subject_id", "category_id", "assignments")):
+ if perimeter_id == value['subject_id'] and category_id == value['category_id']:
+ return value['assignments']
+ else:
+ logger.warning("'subject_id' or 'category_id' or 'assignments'"
+ " keys are not found in subject_assignments")
+ return []
+
+ @property
+ def object_assignments(self):
+ return self.__OBJECT_ASSIGNMENTS
+
+ def __update_object_assignments(self, policy_id, perimeter_id=None):
+ if perimeter_id:
+ response = requests.get("{}/policies/{}/object_assignments/{}".format(
+ self.manager_url, policy_id, perimeter_id))
+ else:
+ response = requests.get("{}/policies/{}/object_assignments".format(
+ self.manager_url, policy_id))
+
+ if 'object_assignments' in response.json():
+ if policy_id not in self.object_assignments:
+ self.__OBJECT_ASSIGNMENTS[policy_id] = {}
+
+ self.__OBJECT_ASSIGNMENTS[policy_id] = response.json()['object_assignments']
+ else:
+ raise exceptions.ObjectAssignmentUnknown(
+ "Cannot find object assignment within policy_id {}".format(policy_id))
+
+ def get_object_assignments(self, policy_id, perimeter_id, category_id):
+ if not policy_id:
+ raise exceptions.PolicyUnknown("Cannot find policy within policy_id {}".format(policy_id))
+
+ if policy_id not in self.object_assignments:
+ self.__update_object_assignments(policy_id, perimeter_id)
+
+ for key, value in self.object_assignments[policy_id].items():
+ if all(k in value for k in ("object_id", "category_id", "assignments")):
+ if perimeter_id == value['object_id'] and category_id == value['category_id']:
+ return value['assignments']
+ else:
+ logger.warning("'object_id' or 'category_id' or'assignments'"
+ " keys are not found in object_assignments")
+ return []
+
+ @property
+ def action_assignments(self):
+ return self.__ACTION_ASSIGNMENTS
+
+ def __update_action_assignments(self, policy_id, perimeter_id=None):
+ if perimeter_id:
+ response = requests.get("{}/policies/{}/action_assignments/{}".format(
+ self.manager_url, policy_id, perimeter_id))
+ else:
+ response = requests.get("{}/policies/{}/action_assignments".format(
+ self.manager_url, policy_id))
+
+ if 'action_assignments' in response.json():
+ if policy_id not in self.__ACTION_ASSIGNMENTS:
+ self.__ACTION_ASSIGNMENTS[policy_id] = {}
+
+ self.__ACTION_ASSIGNMENTS[policy_id] = response.json()['action_assignments']
+ else:
+ raise exceptions.ActionAssignmentUnknown(
+ "Cannot find action assignment within policy_id {}".format(policy_id))
+
+ def get_action_assignments(self, policy_id, perimeter_id, category_id):
+ if not policy_id:
+ raise exceptions.PolicyUnknown("Cannot find policy within policy_id {}".format(policy_id))
+
+ if policy_id not in self.action_assignments:
+ self.__update_action_assignments(policy_id, perimeter_id)
+
+ for key, value in self.action_assignments[policy_id].items():
+ if all(k in value for k in ("action_id", "category_id", "assignments")):
+ if perimeter_id == value['action_id'] and category_id == value['category_id']:
+ return value['assignments']
+ else:
+ logger.warning("'action_id' or 'category_id' or'assignments'"
+ " keys are not found in action_assignments")
+ return []
+
+ # category functions
+
+ @property
+ def subject_categories(self):
+ current_time = time.time()
+ if self.__SUBJECT_CATEGORIES_UPDATE + self.__UPDATE_INTERVAL < current_time:
+ self.__SUBJECT_CATEGORIES_UPDATE = current_time
+ self.__update_subject_categories()
+ self.__SUBJECT_CATEGORIES_UPDATE = current_time
+ return self.__SUBJECT_CATEGORIES
+
+ def __update_subject_categories(self):
+ response = requests.get("{}/policies/subject_categories".format(
+ self.manager_url))
+
+ if 'subject_categories' in response.json():
+ self.__SUBJECT_CATEGORIES.update(response.json()['subject_categories'])
+ else:
+ raise exceptions.SubjectCategoryUnknown("Cannot find subject category")
+
+ @property
+ def object_categories(self):
+ current_time = time.time()
+ if self.__OBJECT_CATEGORIES_UPDATE + self.__UPDATE_INTERVAL < current_time:
+ self.__OBJECT_CATEGORIES_UPDATE = current_time
+ self.__update_object_categories()
+ self.__OBJECT_CATEGORIES_UPDATE = current_time
+ return self.__OBJECT_CATEGORIES
+
+ def __update_object_categories(self):
+ response = requests.get("{}/policies/object_categories".format(self.manager_url))
+
+ if 'object_categories' in response.json():
+ self.__OBJECT_CATEGORIES.update(response.json()['object_categories'])
+ else:
+ raise exceptions.ObjectCategoryUnknown("Cannot find object category")
+
+ @property
+ def action_categories(self):
+ current_time = time.time()
+ if self.__ACTION_CATEGORIES_UPDATE + self.__UPDATE_INTERVAL < current_time:
+ self.__ACTION_CATEGORIES_UPDATE = current_time
+ self.__update_action_categories()
+ self.__ACTION_CATEGORIES_UPDATE = current_time
+ return self.__ACTION_CATEGORIES
+
+ def __update_action_categories(self):
+ response = requests.get("{}/policies/action_categories".format(self.manager_url))
+
+ if 'action_categories' in response.json():
+ self.__ACTION_CATEGORIES.update(response.json()['action_categories'])
+ else:
+ raise exceptions.ActionCategoryUnknown("Cannot find action category")
+
+ # PDP functions
+
+ def __update_pdp(self):
+ response = requests.get("{}/pdp".format(self.manager_url))
+ pdp = response.json()
+ if 'pdps' in pdp:
+ for _pdp in pdp["pdps"].values():
+ if "keystone_project_id" in _pdp and _pdp['keystone_project_id'] not in self.container_chaining:
+ self.__CONTAINER_CHAINING[_pdp['keystone_project_id']] = {}
+ # Note (asteroide): force update of chaining
+ self.__update_container_chaining(_pdp['keystone_project_id'])
+ for key, value in pdp["pdps"].items():
+ self.__PDP[key] = value
+
+ else:
+ raise exceptions.PdpError("Cannot find 'pdps' key")
+
+ @property
+ def pdp(self):
+ """Policy Decision Point
+ Example of content:
+ {
+ "pdp_id": {
+ "keystone_project_id": "keystone_project_id",
+ "name": "pdp1",
+ "description": "test",
+ "security_pipeline": [
+ "policy_id"
+ ]
+ }
+ }
+
+ :return:
+ """
+ current_time = time.time()
+ if self.__PDP_UPDATE + self.__UPDATE_INTERVAL < current_time:
+ self.__PDP_UPDATE = current_time
+ self.__update_pdp()
+ self.__PDP_UPDATE = current_time
+ return self.__PDP
+
+ # policy functions
+ def __update_policies(self):
+ response = requests.get("{}/policies".format(self.manager_url))
+ policies = response.json()
+
+ if 'policies' in policies:
+ for key, value in policies["policies"].items():
+ self.__POLICIES[key] = value
+ else:
+ raise exceptions.PolicytNotFound("Cannot find 'policies' key")
+
+ @property
+ def policies(self):
+ current_time = time.time()
+ if self.__POLICIES_UPDATE + self.__UPDATE_INTERVAL < current_time:
+ self.__POLICIES_UPDATE = current_time
+ self.__update_policies()
+ self.__POLICIES_UPDATE = current_time
+ return self.__POLICIES
+
+ # model functions
+
+ def __update_models(self):
+ response = requests.get("{}/models".format(self.manager_url))
+ models = response.json()
+ if 'models' in models:
+ for key, value in models["models"].items():
+ self.__MODELS[key] = value
+ else:
+ raise exceptions.ModelNotFound("Cannot find 'models' key")
+
+ @property
+ def models(self):
+ current_time = time.time()
+ if self.__MODELS_UPDATE + self.__UPDATE_INTERVAL < current_time:
+ self.__MODELS_UPDATE = current_time
+ self.__update_models()
+ self.__MODELS_UPDATE = current_time
+ return self.__MODELS
+
+ # helper functions
+
+ def get_policy_from_meta_rules(self, meta_rule_id):
+ for pdp_key, pdp_value in self.pdp.items():
+ if "security_pipeline" in pdp_value:
+ for policy_id in pdp_value["security_pipeline"]:
+ if policy_id in self.policies and "model_id" in self.policies[policy_id]:
+ model_id = self.policies[policy_id]["model_id"]
+ if model_id in self.models and "meta_rules" in self.models[model_id]:
+ if meta_rule_id in self.models[model_id]["meta_rules"]:
+ return policy_id
+ else:
+ logger.warning(
+ "Cannot find model_id: {} within "
+ "models and 'meta_rules' key".format(model_id))
+ else:
+ logger.warning(
+ "Cannot find policy_id: {} "
+ "within policies and 'model_id' key".format(
+ policy_id))
+ else:
+ logger.warning("Cannot find 'security_pipeline' "
+ "key within pdp ")
+
+ def get_meta_rule_ids_from_pdp_value(self, pdp_value):
+ meta_rules = []
+ if "security_pipeline" in pdp_value:
+ for policy_id in pdp_value["security_pipeline"]:
+ if policy_id not in self.policies or "model_id" not in self.policies[policy_id]:
+ raise exceptions.PolicyUnknown("Cannot find 'models' key")
+ model_id = self.policies[policy_id]["model_id"]
+ if model_id not in self.models or 'meta_rules' not in self.models[model_id]:
+ raise exceptions.ModelNotFound("Cannot find 'models' key")
+ for meta_rule in self.models[model_id]["meta_rules"]:
+ meta_rules.append(meta_rule)
+ return meta_rules
+ raise exceptions.PdpContentError
+
+ def get_pdp_from_keystone_project(self, keystone_project_id):
+ for pdp_key, pdp_value in self.pdp.items():
+ if "keystone_project_id" in pdp_value and \
+ keystone_project_id == pdp_value["keystone_project_id"]:
+ return pdp_key
+
+ def get_keystone_project_id_from_policy_id(self, policy_id):
+ for pdp_key, pdp_value in self.pdp.items():
+ if "security_pipeline" in pdp_value and \
+ "keystone_project_id" in pdp_value:
+ if policy_id in pdp_value["security_pipeline"]:
+ return pdp_value["keystone_project_id"]
+ else:
+ logger.warning(" 'security_pipeline','keystone_project_id' "
+ "key not in pdp {}".format(pdp_value))
+
+ def get_keystone_project_id_from_pdp_id(self, pdp_id):
+ if pdp_id in self.pdp:
+ pdp_value = self.pdp.get(pdp_id)
+ if "security_pipeline" in pdp_value and \
+ "keystone_project_id" in pdp_value:
+ return pdp_value["keystone_project_id"]
+ logger.warning("Unknown PDP ID".format(pdp_id))
+
+ def get_containers_from_keystone_project_id(self, keystone_project_id,
+ meta_rule_id=None):
+ for container_id, container_values in self.containers.items():
+ for container_value in container_values:
+ if 'keystone_project_id' not in container_value:
+ continue
+ if container_value['keystone_project_id'] == keystone_project_id:
+ if not meta_rule_id:
+ yield container_id, container_value
+ elif "meta_rule_id" in container_value and \
+ container_value.get('meta_rule_id') == meta_rule_id:
+ yield container_id, container_value
+ break
+
+ # containers functions
+
+ def __update_container(self):
+ response = requests.get("{}/pods".format(self.orchestrator_url))
+ pods = response.json()
+ if "pods" in pods:
+ for key, value in pods["pods"].items():
+ # if key not in self.__CONTAINERS:
+ self.__CONTAINERS[key] = value
+ # else:
+ # for container in value:
+ # self.__CONTAINERS[key].update(value)
+ else:
+ raise exceptions.PodError("Cannot find 'pods' key")
+
+ def add_container(self, container_data):
+ """Add a new container in the cache
+
+ :param container_data: dictionary with information for the container
+ Example:
+ {
+ "name": name,
+ "hostname": name,
+ "port": {
+ "PrivatePort": tcp_port,
+ "Type": "tcp",
+ "IP": "0.0.0.0",
+ "PublicPort": tcp_port
+ },
+ "keystone_project_id": uuid,
+ "pdp_id": self.CACHE.get_pdp_from_keystone_project(uuid),
+ "meta_rule_id": meta_rule_id,
+ "container_name": container_name,
+ "plugin_name": plugin_name
+ "container_id": "container_id"
+ }
+
+ :return:
+ """
+ if all(k in container_data for k in ("keystone_project_id", "name", "container_id", "policy_id",
+ "meta_rule_id", "port")) \
+ and all(k in container_data['port'] for k in ("PublicPort", "Type", "IP", "PrivatePort")):
+
+ self.__CONTAINERS[uuid4().hex] = {
+ "keystone_project_id": container_data['keystone_project_id'],
+ "name": container_data['name'],
+ "container_id": container_data['container_id'],
+ "hostname": container_data['name'],
+ "policy_id": container_data['policy_id'],
+ "meta_rule_id": container_data['meta_rule_id'],
+ "port": [
+ {
+ "PublicPort": container_data['port']["PublicPort"],
+ "Type": container_data['port']["Type"],
+ "IP": container_data['port']["IP"],
+ "PrivatePort": container_data['port']["PrivatePort"]
+ }
+ ],
+ "genre": container_data['plugin_name']
+ }
+ self.__update_container_chaining(self.get_keystone_project_id_from_policy_id(container_data['policy_id']))
+ else:
+ raise exceptions.ContainerError("Cannot find 'container' parameters key")
+
+ @property
+ def containers(self):
+ """Containers cache
+ example of content :
+ {
+ "policy_uuid1": "component_hostname1",
+ "policy_uuid2": "component_hostname2",
+ }
+ :return:
+ """
+ current_time = time.time()
+ if self.__CONTAINERS_UPDATE + self.__UPDATE_INTERVAL < current_time:
+ self.__CONTAINERS_UPDATE = current_time
+ self.__update_container()
+ self.__CONTAINERS_UPDATE = current_time
+ return self.__CONTAINERS
+
+ @property
+ def container_chaining(self):
+ """Cache for mapping Keystone Project ID with meta_rule ID and container ID
+ Example of content:
+ {
+ "keystone_project_id": [
+ {
+ "container_id": "container_id",
+ "genre": "genre",
+ "policy_id": "policy_id",
+ "meta_rule_id": "meta_rule_id",
+ }
+ ]
+ }
+
+ :return:
+ """
+ current_time = time.time()
+ if self.__CONTAINER_CHAINING_UPDATE + self.__UPDATE_INTERVAL < current_time:
+ self.__CONTAINER_CHAINING_UPDATE = current_time
+ for key, value in self.pdp.items():
+ if "keystone_project_id" in value:
+ if not value["keystone_project_id"]:
+ continue
+ self.__update_container_chaining(value["keystone_project_id"])
+ else:
+ logger.warning("no 'keystone_project_id' found")
+ self.__CONTAINER_CHAINING_UPDATE = current_time
+ return self.__CONTAINER_CHAINING
+
+ def __update_container_chaining(self, keystone_project_id):
+ container_ids = []
+ for pdp_id, pdp_value, in self.__PDP.items():
+ if pdp_value:
+ if all(k in pdp_value for k in ("keystone_project_id", "security_pipeline")) \
+ and pdp_value["keystone_project_id"] == keystone_project_id:
+ for policy_id in pdp_value["security_pipeline"]:
+ if policy_id in self.policies and "model_id" in self.policies[policy_id]:
+ model_id = self.policies[policy_id]['model_id']
+ if model_id in self.models and "meta_rules" in self.models[model_id]:
+ for meta_rule_id in self.models[model_id]["meta_rules"]:
+ for container_id, container_value in self.get_containers_from_keystone_project_id(
+ keystone_project_id,
+ meta_rule_id
+ ):
+ if "name" in container_value:
+ if all(k in container_value for k in ("genre", "port")):
+ container_ids.append(
+ {
+ "container_id": container_value["name"],
+ "genre": container_value["genre"],
+ "policy_id": policy_id,
+ "meta_rule_id": meta_rule_id,
+ "hostname": container_value["name"],
+ "hostip": "127.0.0.1",
+ "port": container_value["port"],
+ }
+ )
+ else:
+ logger.warning("Container content keys not found {}", container_value)
+ else:
+ logger.warning("Container content keys not found {}", container_value)
+ else:
+ raise exceptions.ModelUnknown("Cannot find model_id: {} in models and "
+ "may not contains 'meta_rules' key".format(model_id))
+ else:
+ raise exceptions.PolicyUnknown("Cannot find policy within policy_id: {}, "
+ "and may not contains 'model_id' key".format(policy_id))
+
+ self.__CONTAINER_CHAINING[keystone_project_id] = container_ids
diff --git a/old/python_moonutilities/python_moonutilities/configuration.py b/old/python_moonutilities/python_moonutilities/configuration.py
new file mode 100644
index 00000000..0516274c
--- /dev/null
+++ b/old/python_moonutilities/python_moonutilities/configuration.py
@@ -0,0 +1,124 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+import base64
+import json
+import python_moonutilities.request_wrapper as requests
+import logging.config
+from python_moonutilities import exceptions
+
+logger = logging.getLogger("moon.utilities.configuration")
+
+CONSUL_HOST = "consul"
+CONSUL_PORT = "8500"
+
+DATABASE = "database"
+KEYSTONE = "keystone"
+DOCKER = "docker"
+COMPONENTS = "components"
+
+
+def init_logging():
+ config = get_configuration("logging")
+ logging.config.dictConfig(config['logging'])
+
+
+def increment_port():
+ components_object = get_configuration("components/port_start")
+ if 'components/port_start' in components_object:
+ components_port_start = int(components_object['components/port_start'])
+ components_port_start += 1
+ else:
+ raise exceptions.ConsulComponentContentError("error={}".format(components_object))
+ url = "http://{}:{}/v1/kv/components/port_start".format(CONSUL_HOST, CONSUL_PORT)
+ req = requests.put(url, json=str(components_port_start))
+ if req.status_code != 200:
+ logger.info("url={}".format(url))
+ raise exceptions.ConsulError
+ return components_port_start
+
+
+def get_configuration(key):
+ url = "http://{}:{}/v1/kv/{}".format(CONSUL_HOST, CONSUL_PORT, key)
+ req = requests.get(url)
+ if req.status_code != 200:
+ logger.error("url={}".format(url))
+ raise exceptions.ConsulComponentNotFound("error={}: {}".format(req.status_code, req.text))
+ data = req.json()
+ if len(data) == 1:
+ data = data[0]
+ if all( k in data for k in ("Key", "Value")) :
+ return {data["Key"]: json.loads(base64.b64decode(data["Value"]).decode("utf-8"))}
+ raise exceptions.ConsulComponentContentError("error={}".format(data))
+ else:
+ for item in data:
+ if not all(k in item for k in ("Key", "Value")):
+ logger.warning("invalidate content {}".format(item))
+ raise exceptions.ConsulComponentContentError("error={}".format(data))
+ return [
+ {
+ item["Key"]: json.loads(base64.b64decode(item["Value"]).decode("utf-8"))
+ } for item in data
+ ]
+
+
+def add_component(name, uuid, port=None, bind="127.0.0.1", keystone_id="", extra=None, container=None):
+ data = {
+ "hostname": name,
+ "keystone_id": keystone_id,
+ "bind": bind,
+ "port": port,
+ "extra": extra,
+ "container": container
+ }
+ req = requests.put(
+ "http://{}:{}/v1/kv/components/{}".format(CONSUL_HOST, CONSUL_PORT, uuid),
+ headers={"content-type": "application/json"},
+ json=data
+ )
+ if req.status_code != 200:
+ logger.debug("url={}".format("http://{}:{}/v1/kv/components/{}".format(CONSUL_HOST, CONSUL_PORT, uuid)))
+ logger.debug("data={}".format(data))
+ raise exceptions.ConsulError
+ logger.info("Add component {}".format(req.text))
+ return get_configuration("components/"+uuid)
+
+
+def get_plugins():
+ pipeline = get_configuration("components/pipeline")
+ logger.debug("pipeline={}".format(pipeline))
+ components = pipeline.get("components/pipeline")
+ if 'interface' in components:
+ components.pop('interface')
+ else:
+ raise exceptions.ConsulComponentContentError("error= Components pipeline has no interface")
+ return components
+
+
+def get_components():
+ url = "http://{}:{}/v1/kv/components?recurse=true".format(CONSUL_HOST, CONSUL_PORT)
+ req = requests.get(url)
+ if req.status_code != 200:
+ logger.info("url={}".format(url))
+ raise exceptions.ConsulError
+ data = req.json()
+ if len(data) == 1:
+ data = data[0]
+ if all(k in data for k in ("Key", "Value")):
+ return {data["Key"].replace("components/", ""): json.loads(base64.b64decode(data["Value"]).decode("utf-8"))}
+ raise exceptions.ConsulComponentContentError("error={}".format(data))
+ else:
+ for item in data:
+ if not all(k in item for k in ("Key", "Value")):
+ logger.warning("invalidate content {}".format(item))
+ raise exceptions.ConsulComponentContentError("error={}".format(data))
+ return {
+ item["Key"].replace("components/", ""): json.loads(base64.b64decode(item["Value"]).decode("utf-8"))
+ for item in data
+ }
+
+
+init_logging()
diff --git a/old/python_moonutilities/python_moonutilities/context.py b/old/python_moonutilities/python_moonutilities/context.py
new file mode 100644
index 00000000..dc140b74
--- /dev/null
+++ b/old/python_moonutilities/python_moonutilities/context.py
@@ -0,0 +1,353 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+import copy
+import logging
+from python_moonutilities import exceptions
+
+logger = logging.getLogger("moon.utilities." + __name__)
+
+
+class Context:
+
+ def __init__(self, init_context, cache):
+ if init_context is None:
+ raise Exception("Invalid context content object")
+
+ self.cache = cache
+ self.__keystone_project_id = init_context.get("project_id")
+ self.__pdp_id = self.cache.get_pdp_from_keystone_project(self.__keystone_project_id)
+
+ if not self.__pdp_id:
+ raise exceptions.AuthzException(
+ "Cannot create context for authz "
+ "with Keystone project ID {}".format(
+ self.__keystone_project_id
+ ))
+ self.__pdp_value = copy.deepcopy(self.cache.pdp[self.__pdp_id])
+
+ self.__subject = init_context.get("subject_name")
+ self.__object = init_context.get("object_name")
+ self.__action = init_context.get("action_name")
+ self.__request_id = init_context.get("req_id")
+ self.__cookie = init_context.get("cookie")
+ self.__manager_url = init_context.get("manager_url")
+ self.__interface_name = init_context.get("interface_name")
+ self.__current_request = None
+
+ self.__index = -1
+ # self.__init_initial_request()
+ self.__meta_rule_ids = self.cache.get_meta_rule_ids_from_pdp_value(self.__pdp_value)
+ self.__meta_rules = self.cache.meta_rules
+
+ self.__pdp_set = {}
+ # self.__init_pdp_set()
+
+ def delete_cache(self):
+ self.cache = {}
+
+ def set_cache(self, cache):
+ self.cache = cache
+
+ def increment_index(self):
+ self.__index += 1
+ self.__init_current_request()
+ self.__init_pdp_set()
+
+ @property
+ def current_state(self):
+ self.__validate_meta_rule_content(self.__pdp_set[self.__meta_rule_ids[self.__index]])
+ return self.__pdp_set[self.__meta_rule_ids[self.__index]]['effect']
+
+ @current_state.setter
+ def current_state(self, state):
+ if state not in ("grant", "deny", "passed"):
+ state = "passed"
+ self.__validate_meta_rule_content(self.__pdp_set[self.__meta_rule_ids[self.__index]])
+ self.__pdp_set[self.__meta_rule_ids[self.__index]]['effect'] = state
+
+ @current_state.deleter
+ def current_state(self):
+ self.__validate_meta_rule_content(self.__pdp_set[self.__meta_rule_ids[self.__index]])
+ self.__pdp_set[self.__meta_rule_ids[self.__index]]['effect'] = "unset"
+
+ @property
+ def current_policy_id(self):
+ if "security_pipeline" not in self.__pdp_value:
+ raise exceptions.AuthzException('Cannot find security_pipeline key within pdp.')
+ return self.__pdp_value["security_pipeline"][self.__index]
+
+ @current_policy_id.setter
+ def current_policy_id(self, value):
+ pass
+
+ @current_policy_id.deleter
+ def current_policy_id(self):
+ pass
+
+ def __init_current_request(self):
+ if "security_pipeline" not in self.__pdp_value:
+ raise exceptions.PdpContentError
+ self.__subject = self.cache.get_subject(
+ self.__pdp_value["security_pipeline"][self.__index],
+ self.__subject)
+ self.__object = self.cache.get_object(
+ self.__pdp_value["security_pipeline"][self.__index],
+ self.__object)
+ self.__action = self.cache.get_action(
+ self.__pdp_value["security_pipeline"][self.__index],
+ self.__action)
+ self.__current_request = dict(self.initial_request)
+
+ def __init_pdp_set(self):
+ for meta_rule_id in self.__meta_rule_ids:
+ self.__pdp_set[meta_rule_id] = dict()
+ self.__pdp_set[meta_rule_id]["meta_rules"] = self.__meta_rules[meta_rule_id]
+ self.__pdp_set[meta_rule_id]["target"] = self.__add_target(meta_rule_id)
+ self.__pdp_set[meta_rule_id]["effect"] = "unset"
+ self.__pdp_set["effect"] = "deny"
+
+ def update_target(self):
+ for meta_rule_id in self.__meta_rule_ids:
+ result = dict()
+ _subject = self.__current_request["subject"]
+ _object = self.__current_request["object"]
+ _action = self.__current_request["action"]
+
+ meta_rules = self.cache.meta_rules
+ policy_id = self.cache.get_policy_from_meta_rules(meta_rule_id)
+
+ if 'subject_categories' not in meta_rules[meta_rule_id]:
+ raise exceptions.MetaRuleContentError(" 'subject_categories' key not found ")
+
+ self.cache.update_assignments(policy_id)
+
+ for sub_cat in meta_rules[meta_rule_id]['subject_categories']:
+ if sub_cat not in result:
+ result[sub_cat] = []
+ result[sub_cat].extend(
+ self.cache.get_subject_assignments(policy_id, _subject, sub_cat))
+
+ if 'object_categories' not in meta_rules[meta_rule_id]:
+ raise exceptions.MetaRuleContentError(" 'object_categories' key not found ")
+
+ for obj_cat in meta_rules[meta_rule_id]['object_categories']:
+ if obj_cat not in result:
+ result[obj_cat] = []
+ result[obj_cat].extend(
+ self.cache.get_object_assignments(policy_id, _object, obj_cat))
+
+ if 'action_categories' not in meta_rules[meta_rule_id]:
+ raise exceptions.MetaRuleContentError(" 'action_categories' key not found ")
+
+ for act_cat in meta_rules[meta_rule_id]['action_categories']:
+ if act_cat not in result:
+ result[act_cat] = []
+ result[act_cat].extend(
+ self.cache.get_action_assignments(policy_id, _action, act_cat))
+
+ self.__pdp_set[meta_rule_id]["target"] = result
+
+ def __add_target(self, meta_rule_id):
+ """build target from meta_rule
+
+ Target is dict of categories as keys ; and the value of each category
+ will be a list of assignments
+
+ """
+ result = dict()
+ _subject = self.__current_request["subject"]
+ _object = self.__current_request["object"]
+ _action = self.__current_request["action"]
+
+ meta_rules = self.cache.meta_rules
+ policy_id = self.cache.get_policy_from_meta_rules(meta_rule_id)
+
+ if 'subject_categories' not in meta_rules[meta_rule_id]:
+ raise exceptions.MetaRuleContentError(" 'subject_categories' key not found ")
+
+ for sub_cat in meta_rules[meta_rule_id]['subject_categories']:
+ if sub_cat not in result:
+ result[sub_cat] = []
+ result[sub_cat].extend(
+ self.cache.get_subject_assignments(policy_id, _subject, sub_cat))
+
+ if 'object_categories' not in meta_rules[meta_rule_id]:
+ raise exceptions.MetaRuleContentError(" 'object_categories' key not found ")
+
+ for obj_cat in meta_rules[meta_rule_id]['object_categories']:
+ if obj_cat not in result:
+ result[obj_cat] = []
+ result[obj_cat].extend(
+ self.cache.get_object_assignments(policy_id, _object, obj_cat))
+
+ if 'action_categories' not in meta_rules[meta_rule_id]:
+ raise exceptions.MetaRuleContentError(" 'action_categories' key not found ")
+
+ for act_cat in meta_rules[meta_rule_id]['action_categories']:
+ if act_cat not in result:
+ result[act_cat] = []
+ result[act_cat].extend(
+ self.cache.get_action_assignments(policy_id, _action, act_cat))
+
+ return result
+
+ def __repr__(self):
+ return """PDP ID: {id}
+current_request: {current_request}
+request_id: {request_id}
+index: {index}
+headers: {headers}
+pdp_set: {pdp_set}
+ """.format(
+ id=self.__pdp_id,
+ current_request=self.__current_request,
+ request_id=self.__request_id,
+ headers=self.__meta_rule_ids,
+ pdp_set=self.__pdp_set,
+ index=self.__index
+ )
+
+ def to_dict(self):
+ return {
+ "initial_request": copy.deepcopy(self.initial_request),
+ "current_request": copy.deepcopy(self.__current_request),
+ "headers": copy.deepcopy(self.__meta_rule_ids),
+ "index": copy.deepcopy(self.__index),
+ "pdp_set": copy.deepcopy(self.__pdp_set),
+ "request_id": copy.deepcopy(self.__request_id),
+ "manager_url": copy.deepcopy(self.__manager_url),
+ "interface_name": copy.deepcopy(self.__interface_name),
+ }
+
+ @property
+ def request_id(self):
+ return self.__request_id
+
+ @request_id.setter
+ def request_id(self, value):
+ raise Exception("You cannot update the request_id")
+
+ @request_id.deleter
+ def request_id(self):
+ raise Exception("You cannot update the request_id")
+
+ @property
+ def manager_url(self):
+ return self.__manager_url
+
+ @manager_url.setter
+ def manager_url(self, value):
+ raise Exception("You cannot update the manager_url")
+
+ @manager_url.deleter
+ def manager_url(self):
+ raise Exception("You cannot update the manager_url")
+
+ @property
+ def interface_name(self):
+ return self.__interface_name
+
+ @interface_name.setter
+ def interface_name(self, value):
+ raise Exception("You cannot update the interface_name")
+
+ @interface_name.deleter
+ def interface_name(self):
+ raise Exception("You cannot update the interface_name")
+
+ @property
+ def cookie(self):
+ return self.__cookie
+
+ @cookie.setter
+ def cookie(self, value):
+ raise Exception("You cannot update the cookie")
+
+ @cookie.deleter
+ def cookie(self):
+ raise Exception("You cannot delete the cookie")
+
+ @property
+ def initial_request(self):
+ return {
+ "subject": self.__subject,
+ "object": self.__object,
+ "action": self.__action,
+ }
+
+ @initial_request.setter
+ def initial_request(self, value):
+ raise Exception("You are not allowed to update the initial_request")
+
+ @initial_request.deleter
+ def initial_request(self):
+ raise Exception("You are not allowed to delete the initial_request")
+
+ @property
+ def current_request(self):
+ if not self.__current_request:
+ self.__current_request = dict(self.initial_request)
+ return self.__current_request
+
+ @current_request.setter
+ def current_request(self, value):
+
+ self.__current_request = copy.deepcopy(value)
+ # Note (asteroide): if the current request is modified,
+ # we must update the PDP Set.
+ self.__init_pdp_set()
+
+ @current_request.deleter
+ def current_request(self):
+ self.__current_request = {}
+ self.__pdp_set = {}
+
+ '''
+ [Note ] Refactor name of headers to meta_rule_ids done ,
+ may need to refactor getter and setter of headers
+ '''
+
+ @property
+ def headers(self):
+ return self.__meta_rule_ids
+
+ @headers.setter
+ def headers(self, meta_rule_ids):
+ self.__meta_rule_ids = meta_rule_ids
+
+ @headers.deleter
+ def headers(self):
+ self.__meta_rule_ids = list()
+
+ @property
+ def index(self):
+ return self.__index
+
+ @index.setter
+ def index(self, index):
+ self.__index += 1
+
+ @index.deleter
+ def index(self):
+ self.__index = -1
+
+ @property
+ def pdp_set(self):
+ return self.__pdp_set
+
+ @pdp_set.setter
+ def pdp_set(self, value):
+ raise Exception("You are not allowed to modify the pdp_set")
+
+ @pdp_set.deleter
+ def pdp_set(self):
+ self.__pdp_set = {}
+
+ def __validate_meta_rule_content(self, meta_rules):
+ if 'effect' not in meta_rules:
+ logger.error("meta_rules={}".format(meta_rules))
+ raise exceptions.PdpContentError("effect not in meta_rules")
diff --git a/old/python_moonutilities/python_moonutilities/exceptions.py b/old/python_moonutilities/python_moonutilities/exceptions.py
new file mode 100644
index 00000000..8ad90e96
--- /dev/null
+++ b/old/python_moonutilities/python_moonutilities/exceptions.py
@@ -0,0 +1,833 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import logging
+from werkzeug.exceptions import HTTPException
+
+logger = logging.getLogger("moon.utilities.exceptions")
+_ = str
+
+
+class MoonErrorMetaClass(type):
+
+ def __init__(cls, name, bases, dct):
+ super(MoonErrorMetaClass, cls).__init__(name, bases, dct)
+ cls.hierarchy += "/" + str(name)
+
+
+class MoonError(HTTPException):
+ __metaclass__ = MoonErrorMetaClass
+ hierarchy = ""
+ description = _("There is an error requesting the Moon platform.")
+ code = 400
+ title = 'Moon Error'
+ logger = "ERROR"
+
+ def __init__(self, message="", status_code=None, payload=""):
+ if message:
+ self.description = message
+ if status_code:
+ self.code = status_code
+ self.payload = payload
+ super(MoonError, self).__init__()
+
+ def __str__(self):
+ return "{}: {}".format(self.code, self.title)
+
+ def __del__(self):
+ message = "{} ({}) {}".format(self.hierarchy, self.description, self.payload)
+ if self.logger == "ERROR":
+ try:
+ logger.error(message)
+ except AttributeError:
+ logger.error(message)
+ elif self.logger == "WARNING":
+ try:
+ logger.warning(message)
+ except AttributeError:
+ logger.warning(message)
+ elif self.logger == "CRITICAL":
+ try:
+ logger.critical(message)
+ except AttributeError:
+ logger.critical(message)
+ elif self.logger == "AUTHZ":
+ try:
+ logger.authz(self.hierarchy)
+ logger.error(message)
+ except AttributeError:
+ logger.error(message)
+ else:
+ try:
+ logger.info(message)
+ except AttributeError:
+ logger.info(message)
+
+ # def to_dict(self):
+ # rv = dict(self.payload or ())
+ # rv['message'] = "{} ({})".format(self.hierarchy, self.description)
+ # rv['title'] = self.title
+ # rv['code'] = self.code
+ # return rv
+
+
+# Exceptions for Tenant
+
+class TenantException(MoonError):
+ description = _("There is an error requesting this tenant.")
+ code = 400
+ title = 'Tenant Error'
+ logger = "ERROR"
+
+
+class TenantUnknown(TenantException):
+ description = _("The tenant is unknown.")
+ code = 400
+ title = 'Tenant Unknown'
+ logger = "ERROR"
+
+
+class TenantAddedNameExisting(TenantException):
+ description = _("The tenant name is existing.")
+ code = 400
+ title = 'Added Tenant Name Existing'
+ logger = "ERROR"
+
+
+class TenantNoIntraExtension(TenantException):
+ description = _("The tenant has not intra_extension.")
+ code = 400
+ title = 'Tenant No Intra_Extension'
+ logger = "ERROR"
+
+
+class TenantNoIntraAuthzExtension(TenantNoIntraExtension):
+ description = _("The tenant has not intra_admin_extension.")
+ code = 400
+ title = 'Tenant No Intra_Admin_Extension'
+ logger = "ERROR"
+
+
+# Exceptions for IntraExtension
+
+
+class IntraExtensionException(MoonError):
+ description = _("There is an error requesting this IntraExtension.")
+ code = 400
+ title = 'Extension Error'
+
+
+class IntraExtensionUnknown(IntraExtensionException):
+ description = _("The intra_extension is unknown.")
+ code = 400
+ title = 'Intra Extension Unknown'
+ logger = "Error"
+
+
+class ModelUnknown(MoonError):
+ description = _("The model is unknown.")
+ code = 400
+ title = 'Model Unknown'
+ logger = "Error"
+
+
+class ModelContentError(MoonError):
+ description = _("The model content is invalid.")
+ code = 400
+ title = 'Model Unknown'
+ logger = "Error"
+
+
+class ModelExisting(MoonError):
+ description = _("The model already exists.")
+ code = 409
+ title = 'Model Error'
+ logger = "Error"
+
+
+# Authz exceptions
+
+class AuthzException(MoonError):
+ description = _("There is an authorization error requesting this IntraExtension.")
+ code = 403
+ title = 'Authz Exception'
+ logger = "AUTHZ"
+
+
+# Auth exceptions
+
+class AuthException(MoonError):
+ description = _("There is an authentication error requesting this API. "
+ "You must provide a valid token from Keystone.")
+ code = 401
+ title = 'Auth Exception'
+ logger = "AUTHZ"
+
+
+# Admin exceptions
+
+class AdminException(MoonError):
+ description = _("There is an error requesting this Authz IntraExtension.")
+ code = 400
+ title = 'Authz Exception'
+ logger = "AUTHZ"
+
+
+class AdminMetaData(AdminException):
+ code = 400
+ title = 'Metadata Exception'
+
+
+class AdminPerimeter(AdminException):
+ code = 400
+ title = 'Perimeter Exception'
+
+
+class AdminScope(AdminException):
+ code = 400
+ title = 'Scope Exception'
+
+
+class AdminAssignment(AdminException):
+ code = 400
+ title = 'Assignment Exception'
+
+
+class AdminMetaRule(AdminException):
+ code = 400
+ title = 'Aggregation Algorithm Exception'
+
+
+class AdminRule(AdminException):
+ code = 400
+ title = 'Rule Exception'
+
+
+class CategoryNameInvalid(AdminMetaData):
+ description = _("The given category name is invalid.")
+ code = 400
+ title = 'Category Name Invalid'
+ logger = "ERROR"
+
+
+class SubjectCategoryExisting(AdminMetaData):
+ description = _("The given subject category already exists.")
+ code = 409
+ title = 'Subject Category Existing'
+ logger = "ERROR"
+
+class ObjectCategoryExisting(AdminMetaData):
+ description = _("The given object category already exists.")
+ code = 409
+ title = 'Object Category Existing'
+ logger = "ERROR"
+
+class ActionCategoryExisting(AdminMetaData):
+ description = _("The given action category already exists.")
+ code = 409
+ title = 'Action Category Existing'
+ logger = "ERROR"
+
+
+class SubjectCategoryUnknown(AdminMetaData):
+ description = _("The given subject category is unknown.")
+ code = 400
+ title = 'Subject Category Unknown'
+ logger = "ERROR"
+
+
+class DeleteSubjectCategoryWithMetaRule(MoonError):
+ description = _("Cannot delete subject category used in meta rule ")
+ code = 400
+ title = 'Subject Category With Meta Rule Error'
+ logger = "Error"
+
+
+class DeleteObjectCategoryWithMetaRule(MoonError):
+ description = _("Cannot delete Object category used in meta rule ")
+ code = 400
+ title = 'Object Category With Meta Rule Error'
+ logger = "Error"
+
+
+class ObjectCategoryUnknown(AdminMetaData):
+ description = _("The given object category is unknown.")
+ code = 400
+ title = 'Object Category Unknown'
+ logger = "ERROR"
+
+
+class DeleteActionCategoryWithMetaRule(MoonError):
+ description = _("Cannot delete Action category used in meta rule ")
+ code = 400
+ title = 'Action Category With Meta Rule Error'
+ logger = "Error"
+
+
+class ActionCategoryUnknown(AdminMetaData):
+ description = _("The given action category is unknown.")
+ code = 400
+ title = 'Action Category Unknown'
+ logger = "ERROR"
+
+class PerimeterContentError(AdminPerimeter):
+ description = _("Perimeter content is invalid.")
+ code = 400
+ title = 'Perimeter content is invalid.'
+ logger = "ERROR"
+
+
+class DeletePerimeterWithAssignment(MoonError):
+ description = _("Cannot delete perimeter with assignment")
+ code = 400
+ title = 'Perimeter With Assignment Error'
+ logger = "Error"
+
+
+class SubjectUnknown(AdminPerimeter):
+ description = _("The given subject is unknown.")
+ code = 400
+ title = 'Subject Unknown'
+ logger = "ERROR"
+
+
+class ObjectUnknown(AdminPerimeter):
+ description = _("The given object is unknown.")
+ code = 400
+ title = 'Object Unknown'
+ logger = "ERROR"
+
+
+class ActionUnknown(AdminPerimeter):
+ description = _("The given action is unknown.")
+ code = 400
+ title = 'Action Unknown'
+ logger = "ERROR"
+
+
+class SubjectExisting(AdminPerimeter):
+ description = _("The given subject is existing.")
+ code = 409
+ title = 'Subject Existing'
+ logger = "ERROR"
+
+
+class ObjectExisting(AdminPerimeter):
+ description = _("The given object is existing.")
+ code = 409
+ title = 'Object Existing'
+ logger = "ERROR"
+
+
+class ActionExisting(AdminPerimeter):
+ description = _("The given action is existing.")
+ code = 409
+ title = 'Action Existing'
+ logger = "ERROR"
+
+
+class SubjectNameExisting(AdminPerimeter):
+ description = _("The given subject name is existing.")
+ code = 409
+ title = 'Subject Name Existing'
+ logger = "ERROR"
+
+
+class ObjectNameExisting(AdminPerimeter):
+ description = _("The given object name is existing.")
+ code = 409
+ title = 'Object Name Existing'
+ logger = "ERROR"
+
+
+class ActionNameExisting(AdminPerimeter):
+ description = _("The given action name is existing.")
+ code = 409
+ title = 'Action Name Existing'
+ logger = "ERROR"
+
+
+class ObjectsWriteNoAuthorized(AdminPerimeter):
+ description = _("The modification on Objects is not authorized.")
+ code = 400
+ title = 'Objects Write No Authorized'
+ logger = "AUTHZ"
+
+
+class ActionsWriteNoAuthorized(AdminPerimeter):
+ description = _("The modification on Actions is not authorized.")
+ code = 400
+ title = 'Actions Write No Authorized'
+ logger = "AUTHZ"
+
+
+class SubjectScopeUnknown(AdminScope):
+ description = _("The given subject scope is unknown.")
+ code = 400
+ title = 'Subject Scope Unknown'
+ logger = "ERROR"
+
+
+class ObjectScopeUnknown(AdminScope):
+ description = _("The given object scope is unknown.")
+ code = 400
+ title = 'Object Scope Unknown'
+ logger = "ERROR"
+
+
+class ActionScopeUnknown(AdminScope):
+ description = _("The given action scope is unknown.")
+ code = 400
+ title = 'Action Scope Unknown'
+ logger = "ERROR"
+
+
+class SubjectScopeExisting(AdminScope):
+ description = _("The given subject scope is existing.")
+ code = 409
+ title = 'Subject Scope Existing'
+ logger = "ERROR"
+
+
+class ObjectScopeExisting(AdminScope):
+ description = _("The given object scope is existing.")
+ code = 409
+ title = 'Object Scope Existing'
+ logger = "ERROR"
+
+
+class ActionScopeExisting(AdminScope):
+ description = _("The given action scope is existing.")
+ code = 409
+ title = 'Action Scope Existing'
+ logger = "ERROR"
+
+
+class SubjectScopeNameExisting(AdminScope):
+ description = _("The given subject scope name is existing.")
+ code = 409
+ title = 'Subject Scope Name Existing'
+ logger = "ERROR"
+
+
+class ObjectScopeNameExisting(AdminScope):
+ description = _("The given object scope name is existing.")
+ code = 409
+ title = 'Object Scope Name Existing'
+ logger = "ERROR"
+
+
+class ActionScopeNameExisting(AdminScope):
+ description = _("The given action scope name is existing.")
+ code = 409
+ title = 'Action Scope Name Existing'
+ logger = "ERROR"
+
+
+class SubjectAssignmentUnknown(AdminAssignment):
+ description = _("The given subject assignment value is unknown.")
+ code = 400
+ title = 'Subject Assignment Unknown'
+ logger = "ERROR"
+
+
+class ObjectAssignmentUnknown(AdminAssignment):
+ description = _("The given object assignment value is unknown.")
+ code = 400
+ title = 'Object Assignment Unknown'
+ logger = "ERROR"
+
+
+class ActionAssignmentUnknown(AdminAssignment):
+ description = _("The given action assignment value is unknown.")
+ code = 400
+ title = 'Action Assignment Unknown'
+ logger = "ERROR"
+
+
+class SubjectAssignmentExisting(AdminAssignment):
+ description = _("The given subject assignment value is existing.")
+ code = 409
+ title = 'Subject Assignment Existing'
+ logger = "ERROR"
+
+
+class ObjectAssignmentExisting(AdminAssignment):
+ description = _("The given object assignment value is existing.")
+ code = 409
+ title = 'Object Assignment Existing'
+ logger = "ERROR"
+
+
+class ActionAssignmentExisting(AdminAssignment):
+ description = _("The given action assignment value is existing.")
+ code = 409
+ title = 'Action Assignment Existing'
+ logger = "ERROR"
+
+
+class AggregationAlgorithmNotExisting(AdminMetaRule):
+ description = _("The given aggregation algorithm is not existing.")
+ code = 400
+ title = 'Aggregation Algorithm Not Existing'
+ logger = "ERROR"
+
+
+class AggregationAlgorithmUnknown(AdminMetaRule):
+ description = _("The given aggregation algorithm is unknown.")
+ code = 400
+ title = 'Aggregation Algorithm Unknown'
+ logger = "ERROR"
+
+
+class SubMetaRuleAlgorithmNotExisting(AdminMetaRule):
+ description = _("The given sub_meta_rule algorithm is unknown.")
+ code = 400
+ title = 'Sub_meta_rule Algorithm Unknown'
+ logger = "ERROR"
+
+
+class MetaRuleUnknown(AdminMetaRule):
+ description = _("The given meta rule is unknown.")
+ code = 400
+ title = 'Meta Rule Unknown'
+ logger = "ERROR"
+
+
+class MetaRuleNotLinkedWithPolicyModel(MoonError):
+ description = _("The meta rule is not found in the model attached to the policy.")
+ code = 400
+ title = 'MetaRule Not Linked With Model - Policy'
+ logger = "Error"
+
+
+class CategoryNotAssignedMetaRule(MoonError):
+ description = _("The category is not found in the meta rules attached to the policy.")
+ code = 400
+ title = 'Category Not Linked With Meta Rule - Policy'
+ logger = "Error"
+
+
+class SubMetaRuleNameExisting(AdminMetaRule):
+ description = _("The sub meta rule name already exists.")
+ code = 409
+ title = 'Sub Meta Rule Name Existing'
+ logger = "ERROR"
+
+
+class MetaRuleExisting(AdminMetaRule):
+ description = _("The meta rule already exists.")
+ code = 409
+ title = 'Meta Rule Existing'
+ logger = "ERROR"
+
+
+class MetaRuleContentError(AdminMetaRule):
+ description = _("Invalid content of meta rule.")
+ code = 400
+ title = 'Meta Rule Error'
+ logger = "ERROR"
+
+
+class MetaRuleUpdateError(AdminMetaRule):
+ description = _("Meta_rule is used in Rule.")
+ code = 400
+ title = 'Meta_Rule Update Error'
+ logger = "ERROR"
+
+
+class RuleExisting(AdminRule):
+ description = _("The rule already exists.")
+ code = 409
+ title = 'Rule Existing'
+ logger = "ERROR"
+
+
+class RuleContentError(AdminRule):
+ description = _("Invalid content of rule.")
+ code = 400
+ title = 'Rule Error'
+ logger = "ERROR"
+
+
+class RuleUnknown(AdminRule):
+ description = _("The rule for that request doesn't exist.")
+ code = 400
+ title = 'Rule Unknown'
+ logger = "ERROR"
+
+
+# Keystone exceptions
+
+
+class KeystoneError(MoonError):
+ description = _("There is an error connecting to Keystone.")
+ code = 400
+ title = 'Keystone error'
+ logger = "ERROR"
+
+
+class KeystoneProjectError(KeystoneError):
+ description = _("There is an error retrieving projects from the Keystone service.")
+ code = 400
+ title = 'Keystone project error'
+ logger = "ERROR"
+
+
+class KeystoneUserError(KeystoneError):
+ description = _("There is an error retrieving users from the Keystone service.")
+ code = 400
+ title = 'Keystone user error'
+ logger = "ERROR"
+
+
+class KeystoneUserConflict(KeystoneUserError):
+ description = _("A user with that name already exist.")
+ code = 400
+ title = 'Keystone user error'
+ logger = "ERROR"
+
+
+# Consul exceptions
+
+
+class ConsulError(MoonError):
+ description = _("There is an error connecting to Consul.")
+ code = 400
+ title = 'Consul error'
+ logger = "ERROR"
+
+
+class ConsulComponentNotFound(ConsulError):
+ description = _("The component do not exist in Consul database.")
+ code = 500
+ title = 'Consul error'
+ logger = "WARNING"
+
+
+class ConsulComponentContentError(ConsulError):
+ description = _("invalid content of component .")
+ code = 500
+ title = 'Consul Content error'
+ logger = "WARNING"
+
+
+# Containers exceptions
+
+
+class DockerError(MoonError):
+ description = _("There is an error with Docker.")
+ code = 400
+ title = 'Docker error'
+ logger = "ERROR"
+
+
+class ContainerMissing(DockerError):
+ description = _("Some containers are missing.")
+ code = 400
+ title = 'Container missing'
+ logger = "ERROR"
+
+
+class WrapperConflict(MoonError):
+ description = _("A Wrapper already exist for the specified slave.")
+ code = 409
+ title = 'Wrapper conflict'
+ logger = "ERROR"
+
+
+class PipelineConflict(MoonError):
+ description = _("A Pipeline already exist for the specified slave.")
+ code = 409
+ title = 'Pipeline conflict'
+ logger = "ERROR"
+
+
+class PipelineUnknown(MoonError):
+ description = _("This Pipeline is unknown from the system.")
+ code = 400
+ title = 'Pipeline Unknown'
+ logger = "ERROR"
+
+
+class WrapperUnknown(MoonError):
+ description = _("This Wrapper is unknown from the system.")
+ code = 400
+ title = 'Wrapper Unknown'
+ logger = "ERROR"
+
+
+class SlaveNameUnknown(MoonError):
+ description = _("The slave is unknown.")
+ code = 400
+ title = 'Slave Unknown'
+ logger = "Error"
+
+
+class PdpUnknown(MoonError):
+ description = _("The pdp is unknown.")
+ code = 400
+ title = 'Pdp Unknown'
+ logger = "Error"
+
+
+class PdpExisting(MoonError):
+ description = _("The pdp already exists.")
+ code = 409
+ title = 'Pdp Error'
+ logger = "Error"
+
+
+class PdpContentError(MoonError):
+ description = _("Invalid content of pdp.")
+ code = 400
+ title = 'Pdp Error'
+ logger = "Error"
+
+
+class PdpKeystoneMappingConflict(MoonError):
+ description = _("A pdp is already mapped to that Keystone project.")
+ code = 409
+ title = 'Pdp Mapping Error'
+ logger = "Error"
+
+
+class PolicyUnknown(MoonError):
+ description = _("The policy is unknown.")
+ code = 400
+ title = 'Policy Unknown'
+ logger = "Error"
+
+class PolicyContentError(MoonError):
+ description = _("The policy content is invalid.")
+ code = 400
+ title = 'Policy Content Error'
+ logger = "Error"
+
+
+class PolicyExisting(MoonError):
+ description = _("The policy already exists.")
+ code = 409
+ title = 'Policy Already Exists'
+ logger = "Error"
+
+
+class PolicyUpdateError(MoonError):
+ description = _("The policy data is used.")
+ code = 400
+ title = 'Policy update error'
+ logger = "Error"
+
+
+class DeleteData(MoonError):
+ description = _("Cannot delete data with assignment")
+ code = 400
+ title = 'Data Error'
+ logger = "Error"
+
+
+class DeleteCategoryWithData(MoonError):
+ description = _("Cannot delete category with data")
+ code = 400
+ title = 'Category With Data Error'
+ logger = "Error"
+
+
+class DeleteCategoryWithMetaRule(MoonError):
+ description = _("Cannot delete category with meta rule")
+ code = 400
+ title = 'Category With MetaRule Error'
+ logger = "Error"
+
+
+class DeleteCategoryWithAssignment(MoonError):
+ description = _("Cannot delete category with assignment ")
+ code = 400
+ title = 'Category With Assignment Error'
+ logger = "Error"
+
+
+class DeleteModelWithPolicy(MoonError):
+ description = _("Cannot delete model with policy")
+ code = 400
+ title = 'Model With Policy Error'
+ logger = "Error"
+
+
+class DeletePolicyWithPdp(MoonError):
+ description = _("Cannot delete policy with pdp")
+ code = 400
+ title = 'Policy With PDP Error'
+ logger = "Error"
+
+
+class DeletePolicyWithPerimeter(MoonError):
+ description = _("Cannot delete policy with perimeter")
+ code = 400
+ title = 'Policy With Perimeter Error'
+ logger = "Error"
+
+
+class DeletePolicyWithData(MoonError):
+ description = _("Cannot delete policy with data")
+ code = 400
+ title = 'Policy With Data Error'
+ logger = "Error"
+
+
+class DeletePolicyWithRules(MoonError):
+ description = _("Cannot delete policy with rules")
+ code = 400
+ title = 'Policy With Rule Error'
+ logger = "Error"
+
+
+class DeleteMetaRuleWithModel(MoonError):
+ description = _("Cannot delete meta rule with model")
+ code = 400
+ title = 'Meta rule With Model Error'
+ logger = "Error"
+
+
+class DeleteMetaRuleWithRule(MoonError):
+ description = _("Cannot delete meta rule with rule")
+ code = 400
+ title = 'Meta rule With Model Error'
+ logger = "Error"
+
+
+class DataUnknown(MoonError):
+ description = _("The data unknown.")
+ code = 400
+ title = 'Data Unknown'
+ logger = "Error"
+
+
+class ValidationContentError(MoonError):
+ description = _("The Content validation incorrect.")
+ code = 400
+ title = 'Invalid Content'
+ logger = "Error"
+
+ def __init__(self, message=""):
+ self.message = message
+ super().__init__(message)
+
+ def __str__(self):
+ return self.message
+
+
+class ValidationKeyError(MoonError):
+ description = _("The Key validation incorrect.")
+ code = 400
+ title = 'Invalid Key'
+ logger = "Error"
+
+ def __init__(self, message=""):
+ self.message = message
+ super().__init__(message)
+
+ def __str__(self):
+ return self.message
diff --git a/old/python_moonutilities/python_moonutilities/misc.py b/old/python_moonutilities/python_moonutilities/misc.py
new file mode 100644
index 00000000..1db4d7cd
--- /dev/null
+++ b/old/python_moonutilities/python_moonutilities/misc.py
@@ -0,0 +1,116 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+import logging
+import random
+
+logger = logging.getLogger("moon.utilities.misc")
+
+
+def get_random_name():
+ _list = (
+ "windy",
+ "vengeful",
+ "precious",
+ "vivacious",
+ "quiet",
+ "confused",
+ "exultant",
+ "impossible",
+ "thick",
+ "obsolete",
+ "piquant",
+ "fanatical",
+ "tame",
+ "perfect",
+ "animated",
+ "dark",
+ "stimulating",
+ "drunk",
+ "depressed",
+ "fumbling",
+ "like",
+ "undesirable",
+ "spurious",
+ "subsequent",
+ "spiteful",
+ "last",
+ "stale",
+ "hulking",
+ "giddy",
+ "minor",
+ "careful",
+ "possessive",
+ "gullible",
+ "fragile",
+ "divergent",
+ "ill-informed",
+ "false",
+ "jumpy",
+ "damaged",
+ "likeable",
+ "volatile",
+ "handsomely",
+ "wet",
+ "long-term",
+ "pretty",
+ "taboo",
+ "normal",
+ "magnificent",
+ "nutty",
+ "puzzling",
+ "small",
+ "kind",
+ "devilish",
+ "chubby",
+ "paltry",
+ "cultured",
+ "old",
+ "defective",
+ "hanging",
+ "innocent",
+ "jagged",
+ "economic",
+ "good",
+ "sulky",
+ "real",
+ "bent",
+ "shut",
+ "furry",
+ "terrific",
+ "hollow",
+ "terrible",
+ "mammoth",
+ "pleasant",
+ "scared",
+ "obnoxious",
+ "absorbing",
+ "imported",
+ "infamous",
+ "grieving",
+ "ill-fated",
+ "mighty",
+ "handy",
+ "comfortable",
+ "astonishing",
+ "brown",
+ "assorted",
+ "wrong",
+ "unsightly",
+ "spooky",
+ "delightful",
+ "acid",
+ "inconclusive",
+ "mere",
+ "careless",
+ "historical",
+ "flashy",
+ "squealing",
+ "quarrelsome",
+ "empty",
+ "long",
+ )
+ return random.choice(_list)
diff --git a/old/python_moonutilities/python_moonutilities/request_wrapper.py b/old/python_moonutilities/python_moonutilities/request_wrapper.py
new file mode 100644
index 00000000..f1603b9d
--- /dev/null
+++ b/old/python_moonutilities/python_moonutilities/request_wrapper.py
@@ -0,0 +1,22 @@
+import sys
+import requests
+from python_moonutilities import exceptions
+
+def get(url):
+ try:
+ response = requests.get(url)
+ except requests.exceptions.RequestException as e:
+ raise exceptions.ConsulError("request failure ",e)
+ except:
+ raise exceptions.ConsulError("Unexpected error ", sys.exc_info()[0])
+ return response
+
+
+def put(url, json=""):
+ try:
+ response = requests.put(url,json=json)
+ except requests.exceptions.RequestException as e:
+ raise exceptions.ConsulError("request failure ",e)
+ except:
+ raise exceptions.ConsulError("Unexpected error ", sys.exc_info()[0])
+ return response \ No newline at end of file
diff --git a/old/python_moonutilities/python_moonutilities/security_functions.py b/old/python_moonutilities/python_moonutilities/security_functions.py
new file mode 100644
index 00000000..1069eb2f
--- /dev/null
+++ b/old/python_moonutilities/python_moonutilities/security_functions.py
@@ -0,0 +1,331 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+import html
+import re
+import os
+import types
+import requests
+import time
+from functools import wraps
+from flask import request
+import logging
+from python_moonutilities import exceptions, configuration
+
+logger = logging.getLogger("moon.utilities." + __name__)
+
+keystone_config = configuration.get_configuration("openstack/keystone")["openstack/keystone"]
+TOKENS = {}
+__targets = {}
+
+
+def filter_input(func_or_str):
+
+ def __filter(string):
+ if string and type(string) is str:
+ return "".join(re.findall("[\w\- +]*", string))
+ return string
+
+ def __filter_dict(arg):
+ result = dict()
+ for key in arg.keys():
+ if key == "email":
+ result["email"] = __filter_email(arg[key])
+ elif key == "password":
+ result["password"] = arg['password']
+ else:
+ result[key] = __filter(arg[key])
+ return result
+
+ def __filter_email(string):
+ if string and type(string) is str:
+ return "".join(re.findall("[\w@\._\- +]*", string))
+ return string
+
+ def wrapped(*args, **kwargs):
+ _args = []
+ for arg in args:
+ if isinstance(arg, str):
+ arg = __filter(arg)
+ elif isinstance(arg, list):
+ arg = [__filter(item) for item in arg]
+ elif isinstance(arg, tuple):
+ arg = (__filter(item) for item in arg)
+ elif isinstance(arg, dict):
+ arg = __filter_dict(arg)
+ _args.append(arg)
+ for arg in kwargs:
+ if type(kwargs[arg]) is str:
+ kwargs[arg] = __filter(kwargs[arg])
+ if isinstance(kwargs[arg], str):
+ kwargs[arg] = __filter(kwargs[arg])
+ elif isinstance(kwargs[arg], list):
+ kwargs[arg] = [__filter(item) for item in kwargs[arg]]
+ elif isinstance(kwargs[arg], tuple):
+ kwargs[arg] = (__filter(item) for item in kwargs[arg])
+ elif isinstance(kwargs[arg], dict):
+ kwargs[arg] = __filter_dict(kwargs[arg])
+ return func_or_str(*_args, **kwargs)
+
+ if isinstance(func_or_str, str):
+ return __filter(func_or_str)
+ if isinstance(func_or_str, list):
+ return [__filter(item) for item in func_or_str]
+ if isinstance(func_or_str, tuple):
+ return (__filter(item) for item in func_or_str)
+ if isinstance(func_or_str, dict):
+ return __filter_dict(func_or_str)
+ if isinstance(func_or_str, types.FunctionType):
+ return wrapped
+ return None
+
+
+"""
+To do should check value of Dictionary but it's dependent on from where it's coming
+"""
+
+
+def validate_data(data):
+ def __validate_string(string):
+ temp_str = html.escape(string)
+ if string != temp_str:
+ raise exceptions.ValidationContentError('Forbidden characters in string')
+
+ def __validate_list_or_tuple(container):
+ for i in container:
+ validate_data(i)
+
+ def __validate_dict(dictionary):
+ for key in dictionary:
+ validate_data(dictionary[key])
+
+ if isinstance(data, bool):
+ return True
+ if data is None:
+ data = ""
+ if isinstance(data, str):
+ __validate_string(data)
+ elif isinstance(data, list) or isinstance(data, tuple):
+ __validate_list_or_tuple(data)
+ elif isinstance(data, dict):
+ __validate_dict(data)
+ else:
+ raise exceptions.ValidationContentError('Value is Not String or Container or Dictionary: {}'.format(data))
+
+
+def validate_input(type='get', args_state=[], kwargs_state=[], body_state=[]):
+ """
+ this fucntion works only on List or tuple or dictionary of Strings ,and String direct
+ Check if input of function is Valid or not, Valid if not has spaces and values is not None or empty.
+
+ :param type: type of request if function is used as decorator
+ :param args_state: list of Booleans for args,
+ values must be order as target values of arguments,
+ True if None is not Allowed and False if is allowed
+ :param kwargs_state: list of Booleans for kwargs as order of input kwargs,
+ values must be order as target values of arguments,
+ True if None is not Allowed and False if is allowed
+ :param body_state: list of Booleans for arguments in body of request if request is post,
+ values must be order as target values of arguments,
+ True if None is not Allowed and False if is allowed
+ :return:
+ """
+
+ def validate_input_decorator(func):
+ def wrapped(*args, **kwargs):
+
+ temp_args = []
+ """
+ this loop made to filter args from object class,
+ when put this function as decorator in function control
+ then there is copy of this class add to front of args
+ """
+ for arg in args:
+ if isinstance(arg, str) == True or \
+ isinstance(arg, list) == True or \
+ isinstance(arg, dict) == True:
+ temp_args.append(arg)
+
+ while len(args_state) < len(temp_args):
+ args_state.append(True)
+
+ for i in range(0, len(temp_args)):
+ if args_state[i]:
+ validate_data(temp_args[i])
+
+ while len(kwargs_state) < len(kwargs):
+ kwargs_state.append(False)
+ counter = 0
+ for i in kwargs:
+ if kwargs_state[counter]:
+ validate_data(kwargs[i])
+
+ counter = counter + 1
+
+ if type == "post" or type == "patch":
+ body = request.json
+ # while len(body_state) < len(body):
+ # body_state.append(True)
+ # counter = 0
+ for key in body_state:
+ if key in body:
+ if body_state[key]:
+ try:
+ validate_data(body.get(key))
+ except exceptions.ValidationContentError as e:
+ raise exceptions.ValidationContentError("Key: '{}', [{}]".format(key, str(e)))
+ else:
+ raise exceptions.ValidationKeyError('Invalid Key :{} not found'.format(key))
+
+ # counter = counter + 1
+
+ return func(*args, **kwargs)
+
+ return wrapped
+
+ return validate_input_decorator
+
+
+def enforce(action_names, object_name, **extra):
+ """Fake version of the enforce decorator"""
+ def wrapper_func(func):
+ def wrapper_args(*args, **kwargs):
+ # LOG.info("kwargs={}".format(kwargs))
+ # kwargs['user_id'] = kwargs.pop('user_id', "admin")
+ # LOG.info("Calling enforce on {} with args={} kwargs={}".format(func.__name__, args, kwargs))
+ return func(*args, **kwargs)
+ return wrapper_args
+ return wrapper_func
+
+
+def login(user=None, password=None, domain=None, project=None, url=None):
+ start_time = time.time()
+ if not user:
+ user = keystone_config['user']
+ if not password:
+ password = keystone_config['password']
+ if not domain:
+ domain = keystone_config['domain']
+ if not project:
+ project = keystone_config['project']
+ if not url:
+ url = keystone_config['url']
+ headers = {
+ "Content-Type": "application/json"
+ }
+ data_auth = {
+ "auth": {
+ "identity": {
+ "methods": [
+ "password"
+ ],
+ "password": {
+ "user": {
+ "domain": {
+ "id": domain
+ },
+ "name": user,
+ "password": password
+ }
+ }
+ },
+ "scope": {
+ "project": {
+ "domain": {
+ "id": domain
+ },
+ "name": project
+ }
+ }
+ }
+ }
+
+ while True:
+ req = requests.post("{}/auth/tokens".format(url),
+ json=data_auth, headers=headers,
+ verify=keystone_config['certificate'])
+
+ if req.status_code in (200, 201, 204):
+ headers['X-Auth-Token'] = req.headers['X-Subject-Token']
+ return headers
+ logger.warning("Waiting for Keystone...")
+ if time.time() - start_time == 100:
+ logger.error(req.text)
+ raise exceptions.KeystoneError
+ time.sleep(5)
+
+
+def logout(headers, url=None):
+ if not url:
+ url = keystone_config['url']
+ headers['X-Subject-Token'] = headers['X-Auth-Token']
+ req = requests.delete("{}/auth/tokens".format(url), headers=headers, verify=keystone_config['certificate'])
+ if req.status_code in (200, 201, 204):
+ return
+ logger.error(req.text)
+ raise exceptions.KeystoneError
+
+
+def check_token(token, url=None):
+ _verify = False
+ if keystone_config['certificate']:
+ _verify = keystone_config['certificate']
+ try:
+ os.environ.pop("http_proxy")
+ os.environ.pop("https_proxy")
+ except KeyError:
+ pass
+ if not url:
+ url = keystone_config['url']
+ headers = {
+ "Content-Type": "application/json",
+ 'X-Subject-Token': token,
+ 'X-Auth-Token': token,
+ }
+ if not keystone_config['check_token']:
+ # TODO (asteroide): must send the admin id
+ return "admin" if not token else token
+ elif keystone_config['check_token'].lower() in ("false", "no", "n"):
+ # TODO (asteroide): must send the admin id
+ return "admin" if not token else token
+ if keystone_config['check_token'].lower() in ("yes", "y", "true"):
+ if token in TOKENS:
+ delta = time.mktime(TOKENS[token]["expires_at"]) - time.mktime(time.gmtime())
+ if delta > 0:
+ return TOKENS[token]["user"]
+ raise exceptions.KeystoneError
+ else:
+ req = requests.get("{}/auth/tokens".format(url), headers=headers, verify=_verify)
+ if req.status_code in (200, 201):
+ # Note (asteroide): the time stamps is not in ISO 8601, so it is necessary to delete
+ # characters after the dot
+ token_time = req.json().get("token").get("expires_at").split(".")
+ TOKENS[token] = dict()
+ TOKENS[token]["expires_at"] = time.strptime(token_time[0], "%Y-%m-%dT%H:%M:%S")
+ TOKENS[token]["user"] = req.json().get("token").get("user").get("id")
+ return TOKENS[token]["user"]
+ logger.error("{} - {}".format(req.status_code, req.text))
+ raise exceptions.KeystoneError
+ elif keystone_config['check_token'].lower() == "strict":
+ req = requests.head("{}/auth/tokens".format(url), headers=headers, verify=_verify)
+ if req.status_code in (200, 201):
+ return token
+ logger.error("{} - {}".format(req.status_code, req.text))
+ raise exceptions.KeystoneError
+ raise exceptions.KeystoneError
+
+
+def check_auth(function):
+ @wraps(function)
+ def wrapper(*args, **kwargs):
+ token = request.headers.get('X-Auth-Token')
+ token = check_token(token)
+ if not token:
+ raise exceptions.AuthException
+ user_id = kwargs.pop("user_id", token)
+ result = function(*args, **kwargs, user_id=user_id)
+ return result
+ return wrapper
diff --git a/old/python_moonutilities/requirements.txt b/old/python_moonutilities/requirements.txt
new file mode 100644
index 00000000..5b80e5f2
--- /dev/null
+++ b/old/python_moonutilities/requirements.txt
@@ -0,0 +1,3 @@
+werkzeug
+flask
+requests \ No newline at end of file
diff --git a/old/python_moonutilities/setup.py b/old/python_moonutilities/setup.py
new file mode 100644
index 00000000..4a2eef5d
--- /dev/null
+++ b/old/python_moonutilities/setup.py
@@ -0,0 +1,42 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+from setuptools import setup, find_packages
+import python_moonutilities
+
+with open('requirements.txt') as f:
+ required = f.read().splitlines()
+
+setup(
+
+ name='python-moonutilities',
+
+ version=python_moonutilities.__version__,
+
+ packages=find_packages(),
+
+ author='Thomas Duval',
+
+ author_email='thomas.duval@orange.com',
+
+ description='Some utilities for all the Moon components',
+
+ long_description=open('README.md').read(),
+
+ install_requires=required,
+
+ include_package_data=True,
+
+ url='https://git.opnfv.org/cgit/moon',
+
+ classifiers=[
+ 'Programming Language :: Python :: 3',
+ 'Development Status :: 1 - Planning',
+ 'License :: OSI Approved',
+ 'Natural Language :: English',
+ 'Operating System :: OS Independent',
+ ],
+
+)
diff --git a/old/python_moonutilities/tests/unit_python/conftest.py b/old/python_moonutilities/tests/unit_python/conftest.py
new file mode 100644
index 00000000..34e5c272
--- /dev/null
+++ b/old/python_moonutilities/tests/unit_python/conftest.py
@@ -0,0 +1,14 @@
+import pytest
+import requests_mock
+import mock_repo
+
+
+@pytest.fixture(autouse=True)
+def no_requests(monkeypatch):
+ """ Modify the response from Requests module
+ """
+ with requests_mock.Mocker(real_http=True) as m:
+ mock_repo.register_cache(m)
+
+ print("End registering URI")
+ yield m \ No newline at end of file
diff --git a/old/python_moonutilities/tests/unit_python/mock_repo/__init__.py b/old/python_moonutilities/tests/unit_python/mock_repo/__init__.py
new file mode 100644
index 00000000..fa50edb3
--- /dev/null
+++ b/old/python_moonutilities/tests/unit_python/mock_repo/__init__.py
@@ -0,0 +1,42 @@
+import mock_repo.urls as register_urls
+import mock_repo.data as data_mock
+
+
+def register_cache(m):
+ """ Modify the response from Requests module
+ """
+ register_urls.register_components(m)
+ register_urls.register_keystone(m)
+
+ register_urls.register_pdp(m)
+ register_urls.register_meta_rules(m)
+ register_urls.register_policies(m)
+ register_urls.register_models(m)
+
+ register_urls.register_policy_subject(m, data_mock.shared_ids["policy"]["policy_id_1"])
+ register_urls.register_policy_subject_invalid_response(m, data_mock.shared_ids["policy"]["policy_id_invalid_response"])
+
+ register_urls.register_policy_object(m, data_mock.shared_ids["policy"]["policy_id_1"])
+ register_urls.register_policy_object_invalid_response(m, data_mock.shared_ids["policy"]["policy_id_invalid_response"])
+
+ register_urls.register_policy_action(m, data_mock.shared_ids["policy"]["policy_id_1"])
+ register_urls.register_policy_action_invalid_response(m, data_mock.shared_ids["policy"]["policy_id_invalid_response"])
+
+ register_urls.register_policy_subject_assignment(m, data_mock.shared_ids["policy"]["policy_id_1"], data_mock.shared_ids["perimeter"]["perimeter_id_1"])
+
+ register_urls.register_policy_subject_assignment_list(m, data_mock.shared_ids["policy"]["policy_id_2"])
+
+ register_urls.register_policy_object_assignment(m, data_mock.shared_ids["policy"]["policy_id_1"], data_mock.shared_ids["perimeter"]["perimeter_id_2"])
+
+ register_urls.register_policy_object_assignment_list(m, data_mock.shared_ids["policy"]["policy_id_2"])
+
+ register_urls.register_policy_action_assignment(m, data_mock.shared_ids["policy"]["policy_id_1"], data_mock.shared_ids["perimeter"]["perimeter_id_3"])
+
+ register_urls.register_policy_action_assignment_list(m, data_mock.shared_ids["policy"]["policy_id_2"])
+ # register_urls.register_pods(m)
+
+ # register_urls.register_policy_action_assignment(m, "policy_id_2", "perimeter_id_2")
+ # register_urls.register_policy_action_assignment(m, "policy_id_2", "perimeter_id_2")
+ # register_urls.register_policy_action_assignment(m, "policy_id_2", "perimeter_id_2")
+
+ register_urls.register_rules(m, "policy_id1")
diff --git a/old/python_moonutilities/tests/unit_python/mock_repo/components_utilities.py b/old/python_moonutilities/tests/unit_python/mock_repo/components_utilities.py
new file mode 100644
index 00000000..11686ce4
--- /dev/null
+++ b/old/python_moonutilities/tests/unit_python/mock_repo/components_utilities.py
@@ -0,0 +1,136 @@
+import base64
+import json
+
+
+CONF = {
+ "openstack": {
+ "keystone": {
+ "url": "http://keystone:5000/v3",
+ "user": "admin",
+ "check_token": False,
+ "password": "p4ssw0rd",
+ "domain": "default",
+ "certificate": False,
+ "project": "admin"
+ }
+ },
+ "components": {
+ "wrapper": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_wrapper:v4.3",
+ "timeout": 5,
+ "hostname": "wrapper"
+ },
+ "manager": {
+ "bind": "0.0.0.0",
+ "port": 8082,
+ "container": "wukongsun/moon_manager:v4.3",
+ "hostname": "manager"
+ },
+ "port_start": 31001,
+ "orchestrator": {
+ "bind": "0.0.0.0",
+ "port": 8083,
+ "container": "wukongsun/moon_orchestrator:v4.3",
+ "hostname": "interface"
+ },
+ "pipeline": {
+ "interface": {
+ "bind": "0.0.0.0",
+ "port": 8080,
+ "container": "wukongsun/moon_interface:v4.3",
+ "hostname": "interface"
+ },
+ "authz": {
+ "bind": "0.0.0.0",
+ "port": 8081,
+ "container": "wukongsun/moon_authz:v4.3",
+ "hostname": "authz"
+ },
+ }
+ },
+ "logging": {
+ "handlers": {
+ "file": {
+ "filename": "/tmp/moon.log",
+ "class": "logging.handlers.RotatingFileHandler",
+ "level": "DEBUG",
+ "formatter": "custom",
+ "backupCount": 3,
+ "maxBytes": 1048576
+ },
+ "console": {
+ "class": "logging.StreamHandler",
+ "formatter": "brief",
+ "level": "INFO",
+ "stream": "ext://sys.stdout"
+ }
+ },
+ "formatters": {
+ "brief": {
+ "format": "%(levelname)s %(name)s %(message)-30s"
+ },
+ "custom": {
+ "format": "%(asctime)-15s %(levelname)s %(name)s %(message)s"
+ }
+ },
+ "root": {
+ "handlers": [
+ "console"
+ ],
+ "level": "ERROR"
+ },
+ "version": 1,
+ "loggers": {
+ "moon": {
+ "handlers": [
+ "console",
+ "file"
+ ],
+ "propagate": False,
+ "level": "DEBUG"
+ }
+ }
+ },
+ "slave": {
+ "name": None,
+ "master": {
+ "url": None,
+ "login": None,
+ "password": None
+ }
+ },
+ "docker": {
+ "url": "tcp://172.88.88.1:2376",
+ "network": "moon"
+ },
+ "database": {
+ "url": "sqlite:///database.db",
+ # "url": "mysql+pymysql://moon:p4sswOrd1@db/moon",
+ "driver": "sql"
+ },
+ "messenger": {
+ "url": "rabbit://moon:p4sswOrd1@messenger:5672/moon"
+ }
+}
+
+
+def get_b64_conf(component=None):
+ if component == "components":
+ return base64.b64encode(
+ json.dumps(CONF["components"]).encode('utf-8')+b"\n").decode('utf-8')
+ elif component in CONF:
+ return base64.b64encode(
+ json.dumps(
+ CONF[component]).encode('utf-8')+b"\n").decode('utf-8')
+ elif not component:
+ return base64.b64encode(
+ json.dumps(CONF).encode('utf-8')+b"\n").decode('utf-8')
+ elif "/" in component:
+ key1, _, key2 = component.partition("/")
+ return base64.b64encode(
+ json.dumps(
+ CONF[key1][key2]).encode('utf-8')+b"\n").decode('utf-8')
+ else:
+ return base64.b64encode(component.encode('utf-8')+b"\n").decode('utf-8')
diff --git a/old/python_moonutilities/tests/unit_python/mock_repo/data.py b/old/python_moonutilities/tests/unit_python/mock_repo/data.py
new file mode 100644
index 00000000..0e772e2c
--- /dev/null
+++ b/old/python_moonutilities/tests/unit_python/mock_repo/data.py
@@ -0,0 +1,315 @@
+components = (
+ "logging",
+ "openstack/keystone",
+ "database",
+ "slave",
+ "components/manager",
+ "components/orchestrator",
+ "components/pipeline",
+ "components/port_start"
+)
+
+shared_ids = {
+ "policy": {
+ "policy_id_1": "policy_id_1",
+ "policy_id_2": "policy_id_2",
+ "policy_id_3": "policy_id_3",
+ "policy_id_invalid_response": "policy_id_invalid_response"
+ },
+ "category": {
+ "category_id_1": "category_id_1",
+ "invalid_category_id_1": " invalid_category_id_1"
+ },
+ "perimeter": {
+ "perimeter_id_1": "subject_id_1",
+ "perimeter_id_2": "object_id_1",
+ "perimeter_id_3": "action_id_1"
+ },
+ "meta_rule": {
+ "meta_rule_id_1": "meta_rule_id_1",
+ "meta_rule_id_2": "meta_rule_id_2"
+ },
+ "rule": {
+ "rule_id_1": "rule_id_2",
+ "rule_id_2": "rule_id_2"
+ },
+ "model": {
+ "model_id_1": "model_id_1"
+ },
+ "subject": {
+ "subject_id_1": "subject_id_1",
+ "invalid_subject_id": "invalid_subject_id",
+ "invalid_category_id": "invalid_category_id",
+ "invalid_assignment_id": "invalid_assignment_id"
+ },
+ "object": {
+ "object_id_1": "object_id_1",
+ "invalid_object_id": "invalid_object_id",
+ "invalid_category_id": "invalid_category_id",
+ "invalid_assignment_id": "invalid_assignment_id"
+ },
+ "action": {
+ "action_id_1": "action_id_1",
+ "invalid_action_id": "invalid_action_id",
+ "invalid_category_id": "invalid_category_id",
+ "invalid_assignment_id": "invalid_assignment_id"
+ }
+}
+
+pdp_mock = {
+ "pdp_id1": {
+ "name": "...",
+ "security_pipeline": ["policy_id_1", "policy_id_2"],
+ "keystone_project_id": "keystone_project_id1",
+ "description": "...",
+ }
+}
+
+meta_rules_mock = {
+ shared_ids["meta_rule"]["meta_rule_id_1"]: {
+ "name": "meta_rule1",
+ "algorithm": "name of the meta rule algorithm",
+ "subject_categories": ["subject_category_id1",
+ "subject_category_id2"],
+ "object_categories": ["object_category_id1"],
+ "action_categories": ["action_category_id1"]
+ },
+ shared_ids["meta_rule"]["meta_rule_id_2"]: {
+ "name": "name of the meta rules2",
+ "algorithm": "name of the meta rule algorithm",
+ "subject_categories": ["subject_category_id1",
+ "subject_category_id2"],
+ "object_categories": ["object_category_id1"],
+ "action_categories": ["action_category_id1"]
+ }
+}
+
+policies_mock = {
+ shared_ids["policy"]["policy_id_1"]: {
+ "name": "test_policy1",
+ "model_id": shared_ids["model"]["model_id_1"],
+ "genre": "authz",
+ "description": "test",
+ }
+}
+
+subject_mock = {
+ shared_ids["policy"]["policy_id_1"]: {
+ "subject_id": {
+ "name": "subject_name",
+ "keystone_id": "keystone_project_id1",
+ "description": "a description"
+ }
+ },
+ shared_ids["policy"]["policy_id_invalid_response"]: {
+ "subject_id": {
+ "name": "subject_name",
+ "keystone_id": "keystone_project_id1",
+ "description": "a description"
+ }
+ }
+
+}
+
+subject_assignment_mock = {
+ shared_ids["subject"]["subject_id_1"]: {
+ "policy_id": shared_ids["policy"]["policy_id_1"],
+ "subject_id": "subject_id_1",
+ "category_id": shared_ids["category"]["category_id_1"],
+ "assignments": ["data_id_1, data_id_2"],
+ }
+}
+
+subject_assignment_mock_invalid_subject_id = {
+ shared_ids["subject"]["invalid_subject_id"]: {
+ "policy_id": shared_ids["policy"]["policy_id_1"],
+ "subject_id_invalid": "subject_id_1",
+ "category_id": shared_ids["category"]["category_id_1"],
+ "assignments": ["data_id_1, data_id_2"],
+ }
+}
+
+subject_assignment_mock_invalid_category_id = {
+ shared_ids["subject"]["invalid_category_id"]: {
+ "policy_id": shared_ids["policy"]["policy_id_1"],
+ "subject_id": "subject_id_1",
+ "category_id_invalid": shared_ids["category"]["category_id_1"],
+ "assignments": ["data_id_1, data_id_2"],
+ }
+}
+
+subject_assignment_mock_invalid_assignment_id = {
+ shared_ids["subject"]["invalid_assignment_id"]: {
+ "policy_id": shared_ids["policy"]["policy_id_1"],
+ "subject_id": "subject_id_1",
+ "category_id": shared_ids["category"]["category_id_1"],
+ "assignments_invalid": ["data_id_1, data_id_2"],
+ }
+}
+
+object_mock = {
+ shared_ids["policy"]["policy_id_1"]: {
+ "object_id": {
+ "name": "object_name",
+ "description": "a description"
+ }
+ }
+}
+
+object_assignment_mock = {
+ shared_ids["object"]["object_id_1"]: {
+ "policy_id": shared_ids["policy"]["policy_id_1"],
+ "object_id": "object_id_1",
+ "category_id": shared_ids["category"]["category_id_1"],
+ "assignments": ["data_id_1, data_id_2"]
+ }
+}
+
+object_assignment_mock_invalid_object_id = {
+ shared_ids["object"]["invalid_object_id"]: {
+ "policy_id": shared_ids["policy"]["policy_id_1"],
+ "object_id": "object_id_1",
+ "category_id": shared_ids["category"]["category_id_1"],
+ "assignments": ["data_id_1, data_id_2"]
+ }
+}
+
+object_assignment_mock_invalid_category_id = {
+ shared_ids["object"]["invalid_category_id"]: {
+ "policy_id": shared_ids["policy"]["policy_id_1"],
+ "object_id": "object_id_1",
+ "category_id": shared_ids["category"]["category_id_1"],
+ "assignments": ["data_id_1, data_id_2"]
+ }
+}
+
+object_assignment_mock_invalid_assignment_id = {
+ shared_ids["object"]["invalid_assignment_id"]: {
+ "policy_id": shared_ids["policy"]["policy_id_1"],
+ "object_id": "object_id_1",
+ "category_id": shared_ids["category"]["category_id_1"],
+ "assignments": ["data_id_1, data_id_2"]
+ }
+}
+
+action_mock = {
+ shared_ids["policy"]["policy_id_1"]: {
+ "action_id": {
+ "name": "action_name",
+ "description": "a description"
+ }
+ }
+}
+
+action_assignment_mock = {
+ shared_ids["action"]["action_id_1"]: {
+ "policy_id": shared_ids["policy"]["policy_id_1"],
+ "action_id": "action_id_1",
+ "category_id": shared_ids["category"]["category_id_1"],
+ "assignments": ["data_id_1, data_id_2"]
+ }
+}
+
+action_assignment_mock_invalid_action_id = {
+ shared_ids["action"]["invalid_action_id"]: {
+ "policy_id": shared_ids["policy"]["policy_id_1"],
+ "action_id": "action_id_1",
+ "category_id": shared_ids["category"]["category_id_1"],
+ "assignments": ["data_id_1, data_id_2"]
+ }
+}
+
+action_assignment_mock_invalid_category_id = {
+ shared_ids["action"]["invalid_category_id"]: {
+ "policy_id": shared_ids["policy"]["policy_id_1"],
+ "action_id": "action_id_1",
+ "category_id": shared_ids["category"]["category_id_1"],
+ "assignments": ["data_id_1, data_id_2"]
+ }
+}
+
+action_assignment_mock_invalid_assignment_id = {
+ shared_ids["action"]["invalid_assignment_id"]: {
+ "policy_id": shared_ids["policy"]["policy_id_1"],
+ "action_id": "action_id_1",
+ "category_id": shared_ids["category"]["category_id_1"],
+ "assignments": ["data_id_1, data_id_2"]
+ }
+}
+
+
+models_mock = {
+ shared_ids["model"]["model_id_1"]: {
+ "name": "test_model",
+ "description": "test",
+ "meta_rules": [shared_ids["meta_rule"]["meta_rule_id_1"]]
+ }
+}
+
+rules_mock = {
+ "rules": {
+ "meta_rule_id": shared_ids["meta_rule"]["meta_rule_id_1"],
+ shared_ids["rule"]["rule_id_1"]: {
+ "rule": ["subject_data_id1",
+ "object_data_id1",
+ "action_data_id1"],
+ "instructions": (
+ {"decision": "grant"},
+ # "grant" to immediately exit,
+ # "continue" to wait for the result of next policy
+ # "deny" to deny the request
+ )
+ },
+ shared_ids["rule"]["rule_id_2"]: {
+ "rule": ["subject_data_id2",
+ "object_data_id2",
+ "action_data_id2"],
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ # operations may be "add" or "delete"
+ "target": "rbac:role:admin"
+ # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}}
+ # chain with the policy named rbac
+ )
+ }
+ }
+}
+
+# pods_mock = {
+# # "name": "pod_id1",
+# # "hostname": "pod_host",
+# # "port": {
+# # "PrivatePort": "8998",
+# # "Type": "tcp",
+# # "IP": "0.0.0.0",
+# # "PublicPort": "8080"
+# # },
+# # "keystone_project_id": "keystone_project_id1",
+# # "pdp_id": "",
+# # "meta_rule_id": "meta_rule_id1",
+# # "container_name": "container_name1",
+# # "plugin_name": "plugin_name1",
+# # "container_id": "container_id"
+# "pod_id1": {
+# "name": "pod_id1",
+# "hostname": "pod_host",
+# "port": {
+# "PrivatePort": "8998",
+# "Type": "tcp",
+# "IP": "0.0.0.0",
+# "PublicPort": "8080"
+# },
+# "keystone_project_id": [1],
+# "pdp_id": "",
+# "meta_rule_id": "meta_rule_id1",
+# "container_name": "container_name1",
+# "plugin_name": "plugin_name1",
+# "container_id": "container_id"
+# },
+#
+# }
diff --git a/old/python_moonutilities/tests/unit_python/mock_repo/urls.py b/old/python_moonutilities/tests/unit_python/mock_repo/urls.py
new file mode 100644
index 00000000..41fd1eec
--- /dev/null
+++ b/old/python_moonutilities/tests/unit_python/mock_repo/urls.py
@@ -0,0 +1,150 @@
+import mock_repo.components_utilities as comp_util
+import mock_repo.data as data_mock
+
+
+def register_components(m):
+ for component in data_mock.components:
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/{}'.format(component),
+ json=[{'Key': component, 'Value': comp_util.get_b64_conf(component)}]
+ )
+
+ m.register_uri(
+ 'PUT', 'http://consul:8500/v1/kv/components/port_start',
+ json=[]
+ )
+
+ m.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/components?recurse=true',
+ json=[
+ {"Key": key, "Value": comp_util.get_b64_conf(key)} for key in data_mock.components
+ ],
+ # json={'Key': "components", 'Value': get_b64_comp_util.CONF("components")}
+ )
+
+
+def register_keystone(m):
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/auth/tokens',
+ headers={'X-Subject-Token': "111111111"}
+ )
+ m.register_uri(
+ 'DELETE', 'http://keystone:5000/v3/auth/tokens',
+ headers={'X-Subject-Token': "111111111"}
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/users?name=testuser&domain_id=default',
+ json={"users": {}}
+ )
+ m.register_uri(
+ 'GET', 'http://keystone:5000/v3/users?name=testuser&domain_id=default',
+ json={"users": {}}
+ )
+ m.register_uri(
+ 'POST', 'http://keystone:5000/v3/users/',
+ json={"users": [{
+ "id": "1111111111111"
+ }]}
+ )
+
+def register_model_any(m, module_name, mocked_data, key=None):
+ if key is None:
+ key = module_name
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}'.format(comp_util.CONF['components']['manager']['hostname'],
+ comp_util.CONF['components']['manager']['port'], module_name),
+
+ json={key: mocked_data}
+ )
+
+def register_policy_any(m, policy_id, module_name, mocked_data, key=None):
+ if key is None:
+ key = module_name
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/{}'.format(comp_util.CONF['components']['manager']['hostname'],
+ comp_util.CONF['components']['manager']['port'], 'policies',
+ policy_id, module_name),
+ json={key: mocked_data}
+ )
+
+def register_pdp(m):
+ register_model_any(m, 'pdp', data_mock.pdp_mock,'pdps')
+
+def register_meta_rules(m):
+ register_model_any(m, 'meta_rules',data_mock.meta_rules_mock)
+
+def register_policies(m):
+ register_model_any(m, 'policies', data_mock.policies_mock)
+
+
+def register_models(m):
+ register_model_any(m, 'models', data_mock.models_mock)
+
+def register_policy_subject(m, policy_id):
+ register_policy_any(m, policy_id, 'subjects', data_mock.subject_mock[policy_id])
+
+
+def register_policy_subject_invalid_response(m, policy_id):
+ register_policy_any(m, policy_id, 'subjects', data_mock.subject_mock[policy_id],'subjects_invalid_key')
+
+def register_policy_object(m, policy_id):
+ register_policy_any(m, policy_id, 'objects', data_mock.object_mock[policy_id])
+
+def register_policy_object_invalid_response(m, policy_id):
+ register_policy_any(m, policy_id, 'objects', data_mock.subject_mock[policy_id],'objects_invalid_key')
+
+def register_policy_action(m, policy_id):
+ register_policy_any(m, policy_id, 'actions', data_mock.action_mock[policy_id])
+
+def register_policy_action_invalid_response(m, policy_id):
+ register_policy_any(m, policy_id, 'actions', data_mock.subject_mock[policy_id],'actions_invalid_key')
+
+def register_policy_subject_assignment_list(m, policy_id):
+ register_policy_any(m, policy_id, 'subject_assignments', data_mock.subject_assignment_mock)
+
+def register_policy_object_assignment_list(m, policy_id):
+ register_policy_any(m, policy_id, 'object_assignments', data_mock.object_assignment_mock)
+
+
+def register_policy_action_assignment_list(m, policy_id):
+ register_policy_any(m, policy_id, 'action_assignments', data_mock.action_assignment_mock)
+
+def register_policy_subject_assignment(m, policy_id, perimeter_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/subject_assignments/{}'.format(comp_util.CONF['components']['manager']['hostname'],
+ comp_util.CONF['components']['manager']['port'],
+ 'policies',
+ policy_id,
+ perimeter_id),
+ json={'subject_assignments': data_mock.subject_assignment_mock}
+ )
+
+def register_policy_object_assignment(m, policy_id, perimeter_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/object_assignments/{}'.format(comp_util.CONF['components']['manager']['hostname'],
+ comp_util.CONF['components']['manager']['port'],
+ 'policies',
+ policy_id,
+ perimeter_id),
+ json={'object_assignments': data_mock.object_assignment_mock}
+ )
+
+def register_policy_action_assignment(m, policy_id, perimeter_id):
+ m.register_uri(
+ 'GET', 'http://{}:{}/{}/{}/action_assignments/{}'.format(comp_util.CONF['components']['manager']['hostname'],
+ comp_util.CONF['components']['manager']['port'],
+ 'policies',
+ policy_id,
+ perimeter_id),
+ json={'action_assignments': data_mock.action_assignment_mock}
+ )
+
+def register_rules(m, policy_id):
+ register_policy_any(m, policy_id, 'rules', data_mock.rules_mock)
+
+# def register_pods(m):
+# m.register_uri(
+# 'GET', 'http://{}:{}/pods'.format(comp_util.CONF['components']['orchestrator']['hostname'],
+# comp_util.CONF['components']['orchestrator']['port']),
+# json={'pods': data_mock.pods_mock}
+# )
diff --git a/old/python_moonutilities/tests/unit_python/requirements.txt b/old/python_moonutilities/tests/unit_python/requirements.txt
new file mode 100644
index 00000000..b08a2603
--- /dev/null
+++ b/old/python_moonutilities/tests/unit_python/requirements.txt
@@ -0,0 +1 @@
+requests_mock \ No newline at end of file
diff --git a/old/python_moonutilities/tests/unit_python/test_cache.py b/old/python_moonutilities/tests/unit_python/test_cache.py
new file mode 100644
index 00000000..bef10a21
--- /dev/null
+++ b/old/python_moonutilities/tests/unit_python/test_cache.py
@@ -0,0 +1,452 @@
+import pytest
+import mock_repo.data as data_mock
+import mock_repo.urls as register_urls
+import requests_mock
+
+
+def test_authz_request():
+ from python_moonutilities import cache
+ c = cache.Cache()
+ assert isinstance(c.authz_requests, dict)
+
+
+# tests for get (subject) in cache
+# ================================================
+def test_get_subject_success():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ name = 'subject_name'
+ subject_id = cache_obj.get_subject(data_mock.shared_ids["policy"]["policy_id_1"], name)
+ assert subject_id is not None
+
+def test_get_subject_no_policy():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ with pytest.raises(Exception) as exception_info:
+ cache_obj.get_subject(None, "")
+ assert str(exception_info.value) == '400: Policy Unknown'
+
+def test_get_subject_invalid_name():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ name = 'invalid name'
+ with pytest.raises(Exception) as exception_info:
+ cache_obj.get_subject(data_mock.shared_ids["policy"]["policy_id_1"], name)
+ assert str(exception_info.value) == '400: Subject Unknown'
+
+def test_get_subject_invalid_response():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ name = 'policy_id_invalid_response'
+ with pytest.raises(Exception) as exception_info:
+ cache_obj.get_subject(data_mock.shared_ids["policy"]["policy_id_invalid_response"], name)
+ assert str(exception_info.value) == '400: Subject Unknown'
+
+# tests for get (object) in cache
+# ================================================
+def test_get_object_success():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ name = 'object_name'
+ object_id = cache_obj.get_object(data_mock.shared_ids["policy"]["policy_id_1"], name)
+ assert object_id is not None
+
+def test_get_object_no_policy():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ with pytest.raises(Exception) as exception_info:
+ cache_obj.get_object(None, "")
+ assert str(exception_info.value) == '400: Policy Unknown'
+
+def test_get_object_invalid_name():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ name = 'invalid name'
+ with pytest.raises(Exception) as exception_info:
+ cache_obj.get_object(data_mock.shared_ids["policy"]["policy_id_1"], name)
+ assert str(exception_info.value) == '400: Object Unknown'
+
+def test_get_object_invalid_response():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ name = 'policy_id_invalid_response'
+ with pytest.raises(Exception) as exception_info:
+ cache_obj.get_object(data_mock.shared_ids["policy"]["policy_id_invalid_response"], name)
+ assert str(exception_info.value) == '400: Object Unknown'
+
+# tests for get (action) in cache
+# ================================================
+def test_get_action_success():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ name = 'action_name'
+ action_id = cache_obj.get_action(data_mock.shared_ids["policy"]["policy_id_1"], name)
+ assert action_id is not None
+
+
+def test_get_action_no_policy():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ with pytest.raises(Exception) as exception_info:
+ cache_obj.get_action(None, "")
+ assert str(exception_info.value) == '400: Policy Unknown'
+
+def test_get_action_invalid_name():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ name = 'invalid name'
+ with pytest.raises(Exception) as exception_info:
+ cache_obj.get_action(data_mock.shared_ids["policy"]["policy_id_1"], name)
+ assert str(exception_info.value) == '400: Action Unknown'
+
+def test_get_action_invalid_response():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ name = 'policy_id_invalid_response'
+ with pytest.raises(Exception) as exception_info:
+ cache_obj.get_action(data_mock.shared_ids["policy"]["policy_id_invalid_response"], name)
+ assert str(exception_info.value) == '400: Action Unknown'
+
+# ====================================================================================================
+
+# tests for get (subject_assignment) in cache
+# =================================================================================
+
+def test_get_subject_assignment_success():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ subject_assignments = cache_obj.get_subject_assignments(data_mock.shared_ids["policy"]["policy_id_1"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"],
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert subject_assignments is not None
+
+def test_get_subject_assignment_no_policy():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ with pytest.raises(Exception) as exception_info:
+ cache_obj.get_subject_assignments(None,
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"],
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert str(exception_info.value) == '400: Policy Unknown'
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_subject_assignment_invalid_subject_id(**kwargs):
+ from python_moonutilities import cache
+
+ register_urls.register_components(kwargs['mock'])
+
+ kwargs['mock'].get('http://manager:8082/policies/{}/subject_assignments/{}'
+ .format(data_mock.shared_ids["subject"]["invalid_subject_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"]),
+ json={'subject_assignments': data_mock.subject_assignment_mock_invalid_subject_id}
+ )
+ cache_obj = cache.Cache()
+ subject_assignments = cache_obj.get_subject_assignments(data_mock.shared_ids["subject"]["invalid_subject_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"],
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert len(subject_assignments) == 0
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_subject_assignment_invalid_category_id(**kwargs):
+ from python_moonutilities import cache
+
+ register_urls.register_components(kwargs['mock'])
+ kwargs['mock'].get('http://manager:8082/policies/{}/subject_assignments/{}'
+ .format(data_mock.shared_ids["subject"]["invalid_category_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"]),
+ json={'subject_assignments': data_mock.subject_assignment_mock_invalid_category_id}
+ )
+ cache_obj = cache.Cache()
+ subject_assignments = cache_obj.get_subject_assignments(data_mock.shared_ids["subject"]["invalid_category_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"],
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert len(subject_assignments) == 0
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_subject_assignment_invalid_assignment_id(**kwargs):
+ from python_moonutilities import cache
+
+ register_urls.register_components(kwargs['mock'])
+ kwargs['mock'].get('http://manager:8082/policies/{}/subject_assignments/{}'
+ .format(data_mock.shared_ids["subject"]["invalid_assignment_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"]),
+ json={'subject_assignments': data_mock.subject_assignment_mock_invalid_assignment_id}
+ )
+
+ cache_obj = cache.Cache()
+ subject_assignments = cache_obj.get_subject_assignments(data_mock.shared_ids["subject"]["invalid_assignment_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"],
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert len(subject_assignments) == 0
+
+
+def test_get_subject_assignment_empty_perimeter():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ subject_assignments = cache_obj.get_subject_assignments(data_mock.shared_ids["policy"]["policy_id_2"],
+ None,
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert len(subject_assignments) == 0
+
+
+def test_get_subject_assignment_invalid_category_failure():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ subject_assignments = cache_obj.get_subject_assignments(data_mock.shared_ids["policy"]["policy_id_1"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"],
+ data_mock.shared_ids["category"]["invalid_category_id_1"])
+ assert len(subject_assignments) == 0
+
+# tests for get (object_assignment) in cache
+# ==========================================
+def test_get_object_assignment_success():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ object_assignments = cache_obj.get_object_assignments(data_mock.shared_ids["policy"]["policy_id_1"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_2"],
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert object_assignments is not None
+
+
+def test_get_object_assignment_no_policy():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ with pytest.raises(Exception) as exception_info:
+ cache_obj.get_object_assignments(None, data_mock.shared_ids["perimeter"]["perimeter_id_2"],
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert str(exception_info.value) == '400: Policy Unknown'
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_object_assignment_invalid_object_id(**kwargs):
+ from python_moonutilities import cache
+
+ register_urls.register_components(kwargs['mock'])
+
+ kwargs['mock'].get('http://manager:8082/policies/{}/object_assignments/{}'
+ .format(data_mock.shared_ids["object"]["invalid_object_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"]),
+ json={'object_assignments': data_mock.object_assignment_mock_invalid_object_id}
+ )
+ cache_obj = cache.Cache()
+ object_assignments = cache_obj.get_object_assignments(data_mock.shared_ids["object"]["invalid_object_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"],
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert len(object_assignments) == 0
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_object_assignment_invalid_category_id(**kwargs):
+ from python_moonutilities import cache
+
+ register_urls.register_components(kwargs['mock'])
+ kwargs['mock'].get('http://manager:8082/policies/{}/object_assignments/{}'
+ .format(data_mock.shared_ids["object"]["invalid_category_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"]),
+ json={'object_assignments': data_mock.object_assignment_mock_invalid_category_id}
+ )
+ cache_obj = cache.Cache()
+ object_assignments = cache_obj.get_object_assignments(data_mock.shared_ids["object"]["invalid_category_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"],
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert len(object_assignments) == 0
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_object_assignment_invalid_assignment_id(**kwargs):
+ from python_moonutilities import cache
+
+ register_urls.register_components(kwargs['mock'])
+ kwargs['mock'].get('http://manager:8082/policies/{}/object_assignments/{}'
+ .format(data_mock.shared_ids["object"]["invalid_assignment_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"]),
+ json={'object_assignments': data_mock.object_assignment_mock_invalid_assignment_id}
+ )
+
+ cache_obj = cache.Cache()
+ object_assignments = cache_obj.get_object_assignments(data_mock.shared_ids["object"]["invalid_assignment_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"],
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert len(object_assignments) == 0
+
+def test_get_object_assignment_none_perimeter():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ object_assignments = cache_obj.get_object_assignments(data_mock.shared_ids["policy"]["policy_id_2"],
+ None,
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert len(object_assignments) == 0
+
+
+def test_get_object_assignment_invalid_category_failure():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ object_assignments = cache_obj.get_object_assignments(data_mock.shared_ids["policy"]["policy_id_1"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"],
+ data_mock.shared_ids["category"]["invalid_category_id_1"])
+ assert len(object_assignments) == 0
+
+# tests for get (action_assignment) in cache
+# ==========================================
+def test_get_action_assignment_success():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ action_assignments = cache_obj.get_action_assignments(data_mock.shared_ids["policy"]["policy_id_1"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_3"],
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert action_assignments is not None
+
+
+def test_get_action_assignment_no_policy():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ with pytest.raises(Exception) as exception_info:
+ cache_obj.get_action_assignments(None, data_mock.shared_ids["perimeter"]["perimeter_id_2"],
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert str(exception_info.value) == '400: Policy Unknown'
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_action_assignment_invalid_object_id(**kwargs):
+ from python_moonutilities import cache
+
+ register_urls.register_components(kwargs['mock'])
+
+ kwargs['mock'].get('http://manager:8082/policies/{}/action_assignments/{}'
+ .format(data_mock.shared_ids["action"]["invalid_action_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"]),
+ json={'action_assignments': data_mock.action_assignment_mock_invalid_action_id}
+ )
+ cache_obj = cache.Cache()
+ action_assignments = cache_obj.get_action_assignments(data_mock.shared_ids["action"]["invalid_action_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"],
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert len(action_assignments) == 0
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_action_assignment_invalid_category_id(**kwargs):
+ from python_moonutilities import cache
+
+ register_urls.register_components(kwargs['mock'])
+ kwargs['mock'].get('http://manager:8082/policies/{}/action_assignments/{}'
+ .format(data_mock.shared_ids["action"]["invalid_category_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"]),
+ json={'action_assignments': data_mock.action_assignment_mock_invalid_category_id}
+ )
+ cache_obj = cache.Cache()
+ action_assignments = cache_obj.get_action_assignments(data_mock.shared_ids["action"]["invalid_category_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"],
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert len(action_assignments) == 0
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_action_assignment_invalid_assignment_id(**kwargs):
+ from python_moonutilities import cache
+
+ register_urls.register_components(kwargs['mock'])
+ kwargs['mock'].get('http://manager:8082/policies/{}/action_assignments/{}'
+ .format(data_mock.shared_ids["action"]["invalid_assignment_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"]),
+ json={'action_assignments': data_mock.action_assignment_mock_invalid_assignment_id}
+ )
+
+ cache_obj = cache.Cache()
+ action_assignments = cache_obj.get_action_assignments(data_mock.shared_ids["action"]["invalid_assignment_id"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"],
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert len(action_assignments) == 0
+
+def test_get_action_assignment_none_perimeter():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ action_assignments = cache_obj.get_action_assignments(data_mock.shared_ids["policy"]["policy_id_2"],
+ None,
+ data_mock.shared_ids["category"]["category_id_1"])
+ assert len(action_assignments) == 0
+
+
+def test_get_action_assignment_invalid_category_failure():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ action_assignments = cache_obj.get_action_assignments(data_mock.shared_ids["policy"]["policy_id_1"],
+ data_mock.shared_ids["perimeter"]["perimeter_id_1"],
+ data_mock.shared_ids["category"]["invalid_category_id_1"])
+ assert len(action_assignments) == 0
+
+
+# ====================================================================================================
+
+# tests for helper function in cache
+# ==================================
+def test_get_policy_from_meta_rules_success():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+ policy_id = cache_obj.get_policy_from_meta_rules(data_mock.shared_ids["meta_rule"]["meta_rule_id_1"])
+ assert policy_id is not None
+
+''' tests for containers function , security pipline in cache which not used for now
+ need to mock pdp object, /pods correctly
+'''
+
+# def test_get_policy_from_meta_rules_failure():
+# from python_moonutilities import cache
+# cache_obj = cache.Cache()
+# meta_rule_id = 'meta_rule_id3'
+# policy_id = cache_obj.get_policy_from_meta_rules(meta_rule_id)
+# assert policy_id is None
+
+# def test_get_pdp_from_keystone_project_success():
+# from python_moonutilities import cache
+# cache_obj = cache.Cache()
+# keystone_project_id = 'keystone_project_id1'
+# pdp_key = cache_obj.get_pdp_from_keystone_project(keystone_project_id)
+# assert pdp_key is not None
+#
+#
+# def test_get_pdp_from_keystone_project_failure():
+# from python_moonutilities import cache
+# cache_obj = cache.Cache()
+# keystone_project_id = 'keystone_project_id2'
+# pdp_key = cache_obj.get_pdp_from_keystone_project(keystone_project_id)
+# assert pdp_key is None
+#
+#
+# def test_get_keystone_project_id_from_policy_id_success():
+# from python_moonutilities import cache
+# cache_obj = cache.Cache()
+# keystone_project_id = cache_obj.get_keystone_project_id_from_policy_id(
+# data_mock.shared_ids["policy"]["policy_id_1"])
+# assert keystone_project_id is not None
+#
+#
+# def test_get_keystone_project_id_from_policy_id_failure():
+# from python_moonutilities import cache
+# cache_obj = cache.Cache()
+# policy_id = 'policy_id_3'
+# keystone_project_id = cache_obj.get_keystone_project_id_from_policy_id(policy_id)
+# assert keystone_project_id is None
+
+
+# def test_get_containers_from_keystone_project_id_success():
+# from python_moonutilities import cache
+# cache_obj = cache.Cache()
+# keystone_project_id = 1
+# meta_rule_id = 'meta_rule_id1'
+# container_id, container_value = cache_obj.get_containers_from_keystone_project_id(keystone_project_id, meta_rule_id)
+# assert container_id, container_value is not None
+
+
+def test_cache_manager():
+ from python_moonutilities import cache
+ cache_obj = cache.Cache()
+# assert cache_obj.pdp is not None
+ assert cache_obj.meta_rules is not None
+ assert len(cache_obj.meta_rules) == 2
+ assert cache_obj.policies is not None
+ assert len(cache_obj.policies) == 1
+ assert cache_obj.models is not None
diff --git a/old/python_moonutilities/tests/unit_python/test_configuration.py b/old/python_moonutilities/tests/unit_python/test_configuration.py
new file mode 100644
index 00000000..d5d83f7a
--- /dev/null
+++ b/old/python_moonutilities/tests/unit_python/test_configuration.py
@@ -0,0 +1,166 @@
+import mock_repo.components_utilities as comp_util
+import pytest
+import requests_mock
+
+
+def test_get_configuration_success():
+ from python_moonutilities import configuration
+ assert configuration.get_configuration("components/port_start")["components/port_start"] == comp_util.CONF["components"]["port_start"]
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_configuration_mutliple_list_success(**kwargs):
+ from python_moonutilities import configuration
+
+ kwargs['mock'].get('http://consul:8500/v1/kv/components/port_start',
+ json=[
+ {'Key': 'port_start', 'Value': comp_util.get_b64_conf("components/port_start")},
+ {'Key': 'port_start', 'Value': comp_util.get_b64_conf("components/port_start")}
+ ]
+ )
+
+ assert len(configuration.get_configuration("components/port_start")) == 2
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_configuration_mutliple_list_failure(**kwargs):
+ from python_moonutilities import configuration
+
+ kwargs['mock'].get('http://consul:8500/v1/kv/components/port_start',
+ json=[
+ {'Key': 'port_start', 'Value': comp_util.get_b64_conf("components/port_start")},
+ {'invalidKey': 'port_start', 'Value': comp_util.get_b64_conf("components/port_start")}
+ ]
+ )
+ with pytest.raises(Exception) as exception_info:
+ configuration.get_configuration("components/port_start")
+ assert str(exception_info.value) == '500: Consul Content error'
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_configuration_not_found(**kwargs):
+ from python_moonutilities import configuration
+
+ kwargs['mock'].get('http://consul:8500/v1/kv/components/port_start_wrong', json=[
+ ], status_code=500)
+ with pytest.raises(Exception) as exception_info:
+ configuration.get_configuration("components/port_start_wrong")
+ assert str(exception_info.value) == '500: Consul error'
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_configuration_invalid_response(**kwargs):
+ from python_moonutilities import configuration
+
+ kwargs['mock'].get('http://consul:8500/v1/kv/components/port_start', json=[
+ {"port_start":'port_start', 'Value': comp_util.get_b64_conf("components/port_start")}
+ ])
+ with pytest.raises(Exception) as exception_info:
+ configuration.get_configuration("components/port_start")
+ assert str(exception_info.value) == '500: Consul Content error'
+
+
+################################ increment_port ####################################
+@requests_mock.Mocker(kw='mock')
+def test_put_increment_port_invalidkey_failure(**kwargs):
+ from python_moonutilities import configuration
+
+ kwargs['mock'].get('http://consul:8500/v1/kv/components/port_start', json=[
+ {'Key': 'invalidkey', 'Value': comp_util.get_b64_conf("components/port_start")}
+ ], status_code=200)
+ with pytest.raises(Exception) as exception_info:
+ configuration.increment_port()
+ assert str(exception_info.value) == '500: Consul Content error'
+
+
+@requests_mock.Mocker(kw='mock')
+def test_put_increment_port_failure(**kwargs):
+ from python_moonutilities import configuration
+ kwargs['mock'].put('http://consul:8500/v1/kv/components/port_start', json=[], status_code=400)
+ kwargs['mock'].get('http://consul:8500/v1/kv/components/port_start', json=[
+ {'Key': 'port_start', 'Value': comp_util.get_b64_conf("components/port_start")}
+ ], status_code=200)
+ with pytest.raises(Exception) as exception_info:
+ configuration.increment_port()
+ assert str(exception_info.value) == '500: Consul Content error'
+
+
+def test_increment_port_success():
+ from python_moonutilities import configuration
+ cur_port = comp_util.CONF["components"]["port_start"]
+ incremented_port = configuration.increment_port()
+ assert incremented_port == cur_port + 1
+
+
+################################ plugin ####################################
+def test_get_plugins_success():
+ from python_moonutilities import configuration
+ plugin = configuration.get_plugins()
+ assert plugin is not None
+
+def test_get_plugins_failure(no_requests):
+ from python_moonutilities import configuration
+ no_requests.register_uri(
+ 'GET', 'http://consul:8500/v1/kv/components/pipeline',
+ json=[{'Key': 'components/pipeline', 'Value': 'eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0='}]
+ )
+ with pytest.raises(Exception) as exception_info:
+ configuration.get_plugins()
+ assert str(exception_info.value) == '500: Consul Content error'
+################################ component ####################################
+def test_get_components():
+ from python_moonutilities import configuration
+ assert isinstance(configuration.get_components(), dict)
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_components_mutliple_list_success(**kwargs):
+ from python_moonutilities import configuration
+
+ kwargs['mock'].get('http://consul:8500/v1/kv/components?recurse=true',
+ json=[
+ {'Key': 'components/c1', 'Value': 'eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0='},
+ {'Key': 'components/c2', 'Value': 'eyJjb250YWluZXIiOiAid3Vrb25nc3VuL21vb25fYXV0aHo6djQuMyIsICJwb3J0IjogODA4MX0='}
+ ]
+ )
+
+ res = configuration.get_components()
+ assert bool(res)
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_components_mutliple_list_failure(**kwargs):
+ from python_moonutilities import configuration
+
+ kwargs['mock'].get('http://consul:8500/v1/kv/components?recurse=true',
+ json=[
+ {'Key': 'components/c1', 'Value': "eyJjb250YWluZXIiOiAid3Vrb25"},
+ {'invalidKey': 'components/c2', 'Value': "eyJjb250YWluZXIiOiAid3Vrb25"}
+ ]
+ )
+ with pytest.raises(Exception) as exception_info:
+ configuration.get_components()
+ assert str(exception_info.value) == '500: Consul Content error'
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_components_not_found(**kwargs):
+ from python_moonutilities import configuration
+
+ kwargs['mock'].get('http://consul:8500/v1/kv/components?recurse=true', json=[
+ ], status_code=500)
+ with pytest.raises(Exception) as exception_info:
+ configuration.get_components()
+ assert str(exception_info.value) == '400: Consul error'
+
+
+@requests_mock.Mocker(kw='mock')
+def test_get_components_invalid_response(**kwargs):
+ from python_moonutilities import configuration
+
+ kwargs['mock'].get('http://consul:8500/v1/kv/components?recurse=true', json=[
+ {"invalidKey":'invalid', 'Value': "jb250"}
+ ])
+ with pytest.raises(Exception) as exception_info:
+ configuration.get_components()
+ assert str(exception_info.value) == '500: Consul Content error'
diff --git a/old/python_moonutilities/tests/unit_python/test_validated_input.py b/old/python_moonutilities/tests/unit_python/test_validated_input.py
new file mode 100644
index 00000000..723bc8ba
--- /dev/null
+++ b/old/python_moonutilities/tests/unit_python/test_validated_input.py
@@ -0,0 +1,154 @@
+# Copyright 2018 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+
+import pytest
+
+
+def test_valid_string():
+ from python_moonutilities.security_functions import validate_data
+ validate_data("CorrectString")
+ validate_data("Correct String")
+ validate_data("Correct String!")
+ validate_data("Correct String@")
+ validate_data(None)
+ validate_data(True)
+
+
+def test_invalid_string():
+ from python_moonutilities.security_functions import validate_data
+ with pytest.raises(Exception) as exception_info:
+ validate_data("Notcorrect<a>String")
+
+ assert str(exception_info.value) == 'Forbidden characters in string'
+
+
+def test_none_value():
+ from python_moonutilities.security_functions import validate_data
+ with pytest.raises(Exception) as exception_info:
+ validate_data(object)
+
+ assert 'Value is Not String or Container or Dictionary' in str(exception_info.value)
+
+
+def test_numeric_value():
+ from python_moonutilities.security_functions import validate_data
+ with pytest.raises(Exception) as exception_info:
+ validate_data(1)
+ assert 'Value is Not String or Container or Dictionary' in str(exception_info.value)
+
+ with pytest.raises(Exception) as exception_info:
+ validate_data(1.23)
+ assert 'Value is Not String or Container or Dictionary' in str(exception_info.value)
+
+
+def test_correct_list_one_element():
+ from python_moonutilities.security_functions import validate_data
+ validate_data(["test_1", "test_2", "test_3"])
+
+
+def test_correct_list_multiple_element():
+ from python_moonutilities.security_functions import validate_data
+ validate_data(["test"])
+
+
+def test_correct_nested_list():
+ from python_moonutilities.security_functions import validate_data
+ validate_data([["test_1", "test_2"], [["test_3"], ["test_4"]], ["test_5", "test_6"], ["test_7"]])
+
+
+def test_incorrect_string_inside_list():
+ from python_moonutilities.security_functions import validate_data
+ with pytest.raises(Exception) as exception_info:
+ validate_data(["test_1", ["test_2", "forbidden<a>character"]])
+
+ assert str(exception_info.value) == 'Forbidden characters in string'
+
+
+def test_correct_tuples():
+ from python_moonutilities.security_functions import validate_data
+ validate_data(("test_1", "test_2"))
+
+
+def test_correct_tuple_of_tuple():
+ from python_moonutilities.security_functions import validate_data
+ validate_data(("test_1", ("test_2", "test_3"), (("test_4", "test_5"), ("test_6", "test_7"))))
+
+
+def test_incorrect_string_within_tuple():
+ from python_moonutilities.security_functions import validate_data
+ with pytest.raises(Exception) as exception_info:
+ validate_data(("test_1", "forbidden<a>character"))
+
+ assert str(exception_info.value) == 'Forbidden characters in string'
+
+
+def test_correct_dictionary():
+ from python_moonutilities.security_functions import validate_data
+ validate_data({"test_1": "test_2"})
+
+
+def test_incorrect_string_within_dictionary():
+ from python_moonutilities.security_functions import validate_data
+ with pytest.raises(Exception) as exception_info:
+ validate_data({"test_1": "forbidden<a>character"})
+
+ assert str(exception_info.value) == 'Forbidden characters in string'
+
+
+def test_correct_function_pass():
+ from python_moonutilities.security_functions import validate_input
+
+ @validate_input()
+ def temp_function(string, list, tuple):
+ if string != "teststring":
+ raise ValueError("values which passed incorrect")
+
+ temp_function("teststring", ["teststring", ["teststring"]], ("teststring", ("teststring", )))
+
+
+def test_incorrect_validating_function_with_kwargs():
+ from python_moonutilities.security_functions import validate_input
+
+ @validate_input(kwargs_state=[True,True])
+ def temp_function(string, list, tuple):
+ if string != "teststring":
+ raise ValueError("values which passed incorrect")
+
+ with pytest.raises(Exception) as exception_info:
+ temp_function("teststring", list=["teststring", ["testst<a>ring"]],tuple=("teststring", ("teststri<a>ng", )))
+
+ assert str(exception_info.value) == 'Forbidden characters in string'
+
+
+def test_incorrect_validating_function():
+ from python_moonutilities.security_functions import validate_input
+
+ @validate_input()
+ def temp_function(string, list, dictionary):
+ if string != "teststring":
+ raise ValueError("values which passed incorrect")
+
+ with pytest.raises(Exception) as exception_info:
+ temp_function("teststring", ["teststring", ["teststri<a>ng"]], {"teststring": ("teststring", )})
+
+ assert str(exception_info.value) == 'Forbidden characters in string'
+
+
+def test_incorrect_validating_class_function():
+ from python_moonutilities.security_functions import validate_input
+
+ class Testclass:
+ @validate_input()
+ def temp_function(self, string, list, dictionary):
+ if string != "teststring":
+ raise ValueError("values which passed incorrect")
+
+ e = Testclass()
+
+ with pytest.raises(Exception) as exception_info:
+ e.temp_function("teststring", ["teststring", ["teststri<a>ng"]], {"teststring": ("teststring", )})
+
+ assert str(exception_info.value) == 'Forbidden characters in string'
diff --git a/old/tests/functional/README.md b/old/tests/functional/README.md
new file mode 100644
index 00000000..4cac22b6
--- /dev/null
+++ b/old/tests/functional/README.md
@@ -0,0 +1,27 @@
+# Moon Functional Test
+
+[Test Platform Setup](../../tools/moon_kubernetes/README.md)
+
+
+### Pod Functional Test
+Launch functional [test scenario](tests/functional/scenario_enabled) :
+```bash
+sudo pip install python_moonclient --upgrade
+cd $MOON_HOME/tests/functional/scenario_tests
+moon_create_pdp --consul-host=$MOON_HOST --consul-port=30005 -v rbac_large.py
+moon_get_keystone_project --consul-host=$MOON_HOST --consul-port=30005
+moon_get_pdp --consul-host=$MOON_HOST --consul-port=30005
+moon_map_pdp_to_project "<pdp_id>" "<keystone_project_id>"
+moon_send_authz_to_wrapper --consul-host=$MOON_HOST --consul-port=30005 --authz-host=$WRAPPER_HOST --authz-port=$WRAPPER_PORT -v rbac_large.py
+```
+
+To retrieve the wrapper information, use the following command:
+```bash
+kubectl get -n moon services | grep wrapper
+```
+
+Launch functional tests:
+```bash
+cd $MOON_HOME
+sudo bash $TARGET_MODULE/tests/functional_pod/run_functional_tests.sh
+```
diff --git a/old/tests/functional/run_tests.sh b/old/tests/functional/run_tests.sh
new file mode 100755
index 00000000..cf55c3bd
--- /dev/null
+++ b/old/tests/functional/run_tests.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+
+MOON_HOME=${1:-.}
+
+echo "Starting Moon Functional Tests on ${MOON_HOME}"
+
+cd ${MOON_HOME}
+
+COMPONENTS="moon_manager moon_wrapper"
+
+for dir in ${COMPONENTS}; do
+ echo "Testing component ${dir}"
+ cd ${MOON_HOME}/${dir}
+ bash ../tests/functional/run_tests_for_component.sh
+ cd -
+done
+
+# TODO: download tests results
diff --git a/old/tests/functional/run_tests_for_component.sh b/old/tests/functional/run_tests_for_component.sh
new file mode 100644
index 00000000..6c6a0330
--- /dev/null
+++ b/old/tests/functional/run_tests_for_component.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+CUR_PWD=$(pwd)
+INPUT_FILE=../tools/moon_kubernetes/templates/moon_functest.yaml
+OUTPUT_FILE=tests/functional_pod/moon_functest.yaml
+
+echo current working directory: ${CUR_PWD}
+
+cat ${INPUT_FILE} | sed "s|{{PATH}}|${CUR_PWD}|" > ${OUTPUT_FILE}
+
+kubectl create -f ${OUTPUT_FILE}
+
+sleep 5
+kubectl get -n moon jobs
+echo OUTPUT is $?
+if [ "$?" -ne 0 ]
+then
+ sleep 5
+ kubectl get -n moon jobs
+fi
+
+echo "waiting for FuncTests (it may takes time)..."
+echo -e "\033[35m"
+sed '/<END OF JOB>/q' <(kubectl logs -n moon jobs/functest -f)
+echo -e "\033[m"
+
+kubectl delete -f ${OUTPUT_FILE}
diff --git a/old/tests/functional/scenario_available/delegation.py b/old/tests/functional/scenario_available/delegation.py
new file mode 100644
index 00000000..839e74ce
--- /dev/null
+++ b/old/tests/functional/scenario_available/delegation.py
@@ -0,0 +1,40 @@
+
+pdp_name = "pdp1"
+policy_name = "Delegation policy example"
+model_name = "Delegation"
+
+subjects = {"user0": "", }
+objects = {"user1": "", }
+actions = {"delegate": ""}
+
+subject_categories = {"subjectid": "", }
+object_categories = {"delegated": "", }
+action_categories = {"delegation-action": "", }
+
+subject_data = {"subjectid": {"user0": ""}}
+object_data = {"delegated": {"user1": ""}}
+action_data = {"delegation-action": {"delegate": ""}}
+
+subject_assignments = {"user0": {"subjectid": "user0"}}
+object_assignments = {"user1": {"delegated": "user1"}}
+action_assignments = {"delegate": {"delegation-action": "delegate"}}
+
+meta_rule = {
+ "session": {"id": "", "value": ("subjectid", "delegated", "delegation-action")},
+}
+
+rules = {
+ "session": (
+ {
+ "rule": ("user0", "user1", "delegate"),
+ "instructions": (
+ {
+ "update": {"request:subject": "user1"} # update the current user with "user1"
+ },
+ {"chain": {"security_pipeline": "rbac"}}
+ )
+ },
+ )
+}
+
+
diff --git a/old/tests/functional/scenario_available/mls.py b/old/tests/functional/scenario_available/mls.py
new file mode 100644
index 00000000..0e6285c9
--- /dev/null
+++ b/old/tests/functional/scenario_available/mls.py
@@ -0,0 +1,59 @@
+
+pdp_name = "pdp_mls"
+policy_name = "MLS Policy example"
+model_name = "MLS"
+policy_genre = "authz"
+
+subjects = {"adminuser": "", "user1": "", "user2": "", }
+objects = {"vm0": "", "vm1": "", }
+actions = {"start": "", "stop": ""}
+
+subject_categories = {"subject-security-level": "", }
+object_categories = {"object-security-level": "", }
+action_categories = {"action-type": "", }
+
+subject_data = {
+ "subject-security-level": {"low": "", "medium": "", "high": ""},
+}
+object_data = {
+ "object-security-level": {"low": "", "medium": "", "high": ""},
+}
+action_data = {"action-type": {"vm-action": "", "storage-action": "", }}
+
+subject_assignments = {
+ "adminuser": {"subject-security-level": "high"},
+ "user1": {"subject-security-level": "medium"},
+}
+object_assignments = {
+ "vm0": {"object-security-level": "medium"},
+ "vm1": {"object-security-level": "low"},
+}
+action_assignments = {
+ "start": {"action-type": "vm-action"},
+ "stop": {"action-type": "vm-action"}
+}
+
+meta_rule = {
+ "mls": {
+ "id": "",
+ "value": ("subject-security-level",
+ "object-security-level",
+ "action-type")},
+}
+
+rules = {
+ "mls": (
+ {
+ "rule": ("high", "medium", "vm-action"),
+ "instructions": ({"decision": "grant"})
+ },
+ {
+ "rule": ("high", "low", "vm-action"),
+ "instructions": ({"decision": "grant"})
+ },
+ {
+ "rule": ("medium", "low", "vm-action"),
+ "instructions": ({"decision": "grant"})
+ },
+ )
+}
diff --git a/old/tests/functional/scenario_available/rbac.py b/old/tests/functional/scenario_available/rbac.py
new file mode 100644
index 00000000..25c010fd
--- /dev/null
+++ b/old/tests/functional/scenario_available/rbac.py
@@ -0,0 +1,61 @@
+
+pdp_name = "pdp_rbac"
+policy_name = "RBAC policy example"
+model_name = "RBAC"
+policy_genre = "authz"
+
+subjects = {"adminuser": "", "user1": "", }
+objects = {"vm0": "", "vm1": "", }
+actions = {"start": "", "stop": ""}
+
+subject_categories = {"role": "", }
+object_categories = {"id": "", }
+action_categories = {"action-type": "", }
+
+subject_data = {"role": {"admin": "", "employee": "", "*": ""}}
+object_data = {"id": {"vm0": "", "vm1": "", "*": ""}}
+action_data = {"action-type": {"vm-action": "", "*": ""}}
+
+subject_assignments = {
+ "adminuser":
+ ({"role": "admin"}, {"role": "employee"}, {"role": "*"}),
+ "user1":
+ ({"role": "employee"}, {"role": "*"}),
+}
+object_assignments = {
+ "vm0":
+ ({"id": "vm0"}, {"id": "*"}),
+ "vm1":
+ ({"id": "vm1"}, {"id": "*"})
+}
+action_assignments = {
+ "start":
+ ({"action-type": "vm-action"}, {"action-type": "*"}),
+ "stop":
+ ({"action-type": "vm-action"}, {"action-type": "*"})
+}
+
+meta_rule = {
+ "rbac": {"id": "", "value": ("role", "id", "action-type")},
+}
+
+rules = {
+ "rbac": (
+ {
+ "rule": ("admin", "vm0", "vm-action"),
+ "instructions": (
+ {"decision": "grant"},
+ # "grant" to immediately exit,
+ # "continue" to wait for the result of next policy
+ )
+ },
+ {
+ "rule": ("employee", "vm1", "vm-action"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ )
+}
+
+
diff --git a/old/tests/functional/scenario_available/rbac_custom_100.py b/old/tests/functional/scenario_available/rbac_custom_100.py
new file mode 100644
index 00000000..9ee55dbd
--- /dev/null
+++ b/old/tests/functional/scenario_available/rbac_custom_100.py
@@ -0,0 +1,89 @@
+import random
+
+pdp_name = "pdp_100"
+policy_name = "RBAC policy example 100 users"
+model_name = "RBAC"
+policy_genre = "authz"
+
+SUBJECT_NUMBER = 100
+OBJECT_NUMBER = 100
+ROLE_NUMBER = 50
+
+subjects = {}
+for _id in range(SUBJECT_NUMBER):
+ subjects["user{}".format(_id)] = ""
+objects = {}
+for _id in range(OBJECT_NUMBER):
+ objects["vm{}".format(_id)] = ""
+actions = {
+ "start": "",
+ "stop": "",
+ "pause": "",
+ "unpause": "",
+ "destroy": "",
+}
+
+subject_categories = {"role": "", }
+object_categories = {"id": "", }
+action_categories = {"action-type": "", }
+
+subject_data = {"role": {"admin": "", "*": ""}}
+for _id in range(ROLE_NUMBER):
+ subject_data["role"]["role{}".format(_id)] = ""
+object_data = {"id": {"*": ""}}
+for _id in range(OBJECT_NUMBER):
+ object_data["id"]["vm{}".format(_id)] = ""
+action_data = {"action-type": {
+ "vm-read": "",
+ "vm-write": "",
+ "*": ""
+}}
+
+subject_assignments = {}
+for _id in range(SUBJECT_NUMBER):
+ _role = "role{}".format(random.randrange(ROLE_NUMBER))
+ subject_assignments["user{}".format(_id)] = [{"role": _role}, {"role": "*"}]
+object_assignments = {"vm0": ({"id": "vm0"}, {"id": "*"}), "vm1": ({"id": "vm1"}, {"id": "*"})}
+for _id in range(OBJECT_NUMBER):
+ object_assignments["vm{}".format(_id)] = [{"id": "vm{}".format(_id)}, {"id": "*"}]
+action_assignments = {
+ "start": ({"action-type": "vm-write"}, {"action-type": "*"}),
+ "stop": ({"action-type": "vm-write"}, {"action-type": "*"}),
+ "pause": ({"action-type": "vm-read"}, {"action-type": "*"}),
+ "unpause": ({"action-type": "vm-read"}, {"action-type": "*"}),
+ "destroy": ({"action-type": "vm-write"}, {"action-type": "*"}),
+}
+
+meta_rule = {
+ "rbac": {"id": "", "value": ("role", "id", "action-type")},
+}
+
+rules = {
+ "rbac": [
+ {
+ "rule": ("admin", "vm0", "vm-read"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("admin", "vm0", "vm-write"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ ]
+}
+
+for _id in range(SUBJECT_NUMBER):
+ _role = "role{}".format(random.randrange(ROLE_NUMBER))
+ _vm = "vm{}".format(random.randrange(OBJECT_NUMBER))
+ _action = random.choice(list(action_data['action-type'].keys()))
+ rules["rbac"].append(
+ {
+ "rule": (_role, _vm, _action),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ )
diff --git a/old/tests/functional/scenario_available/rbac_custom_1000.py b/old/tests/functional/scenario_available/rbac_custom_1000.py
new file mode 100644
index 00000000..d6850485
--- /dev/null
+++ b/old/tests/functional/scenario_available/rbac_custom_1000.py
@@ -0,0 +1,89 @@
+import random
+
+pdp_name = "pdp_1000"
+policy_name = "RBAC policy example 1000 users"
+model_name = "RBAC"
+policy_genre = "authz"
+
+SUBJECT_NUMBER = 1000
+OBJECT_NUMBER = 500
+ROLE_NUMBER = 50
+
+subjects = {}
+for _id in range(SUBJECT_NUMBER):
+ subjects["user{}".format(_id)] = ""
+objects = {}
+for _id in range(OBJECT_NUMBER):
+ objects["vm{}".format(_id)] = ""
+actions = {
+ "start": "",
+ "stop": "",
+ "pause": "",
+ "unpause": "",
+ "destroy": "",
+}
+
+subject_categories = {"role": "", }
+object_categories = {"id": "", }
+action_categories = {"action-type": "", }
+
+subject_data = {"role": {"admin": "", "*": ""}}
+for _id in range(ROLE_NUMBER):
+ subject_data["role"]["role{}".format(_id)] = ""
+object_data = {"id": {"*": ""}}
+for _id in range(OBJECT_NUMBER):
+ object_data["id"]["vm{}".format(_id)] = ""
+action_data = {"action-type": {
+ "vm-read": "",
+ "vm-write": "",
+ "*": ""
+}}
+
+subject_assignments = {}
+for _id in range(SUBJECT_NUMBER):
+ _role = "role{}".format(random.randrange(ROLE_NUMBER))
+ subject_assignments["user{}".format(_id)] = [{"role": _role}, {"role": "*"}]
+object_assignments = {"vm0": ({"id": "vm0"}, {"id": "*"}), "vm1": ({"id": "vm1"}, {"id": "*"})}
+for _id in range(OBJECT_NUMBER):
+ object_assignments["vm{}".format(_id)] = [{"id": "vm{}".format(_id)}, {"id": "*"}]
+action_assignments = {
+ "start": ({"action-type": "vm-write"}, {"action-type": "*"}),
+ "stop": ({"action-type": "vm-write"}, {"action-type": "*"}),
+ "pause": ({"action-type": "vm-read"}, {"action-type": "*"}),
+ "unpause": ({"action-type": "vm-read"}, {"action-type": "*"}),
+ "destroy": ({"action-type": "vm-write"}, {"action-type": "*"}),
+}
+
+meta_rule = {
+ "rbac": {"id": "", "value": ("role", "id", "action-type")},
+}
+
+rules = {
+ "rbac": [
+ {
+ "rule": ("admin", "vm0", "vm-read"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("admin", "vm0", "vm-write"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ ]
+}
+
+for _id in range(SUBJECT_NUMBER):
+ _role = "role{}".format(random.randrange(ROLE_NUMBER))
+ _vm = "vm{}".format(random.randrange(OBJECT_NUMBER))
+ _action = random.choice(list(action_data['action-type'].keys()))
+ rules["rbac"].append(
+ {
+ "rule": (_role, _vm, _action),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ )
diff --git a/old/tests/functional/scenario_available/rbac_custom_50.py b/old/tests/functional/scenario_available/rbac_custom_50.py
new file mode 100644
index 00000000..e1437cf4
--- /dev/null
+++ b/old/tests/functional/scenario_available/rbac_custom_50.py
@@ -0,0 +1,89 @@
+import random
+
+pdp_name = "pdp_50"
+policy_name = "RBAC policy example 50 users"
+model_name = "RBAC"
+policy_genre = "authz"
+
+SUBJECT_NUMBER = 50
+OBJECT_NUMBER = 50
+ROLE_NUMBER = 10
+
+subjects = {}
+for _id in range(SUBJECT_NUMBER):
+ subjects["user{}".format(_id)] = ""
+objects = {}
+for _id in range(OBJECT_NUMBER):
+ objects["vm{}".format(_id)] = ""
+actions = {
+ "start": "",
+ "stop": "",
+ "pause": "",
+ "unpause": "",
+ "destroy": "",
+}
+
+subject_categories = {"role": "", }
+object_categories = {"id": "", }
+action_categories = {"action-type": "", }
+
+subject_data = {"role": {"admin": "", "*": ""}}
+for _id in range(ROLE_NUMBER):
+ subject_data["role"]["role{}".format(_id)] = ""
+object_data = {"id": {"*": ""}}
+for _id in range(OBJECT_NUMBER):
+ object_data["id"]["vm{}".format(_id)] = ""
+action_data = {"action-type": {
+ "vm-read": "",
+ "vm-write": "",
+ "*": ""
+}}
+
+subject_assignments = {}
+for _id in range(SUBJECT_NUMBER):
+ _role = "role{}".format(random.randrange(ROLE_NUMBER))
+ subject_assignments["user{}".format(_id)] = [{"role": _role}, {"role": "*"}]
+object_assignments = {"vm0": ({"id": "vm0"}, {"id": "*"}), "vm1": ({"id": "vm1"}, {"id": "*"})}
+for _id in range(OBJECT_NUMBER):
+ object_assignments["vm{}".format(_id)] = [{"id": "vm{}".format(_id)}, {"id": "*"}]
+action_assignments = {
+ "start": ({"action-type": "vm-write"}, {"action-type": "*"}),
+ "stop": ({"action-type": "vm-write"}, {"action-type": "*"}),
+ "pause": ({"action-type": "vm-read"}, {"action-type": "*"}),
+ "unpause": ({"action-type": "vm-read"}, {"action-type": "*"}),
+ "destroy": ({"action-type": "vm-write"}, {"action-type": "*"}),
+}
+
+meta_rule = {
+ "rbac": {"id": "", "value": ("role", "id", "action-type")},
+}
+
+rules = {
+ "rbac": [
+ {
+ "rule": ("admin", "vm0", "vm-read"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("admin", "vm0", "vm-write"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ ]
+}
+
+for _id in range(SUBJECT_NUMBER):
+ _role = "role{}".format(random.randrange(ROLE_NUMBER))
+ _vm = "vm{}".format(random.randrange(OBJECT_NUMBER))
+ _action = random.choice(list(action_data['action-type'].keys()))
+ rules["rbac"].append(
+ {
+ "rule": (_role, _vm, _action),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ )
diff --git a/old/tests/functional/scenario_available/rbac_large.py b/old/tests/functional/scenario_available/rbac_large.py
new file mode 100644
index 00000000..ef5dd9b2
--- /dev/null
+++ b/old/tests/functional/scenario_available/rbac_large.py
@@ -0,0 +1,233 @@
+
+pdp_name = "pdp1"
+policy_name = "RBAC policy example"
+model_name = "RBAC"
+policy_genre = "authz"
+
+subjects = {
+ "user0": "",
+ "user1": "",
+ "user2": "",
+ "user3": "",
+ "user4": "",
+ "user5": "",
+ "user6": "",
+ "user7": "",
+ "user8": "",
+ "user9": "",
+}
+objects = {
+ "vm0": "",
+ "vm1": "",
+ "vm2": "",
+ "vm3": "",
+ "vm4": "",
+ "vm5": "",
+ "vm6": "",
+ "vm7": "",
+ "vm8": "",
+ "vm9": "",
+}
+actions = {
+ "start": "",
+ "stop": "",
+ "pause": "",
+ "unpause": "",
+ "destroy": "",
+}
+
+subject_categories = {"role": "", }
+object_categories = {"id": "", }
+action_categories = {"action-type": "", }
+
+subject_data = {"role": {
+ "admin": "",
+ "employee": "",
+ "dev1": "",
+ "dev2": "",
+ "*": ""
+}}
+object_data = {"id": {
+ "vm0": "",
+ "vm1": "",
+ "vm2": "",
+ "vm3": "",
+ "vm4": "",
+ "vm5": "",
+ "vm6": "",
+ "vm7": "",
+ "vm8": "",
+ "vm9": "",
+ "*": ""
+}}
+action_data = {"action-type": {
+ "vm-read": "",
+ "vm-write": "",
+ "*": ""
+}}
+
+subject_assignments = {
+ "user0": ({"role": "employee"}, {"role": "*"}),
+ "user1": ({"role": "employee"}, {"role": "*"}),
+ "user2": ({"role": "dev1"}, {"role": "*"}),
+ "user3": ({"role": "dev1"}, {"role": "*"}),
+ "user4": ({"role": "dev1"}, {"role": "*"}),
+ "user5": ({"role": "dev1"}, {"role": "*"}),
+ "user6": ({"role": "dev2"}, {"role": "*"}),
+ "user7": ({"role": "dev2"}, {"role": "*"}),
+ "user8": ({"role": "dev2"}, {"role": "*"}),
+ "user9": ({"role": "dev2"}, {"role": "*"}),
+}
+object_assignments = {
+ "vm0": ({"id": "vm0"}, {"id": "*"}),
+ "vm1": ({"id": "vm1"}, {"id": "*"}),
+ "vm2": ({"id": "vm2"}, {"id": "*"}),
+ "vm3": ({"id": "vm3"}, {"id": "*"}),
+ "vm4": ({"id": "vm4"}, {"id": "*"}),
+ "vm5": ({"id": "vm5"}, {"id": "*"}),
+ "vm6": ({"id": "vm6"}, {"id": "*"}),
+ "vm7": ({"id": "vm7"}, {"id": "*"}),
+ "vm8": ({"id": "vm8"}, {"id": "*"}),
+ "vm9": ({"id": "vm9"}, {"id": "*"}),
+}
+action_assignments = {
+ "start": ({"action-type": "vm-write"}, {"action-type": "*"}),
+ "stop": ({"action-type": "vm-write"}, {"action-type": "*"}),
+ "pause": ({"action-type": "vm-read"}, {"action-type": "*"}),
+ "unpause": ({"action-type": "vm-read"}, {"action-type": "*"}),
+ "destroy": ({"action-type": "vm-write"}, {"action-type": "*"}),
+}
+
+meta_rule = {
+ "rbac": {"id": "", "value": ("role", "id", "action-type")},
+}
+
+rules = {
+ "rbac": (
+ {
+ "rule": ("admin", "vm0", "vm-read"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("admin", "vm0", "vm-write"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ # Rules for grant all employee to do read actions to all VM except vm0
+ {
+ "rule": ("employee", "vm1", "vm-read"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("employee", "vm2", "vm-read"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("employee", "vm3", "vm-read"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("employee", "vm4", "vm-read"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("employee", "vm5", "vm-read"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("employee", "vm6", "vm-read"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("employee", "vm7", "vm-read"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("employee", "vm8", "vm-read"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("employee", "vm9", "vm-read"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ # Rules for grant all dev1 to do read actions to some VM
+ {
+ "rule": ("dev1", "vm1", "vm-write"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("dev1", "vm2", "vm-write"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("dev1", "vm3", "vm-write"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("dev1", "vm4", "vm-write"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ # Rules for grant all dev2 to do read actions to some VM
+ {
+ "rule": ("dev2", "vm5", "vm-write"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("dev2", "vm6", "vm-write"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("dev2", "vm7", "vm-write"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("dev2", "vm8", "vm-write"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ {
+ "rule": ("dev2", "vm9", "vm-write"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ )
+}
+
+
diff --git a/old/tests/functional/scenario_available/rbac_mls.py b/old/tests/functional/scenario_available/rbac_mls.py
new file mode 100644
index 00000000..8a5362ea
--- /dev/null
+++ b/old/tests/functional/scenario_available/rbac_mls.py
@@ -0,0 +1,50 @@
+
+pdp_name = "pdp1"
+policy_name = "Multi policy example"
+model_name = "RBAC"
+
+subjects = {"user0": "", "user1": "", "user2": "", }
+objects = {"vm0": "", "vm1": "", }
+actions = {"start": "", "stop": ""}
+
+subject_categories = {"role": "", "subject-security-level": "", }
+object_categories = {"id": "", "object-security-level": "", }
+action_categories = {"action-type": "", }
+
+subject_data = {
+ "role": {"admin": "", "employee": ""},
+ "subject-security-level": {"low": "", "medium": "", "high": ""},
+}
+object_data = {
+ "id": {"vm1": "", "vm2": ""},
+ "object-security-level": {"low": "", "medium": "", "high": ""},
+}
+action_data = {"action-type": {"vm-action": "", "storage-action": "", }}
+
+subject_assignments = {
+ "user0": {"role": "admin", "subject-security-level": "high"},
+ "user1": {"role": "employee", "subject-security-level": "medium"},
+}
+object_assignments = {
+ "vm0": {"id": "vm1", "object-security-level": "medium"},
+ "vm1": {"id": "vm2", "object-security-level": "low"},
+}
+action_assignments = {
+ "start": {"action-type": "vm-action"},
+ "stop": {"action-type": "vm-action"}
+}
+
+meta_rule = {
+ "rbac": {"id": "", "value": ("role", "id", "action-type")},
+ "mls": {"id": "", "value": ("subject-security-level", "object-security-level", "action-type")},
+}
+
+rules = {
+ "rbac": (
+ ("admin", "vm1", "vm-action"),
+ ),
+ "mls": (
+ ("high", "medium", "vm-action"),
+ ("medium", "low", "vm-action"),
+ )
+}
diff --git a/old/tests/functional/scenario_available/session.py b/old/tests/functional/scenario_available/session.py
new file mode 100644
index 00000000..97d7aec3
--- /dev/null
+++ b/old/tests/functional/scenario_available/session.py
@@ -0,0 +1,60 @@
+
+pdp_name = "pdp1"
+policy_name = "Session policy example"
+model_name = "Session"
+policy_genre = "session"
+
+subjects = {"user0": "", "user1": "", }
+objects = {"admin": "", "employee": "", }
+actions = {"activate": "", "deactivate": ""}
+
+subject_categories = {"subjectid": "", }
+object_categories = {"role": "", }
+action_categories = {"session-action": "", }
+
+subject_data = {"subjectid": {"user0": "", "user1": ""}}
+object_data = {"role": {"admin": "", "employee": "", "*": ""}}
+action_data = {"session-action": {"activate": "", "deactivate": "", "*": ""}}
+
+subject_assignments = {"user0": ({"subjectid": "user0"}, ), "user1": ({"subjectid": "user1"}, ), }
+object_assignments = {"admin": ({"role": "admin"}, {"role": "*"}),
+ "employee": ({"role": "employee"}, {"role": "employee"})
+ }
+action_assignments = {"activate": ({"session-action": "activate"}, {"session-action": "*"}, ),
+ "deactivate": ({"session-action": "deactivate"}, {"session-action": "*"}, )
+ }
+
+meta_rule = {
+ "session": {"id": "", "value": ("subjectid", "role", "session-action")},
+}
+
+rules = {
+ "session": (
+ {
+ "rule": ("user0", "employee", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user1", "employee", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "delete",
+ "target": "rbac:role:employee" # delete the role employee from the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ )
+}
+
+
diff --git a/old/tests/functional/scenario_available/session_large.py b/old/tests/functional/scenario_available/session_large.py
new file mode 100644
index 00000000..5b4a64b6
--- /dev/null
+++ b/old/tests/functional/scenario_available/session_large.py
@@ -0,0 +1,389 @@
+
+pdp_name = "pdp1"
+policy_name = "Session policy example"
+model_name = "Session"
+policy_genre = "session"
+
+subjects = {
+ "user0": "",
+ "user1": "",
+ "user2": "",
+ "user3": "",
+ "user4": "",
+ "user5": "",
+ "user6": "",
+ "user7": "",
+ "user8": "",
+ "user9": "",
+}
+objects = {"admin": "", "employee": "", "dev1": "", "dev2": "", }
+actions = {"activate": "", "deactivate": ""}
+
+subject_categories = {"subjectid": "", }
+object_categories = {"role": "", }
+action_categories = {"session-action": "", }
+
+subject_data = {"subjectid": {
+ "user0": "",
+ "user1": "",
+ "user2": "",
+ "user3": "",
+ "user4": "",
+ "user5": "",
+ "user6": "",
+ "user7": "",
+ "user8": "",
+ "user9": "",
+}}
+object_data = {"role": {
+ "admin": "",
+ "employee": "",
+ "dev1": "",
+ "dev2": "",
+ "*": ""
+}}
+action_data = {"session-action": {"activate": "", "deactivate": "", "*": ""}}
+
+subject_assignments = {
+ "user0": ({"subjectid": "user0"}, ),
+ "user1": ({"subjectid": "user1"}, ),
+ "user2": ({"subjectid": "user2"}, ),
+ "user3": ({"subjectid": "user3"}, ),
+ "user4": ({"subjectid": "user4"}, ),
+ "user5": ({"subjectid": "user5"}, ),
+ "user6": ({"subjectid": "user6"}, ),
+ "user7": ({"subjectid": "user7"}, ),
+ "user8": ({"subjectid": "user8"}, ),
+ "user9": ({"subjectid": "user9"}, ),
+}
+object_assignments = {"admin": ({"role": "admin"}, {"role": "*"}),
+ "employee": ({"role": "employee"}, {"role": "*"}),
+ "dev1": ({"role": "employee"}, {"role": "dev1"}, {"role": "*"}),
+ "dev2": ({"role": "employee"}, {"role": "dev2"}, {"role": "*"}),
+ }
+action_assignments = {"activate": ({"session-action": "activate"}, {"session-action": "*"}, ),
+ "deactivate": ({"session-action": "deactivate"}, {"session-action": "*"}, )
+ }
+
+meta_rule = {
+ "session": {"id": "", "value": ("subjectid", "role", "session-action")},
+}
+
+rules = {
+ "session": (
+ {
+ "rule": ("user0", "employee", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user1", "employee", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "delete",
+ "target": "rbac:role:employee" # delete the role employee from the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user2", "employee", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user2", "dev1", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user2", "dev2", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user3", "employee", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user3", "dev1", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user3", "dev2", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user4", "employee", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user4", "dev1", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user4", "dev2", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user5", "employee", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user5", "dev1", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user5", "dev2", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user6", "employee", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user6", "dev1", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user6", "dev2", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user7", "employee", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user7", "dev1", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user7", "dev2", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user8", "employee", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user8", "dev1", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user8", "dev2", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user9", "employee", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user9", "dev1", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ {
+ "rule": ("user9", "dev2", "*"),
+ "instructions": (
+ {
+ "update": {
+ "operation": "add",
+ "target": "rbac:role:admin" # add the role admin to the current user
+ }
+ },
+ {"chain": {"name": "rbac"}} # chain with the meta_rule named rbac
+ )
+ },
+ )
+}
+
+
diff --git a/old/tests/functional/scenario_enabled/mls.py b/old/tests/functional/scenario_enabled/mls.py
new file mode 120000
index 00000000..6acd75ce
--- /dev/null
+++ b/old/tests/functional/scenario_enabled/mls.py
@@ -0,0 +1 @@
+../scenario_available/mls.py \ No newline at end of file
diff --git a/old/tests/functional/scenario_enabled/rbac.py b/old/tests/functional/scenario_enabled/rbac.py
new file mode 120000
index 00000000..0edc905a
--- /dev/null
+++ b/old/tests/functional/scenario_enabled/rbac.py
@@ -0,0 +1 @@
+../scenario_available/rbac.py \ No newline at end of file
diff --git a/old/tests/functional/scenario_tests/mls.py b/old/tests/functional/scenario_tests/mls.py
new file mode 100644
index 00000000..0e6285c9
--- /dev/null
+++ b/old/tests/functional/scenario_tests/mls.py
@@ -0,0 +1,59 @@
+
+pdp_name = "pdp_mls"
+policy_name = "MLS Policy example"
+model_name = "MLS"
+policy_genre = "authz"
+
+subjects = {"adminuser": "", "user1": "", "user2": "", }
+objects = {"vm0": "", "vm1": "", }
+actions = {"start": "", "stop": ""}
+
+subject_categories = {"subject-security-level": "", }
+object_categories = {"object-security-level": "", }
+action_categories = {"action-type": "", }
+
+subject_data = {
+ "subject-security-level": {"low": "", "medium": "", "high": ""},
+}
+object_data = {
+ "object-security-level": {"low": "", "medium": "", "high": ""},
+}
+action_data = {"action-type": {"vm-action": "", "storage-action": "", }}
+
+subject_assignments = {
+ "adminuser": {"subject-security-level": "high"},
+ "user1": {"subject-security-level": "medium"},
+}
+object_assignments = {
+ "vm0": {"object-security-level": "medium"},
+ "vm1": {"object-security-level": "low"},
+}
+action_assignments = {
+ "start": {"action-type": "vm-action"},
+ "stop": {"action-type": "vm-action"}
+}
+
+meta_rule = {
+ "mls": {
+ "id": "",
+ "value": ("subject-security-level",
+ "object-security-level",
+ "action-type")},
+}
+
+rules = {
+ "mls": (
+ {
+ "rule": ("high", "medium", "vm-action"),
+ "instructions": ({"decision": "grant"})
+ },
+ {
+ "rule": ("high", "low", "vm-action"),
+ "instructions": ({"decision": "grant"})
+ },
+ {
+ "rule": ("medium", "low", "vm-action"),
+ "instructions": ({"decision": "grant"})
+ },
+ )
+}
diff --git a/old/tests/functional/scenario_tests/rbac.py b/old/tests/functional/scenario_tests/rbac.py
new file mode 100644
index 00000000..1d2cabee
--- /dev/null
+++ b/old/tests/functional/scenario_tests/rbac.py
@@ -0,0 +1,61 @@
+
+pdp_name = "pdp_rbac1"
+policy_name = "RBAC policy example"
+model_name = "RBAC"
+policy_genre = "authz"
+
+subjects = {"adminuser": "", "user1": "", }
+objects = {"vm0": "", "vm1": "", }
+actions = {"start": "", "stop": ""}
+
+subject_categories = {"role": "", }
+object_categories = {"id": "", }
+action_categories = {"action-type": "", }
+
+subject_data = {"role": {"admin": "", "employee": "", "*": ""}}
+object_data = {"id": {"vm0": "", "vm1": "", "*": ""}}
+action_data = {"action-type": {"vm-action": "", "*": ""}}
+
+subject_assignments = {
+ "adminuser":
+ ({"role": "admin"}, {"role": "employee"}, {"role": "*"}),
+ "user1":
+ ({"role": "employee"}, {"role": "*"}),
+}
+object_assignments = {
+ "vm0":
+ ({"id": "vm0"}, {"id": "*"}),
+ "vm1":
+ ({"id": "vm1"}, {"id": "*"})
+}
+action_assignments = {
+ "start":
+ ({"action-type": "vm-action"}, {"action-type": "*"}),
+ "stop":
+ ({"action-type": "vm-action"}, {"action-type": "*"})
+}
+
+meta_rule = {
+ "rbac": {"id": "", "value": ("role", "id", "action-type")},
+}
+
+rules = {
+ "rbac": (
+ {
+ "rule": ("admin", "vm0", "vm-action"),
+ "instructions": (
+ {"decision": "grant"},
+ # "grant" to immediately exit,
+ # "continue" to wait for the result of next policy
+ )
+ },
+ {
+ "rule": ("employee", "vm1", "vm-action"),
+ "instructions": (
+ {"decision": "grant"},
+ )
+ },
+ )
+}
+
+
diff --git a/old/tests/performance/README.md b/old/tests/performance/README.md
new file mode 100644
index 00000000..fcb80589
--- /dev/null
+++ b/old/tests/performance/README.md
@@ -0,0 +1,80 @@
+# Moon Yardstick/Bottlenecks Performance Tests
+
+The main objective of this document is to describe the performance tests for the Moon project/module.
+Moon is a security management platform which provides a set of security functions to project the underlying OPNFV infrastructure and/or VNFs.
+It is consisted of 2 parts: a master and a set of slaves. The master holds all security-related information and each slave only fetches and holds
+related information for its local usage from master.
+
+## Master Performance Tests
+### Pre-requisite
+- setup a Moon master service on a physical server
+- create a project in OpenStack/Keystone
+- create a MSL PDP with a model of 4 subject security levels and 4 object security levels, the MLS policy will be defined later
+
+### Policy Size Test
+Increase the number of users and resources N to find the limit of the security policy
+- create N users and N resources (VMs in our case) in this MLS security policy
+- sends 5 authz requests/second
+- gather performance metrics like CPU, memory, network usages
+Through the iteration, determine the maximal number of N to support 5 requests/second
+
+### PDP Number Test
+- setup 20 user and 20 resources (VMs in our case) for each MLS PDP
+- sends 5 authz requests/second for each MLS PDP
+- increase the number of PDP to test the maximal number of PDP on the master
+
+### Policy Size Test for 5 PDPs
+- setup 5 PDPs of N users and N resources (VMs in our case)
+- sends 5 authz requests/second for each MLS PDP
+- gather performance metrics like CPU, memory, network usages
+Through the iteration, determine the maximal user/resource number of these 5 PDPs
+
+### Policy Size Test for 10 PDPs
+- setup 10 PDPs of N users and N resources (VMs in our case)
+- sends 5 authz requests/second for each MLS PDP
+- gather performance metrics like CPU, memory, network usages
+Through the iteration, determine the maximal user/resource number of these 10 PDPs
+
+### Policy Size Test for 20 PDPs
+- setup 20 PDPs of N users and N resources (VMs in our case)
+- sends 5 authz requests/second for each MLS PDP
+- gather performance metrics like CPU, memory, network usages
+Through the iteration, determine the maximal user/resource number of these 20 PDPs
+
+
+## Master-Slave Performance Tests
+### Pre-requisite
+- setup a Moon master on a physical server
+- setup a Moon slave on a physical server
+- create a project in OpenStack/Keystone
+- create a MSL PDP with a model of 4 subject security levels and 4 object security levels, the MLS policy will be defined later on the master
+
+### Slave Policy Size Test
+Increase the number of users and resources N to find the limit of the security policy
+- create N users and N resources (VMs in our case) in this MLS security policy on the master
+- sends 5 authz requests/second to the slave
+- gather performance metrics like CPU, memory, network usages of the slave
+Through the iteration, determine the maximal number of N to support 5 requests/second of the slave
+
+### Slave PDP Number Test
+- setup 20 user and 20 resources (VMs in our case) for each MLS PDP on the master
+- sends 5 authz requests/second for each MLS PDP to the slave
+Through the iteration, determine the maximal number of PDP to support 5 requests/second of the slave
+
+### Slave Policy Size Test for 5 PDPs
+- setup 5 PDPs of N users and N resources (VMs in our case) on the master
+- sends 5 authz requests/second for each MLS PDP to the slave
+- gather performance metrics like CPU, memory, network usages of the slave
+Through the iteration, determine the maximal user/resource number of these 5 PDPs
+
+### Slave Policy Size Test for 10 PDPs
+- setup 10 PDPs of N users and N resources (VMs in our case) on the master
+- sends 5 authz requests/second for each MLS PDP to the slave
+- gather performance metrics like CPU, memory, network usages of the slave
+Through the iteration, determine the maximal user/resource number of these 10 PDPs
+
+### Slave Policy Size Test for 20 PDPs
+- setup 20 PDPs of N users and N resources (VMs in our case) on the master
+- sends 5 authz requests/second for each MLS PDP to the slave
+- gather performance metrics like CPU, memory, network usages of the slave
+Through the iteration, determine the maximal user/resource number of these 20 PDPs
diff --git a/old/tests/python_unit/README.md b/old/tests/python_unit/README.md
new file mode 100644
index 00000000..a399f834
--- /dev/null
+++ b/old/tests/python_unit/README.md
@@ -0,0 +1,5 @@
+# Python Unit Test
+
+```bash
+bash run_tests.sh
+```
diff --git a/old/tests/python_unit/run_tests.sh b/old/tests/python_unit/run_tests.sh
new file mode 100644
index 00000000..ab30e523
--- /dev/null
+++ b/old/tests/python_unit/run_tests.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+echo "starting Moon Unit Tests"
+
+cd python_moonutilities
+docker run --rm --volume $(pwd):/data wukongsun/moon_python_unit_test:latest
+
+cd ../python_moondb
+docker run --rm --volume $(pwd):/data wukongsun/moon_python_unit_test:latest
+
+cd ../python_moonclient
+docker run --rm --volume $(pwd):/data wukongsun/moon_python_unit_test:latest
+
+cd ../moon_manager
+rm -f tests/unit_python/database.db
+docker run --rm --volume $(pwd):/data wukongsun/moon_python_unit_test:latest
+
diff --git a/old/tools/bin/README.md b/old/tools/bin/README.md
new file mode 100644
index 00000000..71ff4a44
--- /dev/null
+++ b/old/tools/bin/README.md
@@ -0,0 +1,8 @@
+# Automated Tools/Scripts
+
+## api2pdf
+```bash
+python3 $MOON_HOME/tools/bin/api2rst.py
+pandoc api.rst --toc -o api.pdf
+evince api.pdf
+```
diff --git a/old/tools/bin/api2rst.py b/old/tools/bin/api2rst.py
new file mode 100644
index 00000000..6d407bdf
--- /dev/null
+++ b/old/tools/bin/api2rst.py
@@ -0,0 +1,145 @@
+# Copyright 2015 Open Platform for NFV Project, Inc. and its contributors
+# This software is distributed under the terms and conditions of the 'Apache-2.0'
+# license which can be found in the file 'LICENSE' in this package distribution
+# or at 'http://www.apache.org/licenses/LICENSE-2.0'.
+
+import os
+import sys
+import requests
+import logging
+import time
+import json
+
+os.unsetenv("http_proxy")
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+HOST = "172.18.0.11"
+PORT = 38001
+COMPONENT = sys.argv[2] if len(sys.argv) > 1 else "Interface"
+FILENAME = sys.argv[2] if len(sys.argv) > 2 else "api.rst"
+CURRENT_TIME = time.strftime("%Y/%m/%d %H:%M:%S %Z")
+REVISION = time.strftime("%Y%m%d_%H%M%S_%Z")
+AUTHOR = "Thomas Duval <thomas.duval@orange.com>"
+
+logger.info("Writing to {}".format(FILENAME))
+
+toc = (
+ "generic",
+ "models",
+ "policies",
+ "pdp",
+ "meta_rules",
+ "meta_data",
+ "perimeter",
+ "data",
+ "assignments",
+ "rules",
+ "authz",
+)
+
+
+def get_api_list():
+ url = "http://{}:{}/api".format(HOST, PORT)
+ cnx = requests.get(url)
+ try:
+ return cnx.json()
+ except json.decoder.JSONDecodeError:
+ logger.error("Error decoding JSON on {}\n{}".format(url, cnx.content))
+ sys.exit(1)
+
+
+def analyse_description(desc):
+ result = ""
+ if not desc:
+ return "No description"
+ for line in desc.splitlines():
+ if line.strip().startswith(":"):
+ if ":request body:" in line:
+ result += ":request body:\n\n.. code-block:: json\n\n"
+ result += line.replace(":request body: ", "") + "\n\n"
+ elif ":return:" in line:
+ result += ":return:\n\n.. code-block:: json\n\n"
+ result += line.replace(":return: ", "") + "\n"
+ else:
+ result += line.strip() + "\n\n"
+ else:
+ result += line + "\n"
+ return result
+
+
+def filter_and_sort(list_group_api):
+ results = list()
+ keys = list_group_api.keys()
+ for element in toc:
+ if element in keys:
+ results.append(element)
+ for element in keys:
+ if element not in results:
+ results.append(element)
+ return results
+
+
+def main():
+ list_group_api = get_api_list()
+
+ _toc = filter_and_sort(list_group_api)
+
+ file_desc = open(FILENAME, "w")
+ length_of_title = len("Moon {component} API".format(component=COMPONENT))
+ file_desc.write(HEADERS.format(
+ component=COMPONENT,
+ date=CURRENT_TIME,
+ revision=REVISION,
+ title_headers="="*length_of_title,
+ author=AUTHOR
+ ))
+
+ for key in _toc:
+ logger.info(key)
+ file_desc.write("{}\n".format(key))
+ file_desc.write("{}\n\n".format("="*len(key)))
+ if "description" in list_group_api[key]:
+ file_desc.write("{}\n\n".format(list_group_api[key]["description"]))
+ version = "unknown"
+ logger.debug(list_group_api.keys())
+ if "version" in list_group_api[key]:
+ version = list_group_api[key]["version"]
+ file_desc.write("Version: {}\n\n".format(version))
+ for api in list_group_api[key]:
+ logger.info("\t{}".format(api))
+ if api in ("description", "version"):
+ continue
+ file_desc.write("{}\n".format(api))
+ file_desc.write("{}\n\n".format("-" * len(api)))
+
+ file_desc.write("{}\n\n".format(list_group_api[key][api]["description"]))
+
+ file_desc.write("URLs are:\n\n")
+ for _url in list_group_api[key][api]["urls"]:
+ file_desc.write("* {}\n".format(_url))
+
+ file_desc.write("\nMethods are:\n\n")
+ for _method in list_group_api[key][api]["methods"]:
+ file_desc.write("→ {}\n".format(_method))
+ file_desc.write("{}\n\n".format("~"*(len(_method) + 2)))
+ file_desc.write("{}\n\n".format(analyse_description(list_group_api[key][api]["methods"][_method])))
+
+HEADERS = """{title_headers}
+Moon {component} API
+{title_headers}
+
+:Info: See <https://git.opnfv.org/cgit/moon/> for code.
+:Author: {author}
+:Date: {date}
+:Revision: $Revision: {revision} $
+:Description: List of the API served by the Moon {component} component
+
+This document list all of the API connectors served by the Moon {component} component
+Here are Moon API with some examples of posted data and returned data.
+All requests must be prefixed with the host and port, for example: http://localhost:38001/authz/123456789/123456789/servers/list
+
+"""
+
+if __name__ == "__main__":
+ main()
diff --git a/old/tools/bin/bootstrap.py b/old/tools/bin/bootstrap.py
new file mode 100644
index 00000000..6f2a5e03
--- /dev/null
+++ b/old/tools/bin/bootstrap.py
@@ -0,0 +1,235 @@
+import os
+import sys
+import time
+import requests
+import yaml
+import logging
+import json
+import base64
+import mysql.connector
+import re
+import subprocess
+
+logging.basicConfig(level=logging.INFO)
+log = logging.getLogger("moon.bootstrap")
+requests_log = logging.getLogger("requests.packages.urllib3")
+requests_log.setLevel(logging.WARNING)
+requests_log.propagate = True
+
+if len(sys.argv) == 2:
+ if os.path.isfile(sys.argv[1]):
+ CONF_FILENAME = sys.argv[1]
+ CONSUL_HOST = "consul"
+ else:
+ CONF_FILENAME = "moon.conf"
+ CONSUL_HOST = sys.argv[1]
+ CONSUL_PORT = 8500
+else:
+ CONSUL_HOST = sys.argv[1] if len(sys.argv) > 1 else "consul"
+ CONSUL_PORT = sys.argv[2] if len(sys.argv) > 2 else 8500
+ CONF_FILENAME = sys.argv[3] if len(sys.argv) > 3 else "moon.conf"
+HEADERS = {"content-type": "application/json"}
+
+
+def search_config_file():
+ data_config = None
+ for _file in (
+ CONF_FILENAME,
+ "conf/moon.conf",
+ "../moon.conf",
+ "../conf/moon.conf",
+ "/etc/moon/moon.conf",
+ ):
+ try:
+ data_config = yaml.safe_load(open(_file))
+ except FileNotFoundError:
+ data_config = None
+ continue
+ else:
+ break
+ if not data_config:
+ raise Exception("Configuration file not found...")
+ return data_config
+
+
+def put(key, value):
+ url = "http://{host}:{port}/v1/kv/{key}".format(host=CONSUL_HOST, port=CONSUL_PORT, key=key)
+ log.info(url)
+ req = requests.put(
+ url,
+ headers=HEADERS,
+ json=value
+ )
+ if req.status_code != 200:
+ raise Exception("Error connecting to Consul ({}, {})".format(req.status_code, req.text))
+
+
+def get(key):
+ url = "http://{host}:{port}/v1/kv/{key}".format(host=CONSUL_HOST, port=CONSUL_PORT, key=key)
+ req = requests.get(url)
+ data = req.json()
+ for item in data:
+ log.info("{} {} -> {}".format(
+ req.status_code,
+ item["Key"],
+ json.loads(base64.b64decode(item["Value"]).decode("utf-8"))
+ ))
+ yield json.loads(base64.b64decode(item["Value"]).decode("utf-8"))
+
+
+def start_consul(data_config):
+ cmd = ["docker", "run", "-d", "--net=moon", "--name=consul", "--hostname=consul", "-p", "8500:8500", "consul"]
+ output = subprocess.run(cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ if output.returncode != 0:
+ log.info(" ".join(cmd))
+ log.info(output.returncode)
+ log.error(output.stderr)
+ log.error(output.stdout)
+ raise Exception("Error starting Consul container!")
+ while True:
+ try:
+ req = requests.get("http://{}:{}/ui".format(CONSUL_HOST, CONSUL_PORT))
+ except requests.exceptions.ConnectionError:
+ log.info("Waiting for Consul ({}:{})".format(CONSUL_HOST, CONSUL_PORT))
+ time.sleep(1)
+ continue
+ else:
+ break
+ # if req.status_code in (302, 200):
+ # break
+ # log.info("Waiting for Consul ({}:{})".format(CONSUL_HOST, CONSUL_PORT))
+ # time.sleep(1)
+ log.info("Consul is up")
+
+ req = requests.get("http://{}:{}/v1/kv/database".format(CONSUL_HOST, CONSUL_PORT))
+ if req.status_code == 200:
+ log.info("Consul is already populated")
+ return
+
+ put("database", data_config["database"])
+ put("messenger", data_config["messenger"])
+ put("slave", data_config["slave"])
+ put("docker", data_config["docker"])
+ put("logging", data_config["logging"])
+ put("components_port_start", data_config["components"]["port_start"])
+
+ for _key, _value in data_config["components"].items():
+ if type(_value) is dict:
+ put("components/{}".format(_key), data_config["components"][_key])
+
+ for _key, _value in data_config["plugins"].items():
+ put("plugins/{}".format(_key), data_config["plugins"][_key])
+
+ for _key, _value in data_config["openstack"].items():
+ put("openstack/{}".format(_key), data_config["openstack"][_key])
+
+
+def start_database():
+ cmd = ["docker", "run", "-dti", "--net=moon", "--hostname=db", "--name=db",
+ "-e", "MYSQL_ROOT_PASSWORD=p4sswOrd1", "-e", "MYSQL_DATABASE=moon", "-e", "MYSQL_USER=moon",
+ "-e", "MYSQL_PASSWORD=p4sswOrd1", "-p", "3306:3306", "mysql:latest"]
+ output = subprocess.run(cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ if output.returncode != 0:
+ log.info(cmd)
+ log.error(output.stderr)
+ log.error(output.stdout)
+ raise Exception("Error starting DB container!")
+ for database in get("database"):
+ database_url = database['url']
+ match = re.search("(?P<proto>^[\\w+]+):\/\/(?P<user>\\w+):(?P<password>.+)@(?P<host>\\w+):*(?P<port>\\d*)",
+ database_url)
+ config = match.groupdict()
+ while True:
+ try:
+ conn = mysql.connector.connect(
+ host=config["host"],
+ user=config["user"],
+ password=config["password"],
+ database="moon"
+ )
+ conn.close()
+ except mysql.connector.errors.InterfaceError:
+ log.info("Waiting for Database ({})".format(config["host"]))
+ time.sleep(1)
+ continue
+ else:
+ log.info("Database is up, populating it...")
+ output = subprocess.run(["moon_db_manager", "upgrade"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ if output.returncode != 0:
+ raise Exception("Error populating the database!")
+ break
+
+
+def start_keystone():
+ output = subprocess.run(["docker", "run", "-dti", "--net=moon", "--hostname=keystone", "--name=keystone",
+ "-e", "DB_HOST=db", "-e", "DB_PASSWORD_ROOT=p4sswOrd1", "-p", "35357:35357",
+ "-p", "5000:5000", "keystone:mitaka"],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ if output.returncode != 0:
+ raise Exception("Error starting Keystone container!")
+ # TODO: Keystone answers request too quickly
+ # even if it is not fully loaded
+ # we must test if a token retrieval is possible or not
+ # to see if Keystone is truly up and running
+ for config in get("openstack/keystone"):
+ while True:
+ try:
+ time.sleep(1)
+ req = requests.get(config["url"])
+ except requests.exceptions.ConnectionError:
+ log.info("Waiting for Keystone ({})".format(config["url"]))
+ time.sleep(1)
+ continue
+ else:
+ log.info("Keystone is up")
+ break
+
+
+def start_moon(data_config):
+ cmds = [
+ # ["docker", "run", "-dti", "--net=moon", "--name=wrapper", "--hostname=wrapper", "-p",
+ # "{0}:{0}".format(data_config['components']['wrapper']['port']),
+ # data_config['components']['wrapper']['container']],
+ ["docker", "run", "-dti", "--net=moon", "--name=manager",
+ "--hostname=manager", "-p",
+ "{0}:{0}".format(data_config['components']['manager']['port']),
+ data_config['components']['manager']['container']],
+ ["docker", "run", "-dti", "--net=moon", "--name=interface",
+ "--hostname=interface", "-p",
+ "{0}:{0}".format(data_config['components']['interface']['port']),
+ data_config['components']['interface']['container']],
+ ]
+ for cmd in cmds:
+ log.warning("Start {}".format(cmd[-1]))
+ # answer = input()
+ # if answer.lower() in ("y", "yes", "o", "oui"):
+ output = subprocess.run(cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ time.sleep(3)
+ if output.returncode != 0:
+ log.info(" ".join(cmd))
+ log.info(output.returncode)
+ log.error(output.stderr)
+ log.error(output.stdout)
+ raise Exception("Error starting {} container!".format(cmd[-1]))
+ subprocess.run(["docker", "ps"])
+
+
+def main():
+ data_config = search_config_file()
+ subprocess.run(["docker", "rm", "-f", "consul", "db", "manager", "wrapper", "interface", "authz*", "keystone"])
+ start_consul(data_config)
+ start_database()
+ start_keystone()
+ start_moon(data_config)
+
+main()
+
diff --git a/old/tools/bin/build_all.sh b/old/tools/bin/build_all.sh
new file mode 100644
index 00000000..5bbf6a19
--- /dev/null
+++ b/old/tools/bin/build_all.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+VERSION=v4.1
+export DOCKER_HOST=tcp://172.88.88.1:2376
+
+
+mkdir $MOON_HOME/moon_orchestrator/dist 2>/dev/null
+
+echo Building Moon_Orchestrator
+cd $MOON_HOME/moon_orchestrator
+docker build -t wukongsun/moon_orchestrator:${VERSION} .
+
+echo Building Moon_Interface
+cd $MOON_HOME/moon_interface
+docker build -t wukongsun/moon_interface:${VERSION} .
+
+echo Building Moon_Security_Router
+cd $MOON_HOME/moon_secrouter
+docker build -t wukongsun/moon_router:${VERSION} .
+
+echo Building Moon_Manager
+cd $MOON_HOME/moon_manager
+docker build -t wukongsun/moon_manager:${VERSION} .
+
+echo Building Moon_Authz
+cd $MOON_HOME/moon_authz
+docker build -t wukongsun/moon_authz:${VERSION} .
+
+
+echo Building Moon_DB
+cd $MOON_HOME/moon_db
+python3 setup.py sdist bdist_wheel > /tmp/moon_db.log
+
+echo Building Moon_Utilities
+cd $MOON_HOME/moon_utilities
+python3 setup.py sdist bdist_wheel > /tmp/moon_utilities.log
diff --git a/old/tools/bin/build_all_pip.sh b/old/tools/bin/build_all_pip.sh
new file mode 100644
index 00000000..2b415bf0
--- /dev/null
+++ b/old/tools/bin/build_all_pip.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+
+echo Building Moon_DB
+cd $MOON_HOME/moon_db
+python3 setup.py sdist bdist_wheel> /tmp/moon_db.log
+
+
+echo Building Moon_Utilities
+cd $MOON_HOME/moon_utilities
+python3 setup.py sdist bdist_wheel> /tmp/moon_utilities.log
+
+
+echo Building Moon_Orchestrator
+cd $MOON_HOME/moon_orchestrator
+python3 setup.py sdist bdist_wheel> /tmp/moon_orchestrator.log \ No newline at end of file
diff --git a/old/tools/bin/delete_orchestrator.sh b/old/tools/bin/delete_orchestrator.sh
new file mode 100644
index 00000000..4d9d7c98
--- /dev/null
+++ b/old/tools/bin/delete_orchestrator.sh
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+
+set +x
+
+kubectl delete -n moon -f tools/moon_kubernetes/templates/moon_orchestrator.yaml
+for i in $(kubectl get deployments -n moon | grep wrapper | cut -d " " -f 1 | xargs); do
+ echo deleting $i
+ kubectl delete deployments/$i -n moon;
+done
+for i in $(kubectl get deployments -n moon | grep pipeline | cut -d " " -f 1 | xargs); do
+ echo deleting $i
+ kubectl delete deployments/$i -n moon;
+done
+for i in $(kubectl get services -n moon | grep wrapper | cut -d " " -f 1 | xargs); do
+ echo deleting $i
+ kubectl delete services/$i -n moon;
+done
+for i in $(kubectl get services -n moon | grep pipeline | cut -d " " -f 1 | xargs); do
+ echo deleting $i
+ kubectl delete services/$i -n moon;
+done
+
+if [ "$1" = "build" ]; then
+
+ DOCKER_ARGS=""
+
+ cd moon_manager
+ docker build -t wukongsun/moon_manager:v4.3.1 . ${DOCKER_ARGS}
+ if [ "$2" = "push" ]; then
+ docker push wukongsun/moon_manager:v4.3.1
+ fi
+ cd -
+
+ cd moon_orchestrator
+ docker build -t wukongsun/moon_orchestrator:v4.3 . ${DOCKER_ARGS}
+ if [ "$2" = "push" ]; then
+ docker push wukongsun/moon_orchestrator:v4.3
+ fi
+ cd -
+
+ cd moon_interface
+ docker build -t wukongsun/moon_interface:v4.3 . ${DOCKER_ARGS}
+ if [ "$2" = "push" ]; then
+ docker push wukongsun/moon_interface:v4.3
+ fi
+ cd -
+
+ cd moon_authz
+ docker build -t wukongsun/moon_authz:v4.3 . ${DOCKER_ARGS}
+ if [ "$2" = "push" ]; then
+ docker push wukongsun/moon_authz:v4.3
+ fi
+ cd -
+
+ cd moon_wrapper
+ docker build -t wukongsun/moon_wrapper:v4.3 . ${DOCKER_ARGS}
+ if [ "$2" = "push" ]; then
+ docker push wukongsun/moon_wrapper:v4.3
+ fi
+ cd -
+fi
diff --git a/old/tools/bin/get_keystone_token.py b/old/tools/bin/get_keystone_token.py
new file mode 100644
index 00000000..1856aab8
--- /dev/null
+++ b/old/tools/bin/get_keystone_token.py
@@ -0,0 +1,71 @@
+import requests
+from oslo_config import cfg
+from oslo_log import log as logging
+from python_moonutilities import exceptions
+
+CONF = cfg.CONF
+LOG = logging.getLogger(__name__)
+
+
+def login(user=None, password=None, domain=None, project=None, url=None):
+ print("""Configuration:
+ user: {user}
+ domain: {domain}
+ project: {project}
+ url: {url}""".format(
+ user=CONF.keystone.user,
+ domain=CONF.keystone.domain,
+ project=CONF.keystone.project,
+ url=CONF.keystone.url,
+ ))
+ if not user:
+ user = CONF.keystone.user
+ if not password:
+ password = CONF.keystone.password
+ if not domain:
+ domain = CONF.keystone.domain
+ if not project:
+ project = CONF.keystone.project
+ if not url:
+ url = CONF.keystone.url
+ headers = {
+ "Content-Type": "application/json"
+ }
+ data_auth = {
+ "auth": {
+ "identity": {
+ "methods": [
+ "password"
+ ],
+ "password": {
+ "user": {
+ "domain": {
+ "id": domain
+ },
+ "name": user,
+ "password": password
+ }
+ }
+ },
+ "scope": {
+ "project": {
+ "domain": {
+ "id": domain
+ },
+ "name": project
+ }
+ }
+ }
+ }
+
+ req = requests.post("{}/auth/tokens".format(url),
+ json=data_auth, headers=headers,
+ verify=False)
+
+ if req.status_code not in (200, 201):
+ LOG.error(req.text)
+ raise exceptions.KeystoneError
+ headers['X-Auth-Token'] = req.headers['X-Subject-Token']
+ return headers
+
+print(login()['X-Auth-Token'])
diff --git a/old/tools/bin/moon_lib_upload.sh b/old/tools/bin/moon_lib_upload.sh
new file mode 100644
index 00000000..d2dc2a3f
--- /dev/null
+++ b/old/tools/bin/moon_lib_upload.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+# usage: moon_update.sh <GPG_ID>
+
+COMPONENT=$(basename $(pwd))
+GPG_ID=$1
+
+if [ -f setup.py ]; then
+ echo
+else
+ echo "Not a python package"
+ exit 1
+fi
+
+VERSION=${COMPONENT}-$(grep __version__ ${COMPONENT}/__init__.py | cut -d "\"" -f 2)
+
+python3 setup.py sdist bdist_wheel
+
+echo $COMPONENT
+echo $VERSION
+
+# Instead of "A0A96E75", use your own GPG ID
+rm dist/*.asc 2>/dev/null
+gpg --detach-sign -u "${GPG_ID}" -a dist/${VERSION}-py3-none-any.whl
+gpg --detach-sign -u "${GPG_ID}" -a dist/${VERSION/_/-}.tar.gz
+twine upload dist/${VERSION}-py3-none-any.whl dist/${VERSION}-py3-none-any.whl.asc
+twine upload dist/${VERSION/_/-}.tar.gz dist/${VERSION/_/-}.tar.gz.asc
diff --git a/old/tools/bin/set_auth.src b/old/tools/bin/set_auth.src
new file mode 100644
index 00000000..d955e30b
--- /dev/null
+++ b/old/tools/bin/set_auth.src
@@ -0,0 +1,7 @@
+export OS_USERNAME=admin
+export OS_PASSWORD=p4ssw0rd
+export OS_REGION_NAME=Orange
+export OS_TENANT_NAME=admin
+export OS_AUTH_URL=http://keystone:5000/v3
+export OS_DOMAIN_NAME=Default
+export MOON_URL=http://172.18.0.11:38001
diff --git a/old/tools/bin/start.sh b/old/tools/bin/start.sh
new file mode 100755
index 00000000..e95ac393
--- /dev/null
+++ b/old/tools/bin/start.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+
+VERSION=4.1
+export DOCKER_HOST=tcp://172.88.88.1:2376
+
+echo -e "\033[31mDeleting previous dockers\033[m"
+docker rm -f $(docker ps -a | grep moon | cut -d " " -f 1) 2>/dev/null
+docker rm -f messenger db keystone consul 2>/dev/null
+
+echo -e "\033[32mStarting Messenger\033[m"
+docker run -dti --net=moon --hostname messenger --name messenger -e RABBITMQ_DEFAULT_USER=moon -e RABBITMQ_DEFAULT_PASS=p4sswOrd1 -e RABBITMQ_NODENAME=rabbit@messenger -e RABBITMQ_DEFAULT_VHOST=moon -e RABBITMQ_HIPE_COMPILE=1 -p 5671:5671 -p 5672:5672 -p 8080:15672 rabbitmq:3-management
+
+echo -e "\033[32mStarting DB manager\033[m"
+docker run -dti --net=moon --hostname db --name db -e MYSQL_ROOT_PASSWORD=p4sswOrd1 -e MYSQL_DATABASE=moon -e MYSQL_USER=moon -e MYSQL_PASSWORD=p4sswOrd1 -p 3306:3306 mysql:latest
+
+docker run -d --net=moon --name=consul --hostname=consul -p 8500:8500 consul
+
+echo "waiting for Database (it may takes time)..."
+echo -e "\033[35m"
+sed '/ready for connections/q' <(docker logs db -f)
+echo -e "\033[m"
+
+echo "waiting for Messenger (it may takes time)..."
+echo -e "\033[35m"
+sed '/Server startup complete;/q' <(docker logs messenger -f)
+echo -e "\033[m"
+
+docker run -dti --net moon --hostname keystone --name keystone -e DB_HOST=db -e DB_PASSWORD_ROOT=p4sswOrd1 -p 35357:35357 -p 5000:5000 keystone:mitaka
+
+echo -e "\033[32mConfiguring Moon platform\033[m"
+sudo pip install moon_db
+moon_db_manager upgrade
+
+cd ${MOON_HOME}/moon_orchestrator
+python3 populate_consul.py
+
+echo -e "\033[32mStarting Moon platform\033[m"
+
+docker container run -dti --net moon --hostname orchestrator --name orchestrator wukongsun/moon_orchestrator:${VERSION}
diff --git a/old/tools/moon_jenkins/Dockerfile b/old/tools/moon_jenkins/Dockerfile
new file mode 100644
index 00000000..058f388c
--- /dev/null
+++ b/old/tools/moon_jenkins/Dockerfile
@@ -0,0 +1,8 @@
+FROM jenkinsci/blueocean
+
+ENV JAVA_OPTS="-Djenkins.install.runSetupWizard=false"
+
+COPY security.groovy /usr/share/jenkins/ref/init.groovy.d/security.groovy
+
+COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
+RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt \ No newline at end of file
diff --git a/old/tools/moon_jenkins/README.md b/old/tools/moon_jenkins/README.md
new file mode 100644
index 00000000..684b351c
--- /dev/null
+++ b/old/tools/moon_jenkins/README.md
@@ -0,0 +1,37 @@
+# Moon Jenkins
+The aim of this repo is to give a quick way to start with jenkins in containers.
+These were the aims of the automation:
+- minimal interaction with Jenkins GUI - the plugins in plugins.txt are installed automatically, the admin user is setup based on environment variables, proxy variables are inherited from environment
+- the build of the custom image is integrated in the same workflow
+
+## Prerequisites
+- one host running a newer version of the docker-engine
+- docker-compose 1.18.0
+
+## Usage
+- Setup secrets:
+```bash
+export JENKINS_USER=admin
+export JENKINS_PASSWORD=admin
+```
+- Deploy jenkins:
+```bash
+docker-compose up -d
+ ```
+- Test: Jenkins GUI can be available on `http://<docker host IP>:8080`
+
+
+## Pipeline Creation
+You may find bellow an example of pipeline creation using BlueOcean interface.
+As example I used a clone (https://github.com/brutus333/moon.git) of the moon project (https://git.opnfv.org/moon/)
+
+Click on "Create a new job" in the classical Jenkins UI and follow the steps highlighted bellow:
+
+![Create Multibranch Pipeline](images/Create%20Multibranch%20Pipeline.png)
+![Select Source](images/Select%20Source%20Multibranch%20Pipeline.png)
+![Configure Source](images/Git%20Source%20Multibranch%20Pipeline.png)
+![Multibranch Pipeline Log](images/Multibranch%20Pipeline%20Log.png)
+
+Clicking on BlueOcean shows the pipeline in the blueocean interface:
+
+![Blue Ocean Pipeline success](images/blue%20ocean%20success%20pipeline.png)
diff --git a/old/tools/moon_jenkins/docker-compose.yml b/old/tools/moon_jenkins/docker-compose.yml
new file mode 100644
index 00000000..eb9354ce
--- /dev/null
+++ b/old/tools/moon_jenkins/docker-compose.yml
@@ -0,0 +1,20 @@
+version: '3.1'
+
+services:
+ jenkins:
+ build:
+ context: .
+ image: blueocean:v0.4
+ ports:
+ - 8080:8080
+ - 50000:50000
+ environment:
+ - jenkins_user=${JENKINS_USER}
+ - jenkins_password=${JENKINS_PASSWORD}
+ volumes:
+ - jenkins-data:/var/jenkins_home
+ - /var/run/docker.sock:/var/run/docker.sock
+ user: root
+
+volumes:
+ jenkins-data: \ No newline at end of file
diff --git a/old/tools/moon_jenkins/images/Create Multibranch Pipeline.png b/old/tools/moon_jenkins/images/Create Multibranch Pipeline.png
new file mode 100644
index 00000000..c71415c0
--- /dev/null
+++ b/old/tools/moon_jenkins/images/Create Multibranch Pipeline.png
Binary files differ
diff --git a/old/tools/moon_jenkins/images/Git Source Multibranch Pipeline.png b/old/tools/moon_jenkins/images/Git Source Multibranch Pipeline.png
new file mode 100644
index 00000000..dd37f217
--- /dev/null
+++ b/old/tools/moon_jenkins/images/Git Source Multibranch Pipeline.png
Binary files differ
diff --git a/old/tools/moon_jenkins/images/Multibranch Pipeline Log.png b/old/tools/moon_jenkins/images/Multibranch Pipeline Log.png
new file mode 100644
index 00000000..a1905934
--- /dev/null
+++ b/old/tools/moon_jenkins/images/Multibranch Pipeline Log.png
Binary files differ
diff --git a/old/tools/moon_jenkins/images/Select Source Multibranch Pipeline.png b/old/tools/moon_jenkins/images/Select Source Multibranch Pipeline.png
new file mode 100644
index 00000000..eadbe916
--- /dev/null
+++ b/old/tools/moon_jenkins/images/Select Source Multibranch Pipeline.png
Binary files differ
diff --git a/old/tools/moon_jenkins/plugins.txt b/old/tools/moon_jenkins/plugins.txt
new file mode 100644
index 00000000..65bae872
--- /dev/null
+++ b/old/tools/moon_jenkins/plugins.txt
@@ -0,0 +1,100 @@
+ssh-credentials
+git
+blueocean-dashboard
+pipeline-model-api
+pipeline-graph-analysis
+workflow-support
+display-url-api
+blueocean-config
+workflow-cps
+branch-api
+blueocean-i18n
+workflow-job
+blueocean-bitbucket-pipeline
+favorite
+docker-commons
+pipeline-input-step
+blueocean-pipeline-api-impl
+workflow-api
+jackson2-api
+git-client
+blueocean-pipeline-scm-api
+blueocean
+pipeline-build-step
+jquery-detached
+matrix-project
+antisamy-markup-formatter
+pipeline-model-extensions
+docker-workflow
+github
+git-server
+authentication-tokens
+workflow-cps-global-lib
+pipeline-model-definition
+workflow-scm-step
+pipeline-model-declarative-agent
+cloudbees-bitbucket-branch-source
+script-security
+scm-api
+blueocean-rest
+variant
+sse-gateway
+htmlpublisher
+matrix-auth
+pubsub-light
+blueocean-github-pipeline
+token-macro
+credentials
+mercurial
+plain-credentials
+blueocean-events
+github-api
+blueocean-git-pipeline
+structs
+durable-task
+pipeline-milestone-step
+blueocean-pipeline-editor
+blueocean-web
+pipeline-stage-tags-metadata
+ace-editor
+blueocean-commons
+blueocean-jira
+blueocean-rest-impl
+workflow-step-api
+blueocean-personalization
+workflow-basic-steps
+blueocean-display-url
+jira
+pipeline-stage-step
+jsch
+blueocean-jwt
+cloudbees-folder
+credentials-binding
+github-branch-source
+apache-httpcomponents-client-4-api
+blueocean-autofavorite
+workflow-multibranch
+mailer
+workflow-durable-task-step
+junit
+command-launcher
+bouncycastle-api
+build-timeout
+timestamper
+resource-disposer
+ws-cleanup
+ant
+gradle
+pipeline-rest-api
+handlebars
+momentjs
+pipeline-stage-view
+workflow-aggregator
+pipeline-github-lib
+mapdb-api
+subversion
+ssh-slaves
+pam-auth
+ldap
+email-ext
+locale \ No newline at end of file
diff --git a/old/tools/moon_jenkins/security.groovy b/old/tools/moon_jenkins/security.groovy
new file mode 100644
index 00000000..0fb5ff6e
--- /dev/null
+++ b/old/tools/moon_jenkins/security.groovy
@@ -0,0 +1,20 @@
+#!groovy
+
+import jenkins.model.*
+import hudson.security.*
+
+def instance = Jenkins.getInstance()
+
+def user = System.getenv()['jenkins_user']
+def pass = System.getenv()['jenkins_password']
+// Create user account
+def hudsonRealm = new HudsonPrivateSecurityRealm(false)
+hudsonRealm.createAccount(user,pass)
+instance.setSecurityRealm(hudsonRealm)
+
+// Enable matrix auth strategy and set my_user as admin
+def strategy = new GlobalMatrixAuthorizationStrategy()
+strategy.add(Jenkins.ADMINISTER, user)
+instance.setAuthorizationStrategy(strategy)
+
+instance.save()
diff --git a/old/tools/moon_keystone/Dockerfile b/old/tools/moon_keystone/Dockerfile
new file mode 100644
index 00000000..2a43bd92
--- /dev/null
+++ b/old/tools/moon_keystone/Dockerfile
@@ -0,0 +1,25 @@
+FROM ubuntu:zesty
+
+ENV ADMIN_TOKEN=p4ssw0rd
+ENV ADMIN_PASSWORD=p4ssw0rd
+ENV DB_CONNECTION="mysql+pymysql"
+ENV DB_DRIVER=sql
+ENV DB_HOST=localhost
+ENV DB_DATABASE=keystonedb
+ENV DB_USER=keystone
+ENV DB_PASSWORD=p4ssw0rd
+ENV DB_USER_ROOT=root
+ENV DB_PASSWORD_ROOT=p4sswOrd1
+ENV RABBIT_NODE=server
+ENV INTERFACE_HOST="http://localhost:3001"
+
+RUN apt update && apt install apache2 rabbitmq-server keystone python-openstackclient libapache2-mod-wsgi mysql-client -y
+
+# RUN apt update && apt install iputils-ping net-tools -y
+
+ADD run.sh /root
+
+EXPOSE 35357
+EXPOSE 5000
+
+CMD ["/bin/bash", "/root/run.sh"] \ No newline at end of file
diff --git a/old/tools/moon_keystone/README.md b/old/tools/moon_keystone/README.md
new file mode 100644
index 00000000..7027324e
--- /dev/null
+++ b/old/tools/moon_keystone/README.md
@@ -0,0 +1,26 @@
+# Keystone container
+
+## build keystone image
+
+without proxy:
+```bash
+docker build -t keystone:mitaka .
+```
+
+with a proxy:
+```bash
+docker build --build-arg https_proxy=http://proxy:3128 --build-arg http_proxy=http://proxy:3128 -t keystone:mitaka .
+```
+
+
+### access to the container
+```bash
+docker container exec -ti keystone /bin/bash
+export OS_USERNAME=admin
+export OS_PASSWORD=p4ssw0rd
+export OS_REGION_NAME=Orange
+export OS_TENANT_NAME=admin
+export OS_AUTH_URL=http://localhost:5000/v3
+export OS_DOMAIN_NAME=Default
+openstack project list
+``` \ No newline at end of file
diff --git a/old/tools/moon_keystone/run.sh b/old/tools/moon_keystone/run.sh
new file mode 100644
index 00000000..2a61901e
--- /dev/null
+++ b/old/tools/moon_keystone/run.sh
@@ -0,0 +1,81 @@
+#!/usr/bin/env bash
+
+MY_HOSTNAME=localhost
+
+echo DB_HOST=$DB_HOST
+echo DB_DATABASE=$DB_DATABASE
+echo RABBIT_NODE=$RABBIT_NODE
+echo RABBIT_NODE=$[RABBIT_NODE]
+echo INTERFACE_HOST=$INTERFACE_HOST
+
+sed "s/#admin_token = <None>/admin_token=$ADMIN_TOKEN/g" -i /etc/keystone/keystone.conf
+sed "s/#connection = <None>/connection = $DB_CONNECTION:\/\/$DB_USER:$DB_PASSWORD@$DB_HOST\/$DB_DATABASE/g" -i /etc/keystone/keystone.conf
+
+cat << EOF | tee -a /etc/keystone/keystone.conf
+[cors]
+allowed_origin = $INTERFACE_HOST
+max_age = 3600
+allow_methods = POST,GET,DELETE
+EOF
+
+until echo status | mysql -h${DB_HOST} -u${DB_USER_ROOT} -p${DB_PASSWORD_ROOT}; do
+ >&2 echo "MySQL is unavailable - sleeping"
+ sleep 1
+done
+
+>&2 echo "Mysql is up - executing command"
+
+mysql -h $DB_HOST -u$DB_USER_ROOT -p$DB_PASSWORD_ROOT <<EOF
+CREATE DATABASE $DB_DATABASE DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
+GRANT ALL ON $DB_DATABASE.* TO '$DB_USER'@'%' IDENTIFIED BY '$DB_PASSWORD';
+GRANT ALL ON $DB_DATABASE.* TO '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASSWORD';
+EOF
+
+keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone
+keystone-manage credential_setup --keystone-user keystone --keystone-group keystone
+
+su -s /bin/sh -c "keystone-manage db_sync" keystone
+
+keystone-manage bootstrap \
+ --bootstrap-password ${ADMIN_PASSWORD} \
+ --bootstrap-username admin \
+ --bootstrap-project-name admin \
+ --bootstrap-role-name admin \
+ --bootstrap-service-name keystone \
+ --bootstrap-region-id Orange \
+ --bootstrap-admin-url http://localhost:35357 \
+ --bootstrap-public-url http://localhost:5000 \
+ --bootstrap-internal-url http://localhost:5000
+
+
+service apache2 start
+
+export OS_USERNAME=admin
+export OS_PASSWORD=${ADMIN_PASSWORD}
+export OS_REGION_NAME=Orange
+export OS_TENANT_NAME=admin
+export OS_AUTH_URL=http://localhost:5000/v3
+export OS_DOMAIN_NAME=Default
+export OS_IDENTITY_API_VERSION=3
+
+openstack project create --description "Service Project" demo
+openstack role create user
+openstack role add --project demo --user demo user
+
+echo -e "\n Project list:"
+openstack project list
+
+echo -e "\n Users list:"
+openstack user list
+
+echo -e "\n Roles list:"
+openstack role list
+
+echo -e "\n Service list:"
+openstack service list
+
+echo -e "\n Endpoint list:"
+openstack endpoint list
+
+
+tail -f /var/log/apache2/keystone.log \ No newline at end of file
diff --git a/old/tools/moon_kubernetes/README.md b/old/tools/moon_kubernetes/README.md
new file mode 100644
index 00000000..e75fe086
--- /dev/null
+++ b/old/tools/moon_kubernetes/README.md
@@ -0,0 +1,141 @@
+# Moon Platform Setup
+## Docker Installation
+```bash
+apt update
+apt install -y docker.io
+```
+
+## K8S Installation
+Choose the right K8S platform
+### Minikube
+```bash
+curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
+chmod +x ./kubectl
+sudo mv ./kubectl /usr/local/bin/kubectl
+curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.21.0/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/
+```
+
+### Kubeadm
+see: https://kubernetes.io/docs/setup/independent/install-kubeadm/
+```bash
+apt-get update && apt-get install -y apt-transport-https
+curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
+cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
+deb http://apt.kubernetes.io/ kubernetes-xenial main
+EOF
+apt-get update
+apt-get install -y kubelet kubeadm kubectl
+```
+
+## Moon Deployment
+### Deploy kubernete and moon
+```bash
+cd $MOON_HOME
+bash tools/moon_kubernetes/init_k8s_moon.sh
+```
+This will wait for kubernetes and then moon to be up
+
+To check that the platform is running correctely,
+```bash
+watch kubectl get po --namespace=kube-system
+```
+You must see something like this:
+
+ $ kubectl get po --namespace=kube-system
+ NAME READY STATUS RESTARTS AGE
+ calico-etcd-7qgjb 1/1 Running 0 1h
+ calico-node-f8zvm 2/2 Running 1 1h
+ calico-policy-controller-59fc4f7888-ns9kv 1/1 Running 0 1h
+ etcd-varuna 1/1 Running 0 1h
+ kube-apiserver-varuna 1/1 Running 0 1h
+ kube-controller-manager-varuna 1/1 Running 0 1h
+ kube-dns-bfbb49cd7-rgqxn 3/3 Running 0 1h
+ kube-proxy-x88wg 1/1 Running 0 1h
+ kube-scheduler-varuna 1/1 Running 0 1h
+
+```bash
+watch kubectl get po --namespace=moon
+```
+
+You must see something like this:
+
+ $ kubectl get po --namespace=moon
+ NAME READY STATUS RESTARTS AGE
+ consul-57b6d66975-9qnfx 1/1 Running 0 52m
+ db-867f9c6666-bq8cf 1/1 Running 0 52m
+ gui-bc9878b58-q288x 1/1 Running 0 51m
+ keystone-7d9cdbb69f-bl6ln 1/1 Running 0 52m
+ manager-5bfbb96988-2nvhd 1/1 Running 0 51m
+ manager-5bfbb96988-fg8vj 1/1 Running 0 51m
+ manager-5bfbb96988-w9wnk 1/1 Running 0 51m
+ orchestrator-65d8fb4574-tnfx2 1/1 Running 0 51m
+ wrapper-astonishing-748b7dcc4f-ngsvp 1/1 Running 0 51m
+
+
+### Deploy or redeploy Moon only
+
+Kubernete shall be running.
+
+```bash
+cd $MOON_HOME
+sudo bash tools/moon_kubernetes/init_k8s_moon.sh moon
+```
+
+
+### Troubleshoot
+check *Consul* for:
+- *Components/Manager*, e.g.
+```json
+{
+ "port": 8082,
+ "bind": "0.0.0.0",
+ "hostname": "manager",
+ "container": "wukongsun/moon_manager:v4.3.1",
+ "external": {
+ "port": 30001,
+ "hostname": "$MOON_HOST"
+ }
+}
+```
+- *OpenStack/Keystone*: e.g.
+```json
+{
+ "url": "http://keystone:5000/v3",
+ "user": "admin",
+ "password": "p4ssw0rd",
+ "domain": "default",
+ "project": "admin",
+ "check_token": false,
+ "certificate": false,
+ "external": {
+ "url": "http://$MOON_HOST:30006/v3"
+ }
+}
+```
+
+
+### Docker-K8S Port Mapping
+```yamlex
+manager:
+ port: 8082
+ kport: 30001
+gui:
+ port: 3000
+ kport: 30002
+orchestrator:
+ port: 8083
+ kport: 30003
+consul:
+ port: 8500
+ kport: 30005
+keystone:
+ port: 5000
+ kport: 30006
+wrapper:
+ port: 8080
+ kport: 30010
+interface:
+ port: 8080
+authz:
+ port: 8081
+```
diff --git a/old/tools/moon_kubernetes/conf/moon.conf b/old/tools/moon_kubernetes/conf/moon.conf
new file mode 100644
index 00000000..5fc94edd
--- /dev/null
+++ b/old/tools/moon_kubernetes/conf/moon.conf
@@ -0,0 +1,90 @@
+database:
+ url: mysql+pymysql://moon:p4sswOrd1@db/moon
+ driver: sql
+
+openstack:
+ keystone:
+ url: http://keystone:5000/v3
+ user: admin
+ password: p4ssw0rd
+ domain: default
+ project: admin
+ check_token: false
+ certificate: false
+ external:
+ url: http://keystone:30006/v3
+
+components:
+ port_start:
+ 31001
+ pipeline:
+ interface:
+ port: 8080
+ bind: 0.0.0.0
+ hostname: interface
+ container: moonplatform/moon_interface:latest
+ authz:
+ port: 8081
+ bind: 0.0.0.0
+ hostname: interface
+ container: moonplatform/moon_authz:latest
+ session:
+ container: asteroide/session:latest
+ port: 8082
+ orchestrator:
+ port: 8083
+ bind: 0.0.0.0
+ hostname: orchestrator
+ container: moonplatform/moon_orchestrator:latest
+ external:
+ port: 30003
+ hostname: orchestrator
+ wrapper:
+ port: 8080
+ bind: 0.0.0.0
+ hostname: wrapper
+ container: moonplatform/moon_wrapper:latest
+ timeout: 5
+ manager:
+ port: 8082
+ bind: 0.0.0.0
+ hostname: manager
+ container: moonplatform/moon_manager:latest
+ external:
+ port: 30001
+ hostname: manager
+ port_start: 31001
+
+logging:
+ version: 1
+
+ formatters:
+ brief:
+ format: "%(levelname)s %(name)s %(message)-30s"
+ custom:
+ format: "%(asctime)-15s %(levelname)s %(name)s %(message)s"
+
+ handlers:
+ console:
+ class : logging.StreamHandler
+ formatter: custom
+ level : INFO
+ stream : ext://sys.stdout
+ file:
+ class : logging.handlers.RotatingFileHandler
+ formatter: custom
+ level : DEBUG
+ filename: /tmp/moon.log
+ maxBytes: 1048576
+ backupCount: 3
+
+ loggers:
+ moon:
+ level: DEBUG
+ handlers: [console, file]
+ propagate: no
+
+ root:
+ level: ERROR
+ handlers: [console]
+
diff --git a/old/tools/moon_kubernetes/conf/password_moon.txt b/old/tools/moon_kubernetes/conf/password_moon.txt
new file mode 100644
index 00000000..bb9bcf7d
--- /dev/null
+++ b/old/tools/moon_kubernetes/conf/password_moon.txt
@@ -0,0 +1 @@
+p4sswOrd1 \ No newline at end of file
diff --git a/old/tools/moon_kubernetes/conf/password_root.txt b/old/tools/moon_kubernetes/conf/password_root.txt
new file mode 100644
index 00000000..bb9bcf7d
--- /dev/null
+++ b/old/tools/moon_kubernetes/conf/password_root.txt
@@ -0,0 +1 @@
+p4sswOrd1 \ No newline at end of file
diff --git a/old/tools/moon_kubernetes/init_k8s_moon.sh b/old/tools/moon_kubernetes/init_k8s_moon.sh
new file mode 100644
index 00000000..0617de86
--- /dev/null
+++ b/old/tools/moon_kubernetes/init_k8s_moon.sh
@@ -0,0 +1,280 @@
+#!/bin/bash
+#number of pods type that should be running or be stopped
+declare -i pods_to_check=0
+ #global variable on current namespace to check
+current_namespace=""
+#if set to 1 we check that the pods are running, otherwise we chack that the pods are stopped
+declare -i check_running=1
+#name of the pod to check
+match_pattern=""
+#postfix used to recognize pods name
+OS="unknown_os"
+
+#this function checks if a pod with name starting with $1 is in the Running / Stopped state depending on $heck_running
+# $1 : the name the pods starts with (without the random string added by kubernate to the pod name)
+# $2 : either the number of identical pods that shall be run or #
+# $3 : if $2 is #, the number of lines of the pods name appear on which the pod appears
+function check_pod() {
+ declare -i nb_arguments=$#
+ match_pattern="$1"; shift
+ if [ $nb_arguments -gt 2 ]; then
+ shift; declare -i nb_pods_pattern="$1"
+ if [ $check_running -eq 1 ]; then #check if pods are running
+ declare -i result=$(sudo kubectl get po --namespace=${current_namespace} | grep $match_pattern | grep "1/1" | grep -c "Running")
+ if [ $result -eq $nb_pods_pattern ]; then
+ pods_to_check=$pods_to_check+1
+ fi
+ else #check if pods are stopped
+ declare -i result=$(sudo kubectl get po --namespace=${current_namespace} | grep $match_pattern | grep -c "Running\|Terminating")
+ if [ $result -eq 0 ]; then
+ pods_to_check=$pods_to_check+1
+ fi
+ fi
+ else
+ declare -i nb=$1
+ if [ $check_running -eq 1 ]; then #check if pods are running
+ declare -i result=$(sudo kubectl get po --namespace=${current_namespace} | grep $match_pattern | grep "$nb/$nb" | grep -c "Running")
+ if [ $result -eq 1 ]; then
+ pods_to_check=$pods_to_check+1
+ fi
+ else #check if pods are stopped
+ declare -i result=$(sudo kubectl get po --namespace=${current_namespace} | grep $match_pattern | grep -c "Running\|Terminating")
+ if [ $result -eq 0 ]; then
+ pods_to_check=$pods_to_check+1
+ fi
+ fi
+ fi
+}
+
+#this function tests a list of pods
+function check_pods() {
+ current_namespace="${1}"; shift
+ pods=("${@}")
+ declare -i pods_nb=${#pods[@]}
+ sleep 2
+ while [ $pods_to_check -lt $pods_nb ]
+ do
+ pods_to_check=0
+ for node in "${pods[@]}"
+ do
+ check_pod $node
+ done
+
+ if [ $check_running -eq 1 ]; then
+ echo -ne "$pods_to_check node types on $pods_nb are running...\033[0K\r"
+ else
+ declare -i running_pods=$pods_nb-$pods_to_check
+ echo -ne "$running_pods node types on $pods_nb are still running...\033[0K\r"
+ fi
+ sleep 2
+ done
+}
+
+#this function checks if a list of pods ($2) in a specific namspace ($1) are in the Running state
+function check_pods_running() {
+ check_running=1
+ check_pods "${@}"
+ pods_to_check=0
+}
+
+#this function checks if a list of pods ($2) are not in a specific namspace ($1)
+function check_pods_not_running() {
+ check_running=0
+ check_pods "${@}"
+ pods_to_check=0
+}
+
+function wait_for_kubernate_calico() {
+ echo -ne "Waiting for kubernate... "
+ kube_namespace="kube-system"
+ declare -a kube_pods=("calico-etcd 1" "calico-node 2" "calico-policy-controller 1" "etcd-${OS} 1" "kube-apiserver-${OS} 1" "kube-controller-manager-${OS} 1" "kube-dns 3" "kube-proxy 1" "kube-scheduler-${OS} 1")
+ check_pods_running "$kube_namespace" "${kube_pods[@]}"
+}
+
+function wait_for_moon_init() {
+ echo "Waiting for moon (consul, db, keystone) ..."
+ kube_namespace="moon"
+ declare -a kube_pods=("consul 1" "db 1" "keystone 1")
+ check_pods_running "$kube_namespace" "${kube_pods[@]}"
+}
+
+function wait_for_moon_forming() {
+ echo "Waiting for moon (forming) ..."
+ kube_namespace="moon"
+ declare -a kube_pods=("forming 1")
+ check_pods_running "$kube_namespace" "${kube_pods[@]}"
+}
+
+function wait_for_moon_manager() {
+ echo "Waiting for moon (manager) ..."
+ kube_namespace="moon"
+ declare -a kube_pods=("manager # 1")
+ check_pods_running "$kube_namespace" "${kube_pods[@]}"
+}
+
+function wait_for_moon_end() {
+ echo "Waiting for moon (orchestrator, gui) ..."
+ kube_namespace="moon"
+ declare -a kube_pods=("gui 1" "orchestrator 1")
+ check_pods_running "$kube_namespace" "${kube_pods[@]}"
+}
+
+function wait_for_moon_forming_to_end() {
+ echo "Waiting for moon forming to finish initialization. This can take few minutes..."
+ kube_namespace="moon"
+ declare -a kube_pods=("forming 1")
+ check_pods_not_running "$kube_namespace" "${kube_pods[@]}"
+}
+
+function wait_for_moon_delete_to_end(){
+ echo "Waiting for moon to terminate..."
+ kube_namespace="moon"
+ declare -a kube_pods=("consul 1" "db 1" "keystone 1" "manager # 3" "gui 1" "orchestrator 1")
+ check_pods_not_running "$kube_namespace" "${kube_pods[@]}"
+}
+
+function check_os(){
+ if [ -f /etc/os-release ]; then
+ # freedesktop.org and systemd
+ . /etc/os-release
+ OS=${ID}
+ elif type lsb_release >/dev/null 2>&1; then
+ # linuxbase.org
+ OS=$(lsb_release -si)
+ declare -i result=$(grep -i "debian" $OS)
+ if [ $result -eq 1 ]; then
+ OS="debian"
+ fi
+ declare -i result=$(grep -i "ubuntu" $OS)
+ if [ $result -eq 1 ]; then
+ OS="ubuntu"
+ fi
+ elif [ -f /etc/lsb-release ]; then
+ # For some versions of Debian/Ubuntu without lsb_release command
+ . /etc/lsb-release
+ OS=$DISTRIB_ID
+ declare -i result=$(grep -i "debian" $OS)
+ if [ $result -eq 1 ]; then
+ OS="debian"
+ fi
+ declare -i result=$(grep -i "ubuntu" $OS)
+ if [ $result -eq 1 ]; then
+ OS="ubuntu"
+ fi
+ elif [ -f /etc/debian_version ]; then
+ # Older Debian/Ubuntu/etc.
+ declare -i result=$(grep -i "debian" $OS)
+ if [ $result -eq 1 ]; then
+ OS="debian"
+ fi
+ declare -i result=$(grep -i "ubuntu" $OS)
+ if [ $result -eq 1 ]; then
+ OS="ubuntu"
+ fi
+ elif [ -f /etc/SuSe-release ]; then
+ # Older SuSE/etc.
+ echo "TO DO : get the name of the OS at the end of the pods name"
+ elif [ -f /etc/redhat-release ]; then
+ # Older Red Hat, CentOS, etc.
+ echo "TO DO : get the name of the OS at the end of the pods name"
+ else
+ # Fall back to uname, e.g. "Linux <version>", also works for BSD, etc.
+ OS=$(uname -s)
+ echo "TO DO : get the name of the OS at the end of the pods name"
+ fi
+ echo "postfix used to detect pods name : ${OS}"
+}
+
+declare -i nb_arguments=$#
+declare -i init_kubernate=1
+
+if [ $# -eq 1 ]; then
+ if [ $1 == "moon" ]; then
+ init_kubernate=0
+ fi
+
+ if [ $1 == "-h" ]; then
+ echo "Usage : "
+ echo " - 'bash tools/moon_kubernetes/init_k8s_moon.sh' launches the kubernates platform and the moon platform."
+ echo " - 'bash tools/moon_kubernetes/init_k8s_moon.sh moon' launches the moon platform only. If the moon platform is already launched, it deletes and recreates it."
+ echo " "
+ fi
+fi
+
+if [ $init_kubernate -eq 1 ]; then
+ check_os
+ echo "=============================="
+ echo "Launching kubernate "
+ echo "=============================="
+ sudo kubeadm reset
+ sudo swapoff -a
+ sudo kubeadm init --pod-network-cidr=192.168.0.0/16 # network for Calico
+ #sudo kubeadm init --pod-network-cidr=10.244.0.0/16 # network for Canal
+
+ mkdir -p $HOME/.kube
+ sudo cp -f /etc/kubernetes/admin.conf $HOME/.kube/config
+ sudo chown $(id -u):$(id -g) $HOME/.kube/config
+
+ kubectl apply -f http://docs.projectcalico.org/v2.4/getting-started/kubernetes/installation/hosted/kubeadm/1.6/calico.yaml
+ #kubectl apply -f https://raw.githubusercontent.com/projectcalico/canal/master/k8s-install/1.6/rbac.yaml
+ #kubectl apply -f https://raw.githubusercontent.com/projectcalico/canal/master/k8s-install/1.6/canal.yaml
+ #kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml
+
+ kubectl delete deployment kube-dns --namespace=kube-system
+ kubectl apply -f tools/moon_kubernetes/templates/kube-dns.yaml
+ kubectl taint nodes --all node-role.kubernetes.io/master- # malke the master also as a node
+
+ kubectl proxy&
+
+ wait_for_kubernate_calico
+
+ echo "=============================="
+ echo "Kubernate platform is ready ! "
+ echo "=============================="
+fi
+
+echo "============================"
+echo "Launching moon "
+echo "============================"
+#check if the moon platform is running, if so we terminate it
+declare -i moon_is_running=$(sudo kubectl get namespace | grep -c moon)
+if [ $moon_is_running -eq 1 ]; then
+ sudo kubectl delete namespace moon
+ wait_for_moon_delete_to_end
+ sleep 2
+fi
+
+#launching moon
+kubectl create namespace moon
+kubectl create configmap moon-config --from-file tools/moon_kubernetes/conf/moon.conf -n moon
+kubectl create configmap config --from-file ~/.kube/config -n moon
+kubectl create configmap moon-policy-templates --from-file tests/functional/scenario_tests -n moon
+kubectl create secret generic mysql-root-pass --from-file=tools/moon_kubernetes/conf/password_root.txt -n moon
+kubectl create secret generic mysql-pass --from-file=tools/moon_kubernetes/conf/password_moon.txt -n moon
+
+kubectl create -n moon -f tools/moon_kubernetes/templates/consul.yaml
+kubectl create -n moon -f tools/moon_kubernetes/templates/db.yaml
+kubectl create -n moon -f tools/moon_kubernetes/templates/keystone.yaml
+wait_for_moon_init
+
+
+kubectl create -n moon -f tools/moon_kubernetes/templates/moon_forming.yaml
+wait_for_moon_forming
+
+
+kubectl create -n moon -f tools/moon_kubernetes/templates/moon_manager.yaml
+wait_for_moon_manager
+
+
+kubectl create -n moon -f tools/moon_kubernetes/templates/moon_orchestrator.yaml
+kubectl create -n moon -f tools/moon_kubernetes/templates/moon_gui.yaml
+wait_for_moon_end
+
+#wait the end of pods initialization performed by moon forming
+wait_for_moon_forming_to_end
+
+echo "========================== "
+echo "Moon platform is ready !"
+echo "=========================="
+
+
diff --git a/old/tools/moon_kubernetes/templates/consul.yaml b/old/tools/moon_kubernetes/templates/consul.yaml
new file mode 100644
index 00000000..f0fb764e
--- /dev/null
+++ b/old/tools/moon_kubernetes/templates/consul.yaml
@@ -0,0 +1,33 @@
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+ namespace: moon
+ name: consul
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: consul
+ spec:
+ hostname: consul
+ containers:
+ - name: consul
+ image: consul:latest
+ ports:
+ - containerPort: 8500
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: consul
+ namespace: moon
+spec:
+ ports:
+ - port: 8500
+ targetPort: 8500
+ nodePort: 30005
+ selector:
+ app: consul
+ type: NodePort
diff --git a/old/tools/moon_kubernetes/templates/db.yaml b/old/tools/moon_kubernetes/templates/db.yaml
new file mode 100644
index 00000000..5a0e5e98
--- /dev/null
+++ b/old/tools/moon_kubernetes/templates/db.yaml
@@ -0,0 +1,55 @@
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+ namespace: moon
+ name: db
+spec:
+ replicas: 1
+ strategy:
+ type: Recreate
+ template:
+ metadata:
+ labels:
+ app: db
+ spec:
+ containers:
+ - name: db
+ image: mysql:5.7
+ env:
+ - name: MYSQL_DATABASE
+ value: "moon"
+ - name: MYSQL_USER
+ value: "moon"
+ - name: MYSQL_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: mysql-pass
+ key: password_moon.txt
+ - name: MYSQL_ROOT_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: mysql-root-pass
+ key: password_root.txt
+ ports:
+ - containerPort: 3306
+ name: mysql
+# volumeMounts:
+# - name: mysql-persistent-storage
+# mountPath: /var/lib/mysql
+# volumes:
+# - name: mysql-persistent-storage
+# persistentVolumeClaim:
+# claimName: mysql-pv-claim
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ namespace: moon
+ name: db
+spec:
+ ports:
+ - port: 3306
+ selector:
+ app: db
+--- \ No newline at end of file
diff --git a/old/tools/moon_kubernetes/templates/keystone.yaml b/old/tools/moon_kubernetes/templates/keystone.yaml
new file mode 100644
index 00000000..e4218e4c
--- /dev/null
+++ b/old/tools/moon_kubernetes/templates/keystone.yaml
@@ -0,0 +1,39 @@
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+ namespace: moon
+ name: keystone
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: keystone
+ spec:
+ hostname: keystone
+ containers:
+ - name: keystone
+ image: asteroide/keystone:pike-cors
+ env:
+ - name: KEYSTONE_HOSTNAME
+ value: "127.0.0.1"
+ - name: KEYSTONE_PORT
+ value: "30006"
+ ports:
+ - containerPort: 35357
+ containerPort: 5000
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: keystone
+ namespace: moon
+spec:
+ ports:
+ - port: 5000
+ targetPort: 5000
+ nodePort: 30006
+ selector:
+ app: keystone
+ type: NodePort
diff --git a/old/tools/moon_kubernetes/templates/kube-dns.yaml b/old/tools/moon_kubernetes/templates/kube-dns.yaml
new file mode 100644
index 00000000..c8f18fd8
--- /dev/null
+++ b/old/tools/moon_kubernetes/templates/kube-dns.yaml
@@ -0,0 +1,183 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ annotations:
+ deployment.kubernetes.io/revision: "2"
+ kubectl.kubernetes.io/last-applied-configuration: |
+ {"apiVersion":"extensions/v1beta1","kind":"Deployment","metadata":{"annotations":{"deployment.kubernetes.io/revision":"1"},"creationTimestamp":"2017-10-30T09:03:59Z","generation":1,"labels":{"k8s-app":"kube-dns"},"name":"kube-dns","namespace":"kube-system","resourceVersion":"556","selfLink":"/apis/extensions/v1beta1/namespaces/kube-system/deployments/kube-dns","uid":"4433b709-bd51-11e7-a055-80fa5b15034a"},"spec":{"replicas":1,"selector":{"matchLabels":{"k8s-app":"kube-dns"}},"strategy":{"rollingUpdate":{"maxSurge":"10%","maxUnavailable":0},"type":"RollingUpdate"},"template":{"metadata":{"creationTimestamp":null,"labels":{"k8s-app":"kube-dns"}},"spec":{"affinity":{"nodeAffinity":{"requiredDuringSchedulingIgnoredDuringExecution":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"beta.kubernetes.io/arch","operator":"In","values":["amd64"]}]}]}}},"containers":[{"args":["--domain=cluster.local.","--dns-port=10053","--config-dir=/kube-dns-config","--v=2"],"env":[{"name":"PROMETHEUS_PORT","value":"10055"}],"image":"gcr.io/google_containers/k8s-dns-kube-dns-amd64:1.14.5","imagePullPolicy":"IfNotPresent","livenessProbe":{"failureThreshold":5,"httpGet":{"path":"/healthcheck/kubedns","port":10054,"scheme":"HTTP"},"initialDelaySeconds":60,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"name":"kubedns","ports":[{"containerPort":10053,"name":"dns-local","protocol":"UDP"},{"containerPort":10053,"name":"dns-tcp-local","protocol":"TCP"},{"containerPort":10055,"name":"metrics","protocol":"TCP"}],"readinessProbe":{"failureThreshold":3,"httpGet":{"path":"/readiness","port":8081,"scheme":"HTTP"},"initialDelaySeconds":3,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"resources":{"limits":{"memory":"170Mi"},"requests":{"cpu":"100m","memory":"70Mi"}},"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","volumeMounts":[{"mountPath":"/kube-dns-config","name":"kube-dns-config"}]},{"args":["-v=2","-logtostderr","-configDir=/etc/k8s/dns/dnsmasq-nanny","-restartDnsmasq=true","--","-k","--cache-size=1000","--log-facility=-","--server=/cluster.local/127.0.0.1#10053","--server=/in-addr.arpa/127.0.0.1#10053","--server=/ip6.arpa/127.0.0.1#10053","--server=8.8.8.8"],"image":"gcr.io/google_containers/k8s-dns-dnsmasq-nanny-amd64:1.14.5","imagePullPolicy":"IfNotPresent","livenessProbe":{"failureThreshold":5,"httpGet":{"path":"/healthcheck/dnsmasq","port":10054,"scheme":"HTTP"},"initialDelaySeconds":60,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"name":"dnsmasq","ports":[{"containerPort":53,"name":"dns","protocol":"UDP"},{"containerPort":53,"name":"dns-tcp","protocol":"TCP"}],"resources":{"requests":{"cpu":"150m","memory":"20Mi"}},"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File","volumeMounts":[{"mountPath":"/etc/k8s/dns/dnsmasq-nanny","name":"kube-dns-config"}]},{"args":["--v=2","--logtostderr","--probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.cluster.local,5,A","--probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.cluster.local,5,A"],"image":"gcr.io/google_containers/k8s-dns-sidecar-amd64:1.14.5","imagePullPolicy":"IfNotPresent","livenessProbe":{"failureThreshold":5,"httpGet":{"path":"/metrics","port":10054,"scheme":"HTTP"},"initialDelaySeconds":60,"periodSeconds":10,"successThreshold":1,"timeoutSeconds":5},"name":"sidecar","ports":[{"containerPort":10054,"name":"metrics","protocol":"TCP"}],"resources":{"requests":{"cpu":"10m","memory":"20Mi"}},"terminationMessagePath":"/dev/termination-log","terminationMessagePolicy":"File"}],"dnsPolicy":"Default","restartPolicy":"Always","schedulerName":"default-scheduler","securityContext":{},"serviceAccount":"kube-dns","serviceAccountName":"kube-dns","terminationGracePeriodSeconds":30,"tolerations":[{"key":"CriticalAddonsOnly","operator":"Exists"},{"effect":"NoSchedule","key":"node-role.kubernetes.io/master"}],"volumes":[{"configMap":{"defaultMode":420,"name":"kube-dns","optional":true},"name":"kube-dns-config"}]}}},"status":{"availableReplicas":1,"conditions":[{"lastTransitionTime":"2017-10-30T09:05:11Z","lastUpdateTime":"2017-10-30T09:05:11Z","message":"Deployment has minimum availability.","reason":"MinimumReplicasAvailable","status":"True","type":"Available"}],"observedGeneration":1,"readyReplicas":1,"replicas":1,"updatedReplicas":1}}
+ creationTimestamp: 2017-10-30T09:03:59Z
+ generation: 2
+ labels:
+ k8s-app: kube-dns
+ name: kube-dns
+ namespace: kube-system
+ resourceVersion: "300076"
+ selfLink: /apis/extensions/v1beta1/namespaces/kube-system/deployments/kube-dns
+ uid: 4433b709-bd51-11e7-a055-80fa5b15034a
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ k8s-app: kube-dns
+ strategy:
+ rollingUpdate:
+ maxSurge: 10%
+ maxUnavailable: 0
+ type: RollingUpdate
+ template:
+ metadata:
+ creationTimestamp: null
+ labels:
+ k8s-app: kube-dns
+ spec:
+ affinity:
+ nodeAffinity:
+ requiredDuringSchedulingIgnoredDuringExecution:
+ nodeSelectorTerms:
+ - matchExpressions:
+ - key: beta.kubernetes.io/arch
+ operator: In
+ values:
+ - amd64
+ containers:
+ - args:
+ - --domain=cluster.local.
+ - --dns-port=10053
+ - --config-dir=/kube-dns-config
+ - --v=2
+ env:
+ - name: PROMETHEUS_PORT
+ value: "10055"
+ image: gcr.io/google_containers/k8s-dns-kube-dns-amd64:1.14.5
+ imagePullPolicy: IfNotPresent
+ livenessProbe:
+ failureThreshold: 5
+ httpGet:
+ path: /healthcheck/kubedns
+ port: 10054
+ scheme: HTTP
+ initialDelaySeconds: 60
+ periodSeconds: 10
+ successThreshold: 1
+ timeoutSeconds: 5
+ name: kubedns
+ ports:
+ - containerPort: 10053
+ name: dns-local
+ protocol: UDP
+ - containerPort: 10053
+ name: dns-tcp-local
+ protocol: TCP
+ - containerPort: 10055
+ name: metrics
+ protocol: TCP
+ readinessProbe:
+ failureThreshold: 3
+ httpGet:
+ path: /readiness
+ port: 8081
+ scheme: HTTP
+ initialDelaySeconds: 3
+ periodSeconds: 10
+ successThreshold: 1
+ timeoutSeconds: 5
+ resources:
+ limits:
+ memory: 340Mi
+ requests:
+ cpu: 200m
+ memory: 140Mi
+ terminationMessagePath: /dev/termination-log
+ terminationMessagePolicy: File
+ volumeMounts:
+ - mountPath: /kube-dns-config
+ name: kube-dns-config
+ - args:
+ - -v=2
+ - -logtostderr
+ - -configDir=/etc/k8s/dns/dnsmasq-nanny
+ - -restartDnsmasq=true
+ - --
+ - -k
+ - --dns-forward-max=300
+ - --cache-size=1000
+ - --log-facility=-
+ - --server=/cluster.local/127.0.0.1#10053
+ - --server=/in-addr.arpa/127.0.0.1#10053
+ - --server=/ip6.arpa/127.0.0.1#10053
+ - --server=8.8.8.8
+ image: gcr.io/google_containers/k8s-dns-dnsmasq-nanny-amd64:1.14.5
+ imagePullPolicy: IfNotPresent
+ livenessProbe:
+ failureThreshold: 5
+ httpGet:
+ path: /healthcheck/dnsmasq
+ port: 10054
+ scheme: HTTP
+ initialDelaySeconds: 60
+ periodSeconds: 10
+ successThreshold: 1
+ timeoutSeconds: 5
+ name: dnsmasq
+ ports:
+ - containerPort: 53
+ name: dns
+ protocol: UDP
+ - containerPort: 53
+ name: dns-tcp
+ protocol: TCP
+ resources:
+ requests:
+ cpu: 150m
+ memory: 20Mi
+ terminationMessagePath: /dev/termination-log
+ terminationMessagePolicy: File
+ volumeMounts:
+ - mountPath: /etc/k8s/dns/dnsmasq-nanny
+ name: kube-dns-config
+ - args:
+ - --v=2
+ - --logtostderr
+ - --probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.cluster.local,5,A
+ - --probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.cluster.local,5,A
+ image: gcr.io/google_containers/k8s-dns-sidecar-amd64:1.14.5
+ imagePullPolicy: IfNotPresent
+ livenessProbe:
+ failureThreshold: 5
+ httpGet:
+ path: /metrics
+ port: 10054
+ scheme: HTTP
+ initialDelaySeconds: 60
+ periodSeconds: 10
+ successThreshold: 1
+ timeoutSeconds: 5
+ name: sidecar
+ ports:
+ - containerPort: 10054
+ name: metrics
+ protocol: TCP
+ resources:
+ requests:
+ cpu: 10m
+ memory: 20Mi
+ terminationMessagePath: /dev/termination-log
+ terminationMessagePolicy: File
+ dnsPolicy: Default
+ restartPolicy: Always
+ schedulerName: default-scheduler
+ securityContext: {}
+ serviceAccount: kube-dns
+ serviceAccountName: kube-dns
+ terminationGracePeriodSeconds: 30
+ tolerations:
+ - key: CriticalAddonsOnly
+ operator: Exists
+ - effect: NoSchedule
+ key: node-role.kubernetes.io/master
+ volumes:
+ - configMap:
+ defaultMode: 420
+ name: kube-dns
+ optional: true
+ name: kube-dns-config
diff --git a/old/tools/moon_kubernetes/templates/moon_forming.yaml b/old/tools/moon_kubernetes/templates/moon_forming.yaml
new file mode 100644
index 00000000..1214a41a
--- /dev/null
+++ b/old/tools/moon_kubernetes/templates/moon_forming.yaml
@@ -0,0 +1,30 @@
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: forming
+ namespace: moon
+spec:
+ template:
+ metadata:
+ name: forming
+ spec:
+ containers:
+ - name: forming
+ image: moonplatform/moon_forming:latest
+ env:
+ - name: POPULATE_ARGS
+ value: "--verbose" # debug mode: --debug
+ volumeMounts:
+ - name: config-volume
+ mountPath: /etc/moon
+ - name: templates-volume
+ mountPath: /data
+ volumes:
+ - name: config-volume
+ configMap:
+ name: moon-config
+ - name: templates-volume
+ configMap:
+ name: moon-policy-templates
+ restartPolicy: Never
+ #backoffLimit: 4 \ No newline at end of file
diff --git a/old/tools/moon_kubernetes/templates/moon_functest.yaml b/old/tools/moon_kubernetes/templates/moon_functest.yaml
new file mode 100644
index 00000000..e876849e
--- /dev/null
+++ b/old/tools/moon_kubernetes/templates/moon_functest.yaml
@@ -0,0 +1,27 @@
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: functest
+ namespace: moon
+spec:
+ template:
+ metadata:
+ name: functest
+ spec:
+ containers:
+ - name: functest
+ image: moonplatform/moon_python_func_test:latest
+ volumeMounts:
+ - name: config-volume
+ mountPath: /etc/moon
+ - name: tests-volume
+ mountPath: /data
+ volumes:
+ - name: config-volume
+ configMap:
+ name: moon-config
+ - name: tests-volume
+ hostPath:
+ path: "{{PATH}}"
+ restartPolicy: Never
+ #backoffLimit: 4
diff --git a/old/tools/moon_kubernetes/templates/moon_gui.yaml b/old/tools/moon_kubernetes/templates/moon_gui.yaml
new file mode 100644
index 00000000..eca4267d
--- /dev/null
+++ b/old/tools/moon_kubernetes/templates/moon_gui.yaml
@@ -0,0 +1,42 @@
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+ namespace: moon
+ name: gui
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: gui
+ spec:
+ hostname: gui
+ containers:
+ - name: gui
+ image: moonplatform/moon_gui:latest
+ env:
+ - name: MANAGER_HOST
+ value: "127.0.0.1"
+ - name: MANAGER_PORT
+ value: "30001"
+ - name: KEYSTONE_HOST
+ value: "127.0.0.1"
+ - name: KEYSTONE_PORT
+ value: "30006"
+ ports:
+ - containerPort: 80
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: gui
+ namespace: moon
+spec:
+ ports:
+ - port: 80
+ targetPort: 80
+ nodePort: 30002
+ selector:
+ app: gui
+ type: NodePort
diff --git a/old/tools/moon_kubernetes/templates/moon_manager.yaml b/old/tools/moon_kubernetes/templates/moon_manager.yaml
new file mode 100644
index 00000000..8eb59482
--- /dev/null
+++ b/old/tools/moon_kubernetes/templates/moon_manager.yaml
@@ -0,0 +1,33 @@
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+ name: manager
+ namespace: moon
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: manager
+ spec:
+ hostname: manager
+ containers:
+ - name: manager
+ image: moonplatform/moon_manager:latest
+ ports:
+ - containerPort: 8082
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: manager
+ namespace: moon
+spec:
+ ports:
+ - port: 8082
+ targetPort: 8082
+ nodePort: 30001
+ selector:
+ app: manager
+ type: NodePort
diff --git a/old/tools/moon_kubernetes/templates/moon_orchestrator.yaml b/old/tools/moon_kubernetes/templates/moon_orchestrator.yaml
new file mode 100644
index 00000000..a4ae2bd9
--- /dev/null
+++ b/old/tools/moon_kubernetes/templates/moon_orchestrator.yaml
@@ -0,0 +1,40 @@
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+ namespace: moon
+ name: orchestrator
+spec:
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ app: orchestrator
+ spec:
+ hostname: orchestrator
+ containers:
+ - name: orchestrator
+ image: moonplatform/moon_orchestrator:latest
+ ports:
+ - containerPort: 8083
+ volumeMounts:
+ - name: config-volume
+ mountPath: /root/.kube
+ volumes:
+ - name: config-volume
+ configMap:
+ name: config
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: orchestrator
+ namespace: moon
+spec:
+ ports:
+ - port: 8083
+ targetPort: 8083
+ nodePort: 30003
+ selector:
+ app: orchestrator
+ type: NodePort
diff --git a/old/tools/openstack/README.md b/old/tools/openstack/README.md
new file mode 100644
index 00000000..8b5d06e5
--- /dev/null
+++ b/old/tools/openstack/README.md
@@ -0,0 +1,73 @@
+# OpenStack
+## Installation
+For the *Moon* platform, you must have the following OpenStack components installed somewhere:
+- *Nova*, see [Nova install](https://docs.openstack.org/mitaka/install-guide-ubuntu/nova-controller-install.html)
+- *Glance*, see [Glance install](https://docs.openstack.org/glance/pike/install/)
+- *Keystone* is automatically installed and configured in the Moon platform.
+After the Moon platform installation, the Keystone server will be available
+at: `http://localhost:30005 or http://\<servername\>:30005`
+
+You can also use your own Keystone server if you want.
+
+## Configuration
+Before updating the configuration of the OpenStack platform, check that the platform
+is working without Moon, use the following commands:
+```bash
+# set authentication
+openstack endpoint list
+openstack user list
+openstack server list
+```
+
+In order to connect the OpenStack platform with the Moon platform, you must update some
+configuration files in Nova and Glance:
+- `/etc/nova/policy.json`
+- `/etc/glance/policy.json`
+
+In some installed platform, the `/etc/nova/policy.json` can be absent so you have
+to create one. You can find example files in those directory:
+- `${MOON}/tools/openstack/nova/policy.json`
+- `${MOON}/tools/openstack/glance/policy.json`
+
+Each line is mapped to an OpenStack API interface, for example, the following line
+allows the user to get details for every virtual machines in the cloud
+(the corresponding shell command is `openstack server list`):
+
+ "os_compute_api:servers:detail": "",
+
+This lines indicates that there is no special authorisation to use this API,
+every users can use it. If you want that the Moon platform handles that authorisation,
+update this line with:
+
+ "os_compute_api:servers:detail": "http://my_hostname:31001/authz"
+
+1) by replacing `my_hostname` with the hostname (or the IP address) of the Moon platform.
+2) by updating the TCP port (default: 31001) with the good one.
+
+To find this TCP port, use the following command:
+
+ $ kubectl get services -n moon | grep wrapper | cut -d ":" -f 2 | cut -d " " -f 1
+ 31002/TCP
+
+## Tests
+Here is a shell script to authenticate to the OpenStack platform as `admin`:
+```bash
+export OS_USERNAME=admin
+export OS_PASSWORD=p4ssw0rd
+export OS_REGION_NAME=Orange
+export OS_TENANT_NAME=admin
+export OS_AUTH_URL=http://moon_hostname:30006/v3
+export OS_DOMAIN_NAME=Default
+export OS_IDENTITY_API_VERSION=3
+```
+
+For the `demo_user`, use:
+```bash
+export OS_USERNAME=demo_user
+export OS_PASSWORD=your_secret_password
+export OS_REGION_NAME=Orange
+export OS_TENANT_NAME=demo
+export OS_AUTH_URL=http://moon_hostname:30006/v3
+export OS_DOMAIN_NAME=Default
+export OS_IDENTITY_API_VERSION=3
+```
diff --git a/old/tools/openstack/glance/policy.json b/old/tools/openstack/glance/policy.json
new file mode 100644
index 00000000..5505f67f
--- /dev/null
+++ b/old/tools/openstack/glance/policy.json
@@ -0,0 +1,62 @@
+{
+ "context_is_admin": "role:admin",
+ "default": "role:admin",
+
+ "add_image": "http://my_hostname:31001/authz",
+ "delete_image": "http://my_hostname:31001/authz",
+ "get_image": "http://my_hostname:31001/authz",
+ "get_images": "http://my_hostname:31001/authz",
+ "modify_image": "http://my_hostname:31001/authz",
+ "publicize_image": "role:admin",
+ "communitize_image": "",
+ "copy_from": "",
+
+ "download_image": "",
+ "upload_image": "",
+
+ "delete_image_location": "",
+ "get_image_location": "",
+ "set_image_location": "",
+
+ "add_member": "",
+ "delete_member": "",
+ "get_member": "",
+ "get_members": "",
+ "modify_member": "",
+
+ "manage_image_cache": "role:admin",
+
+ "get_task": "role:admin",
+ "get_tasks": "role:admin",
+ "add_task": "role:admin",
+ "modify_task": "role:admin",
+
+ "deactivate": "",
+ "reactivate": "",
+
+ "get_metadef_namespace": "",
+ "get_metadef_namespaces":"",
+ "modify_metadef_namespace":"",
+ "add_metadef_namespace":"",
+
+ "get_metadef_object":"",
+ "get_metadef_objects":"",
+ "modify_metadef_object":"",
+ "add_metadef_object":"",
+
+ "list_metadef_resource_types":"",
+ "get_metadef_resource_type":"",
+ "add_metadef_resource_type_association":"",
+
+ "get_metadef_property":"",
+ "get_metadef_properties":"",
+ "modify_metadef_property":"",
+ "add_metadef_property":"",
+
+ "get_metadef_tag":"",
+ "get_metadef_tags":"",
+ "modify_metadef_tag":"",
+ "add_metadef_tag":"",
+ "add_metadef_tags":""
+
+}
diff --git a/old/tools/openstack/nova/policy.json b/old/tools/openstack/nova/policy.json
new file mode 100644
index 00000000..29763ce3
--- /dev/null
+++ b/old/tools/openstack/nova/policy.json
@@ -0,0 +1,488 @@
+{
+ "context_is_admin": "role:admin",
+ "admin_or_owner": "is_admin:True or project_id:%(project_id)s",
+ "default": "rule:admin_or_owner",
+
+ "cells_scheduler_filter:TargetCellFilter": "is_admin:True",
+
+ "compute:create": "http://my_hostname:31001/authz",
+ "compute:create:attach_network": "",
+ "compute:create:attach_volume": "",
+ "compute:create:forced_host": "is_admin:True",
+
+ "compute:get": "http://my_hostname:31001/authz",
+ "compute:get_all": "http://my_hostname:31001/authz",
+ "compute:get_all_tenants": "is_admin:True",
+
+ "compute:update": "",
+
+ "compute:get_instance_metadata": "",
+ "compute:get_all_instance_metadata": "",
+ "compute:get_all_instance_system_metadata": "",
+ "compute:update_instance_metadata": "",
+ "compute:delete_instance_metadata": "",
+
+ "compute:get_instance_faults": "",
+ "compute:get_diagnostics": "",
+ "compute:get_instance_diagnostics": "",
+
+ "compute:start": "rule:admin_or_owner",
+ "compute:stop": "rule:admin_or_owner",
+
+ "compute:get_lock": "",
+ "compute:lock": "rule:admin_or_owner",
+ "compute:unlock": "rule:admin_or_owner",
+ "compute:unlock_override": "rule:admin_api",
+
+ "compute:get_vnc_console": "",
+ "compute:get_spice_console": "",
+ "compute:get_rdp_console": "",
+ "compute:get_serial_console": "",
+ "compute:get_mks_console": "",
+ "compute:get_console_output": "",
+
+ "compute:reset_network": "",
+ "compute:inject_network_info": "",
+ "compute:add_fixed_ip": "",
+ "compute:remove_fixed_ip": "",
+
+ "compute:attach_volume": "",
+ "compute:detach_volume": "",
+ "compute:swap_volume": "",
+
+ "compute:attach_interface": "",
+ "compute:detach_interface": "",
+
+ "compute:set_admin_password": "",
+
+ "compute:rescue": "",
+ "compute:unrescue": "",
+
+ "compute:suspend": "",
+ "compute:resume": "",
+
+ "compute:pause": "",
+ "compute:unpause": "",
+
+ "compute:shelve": "",
+ "compute:shelve_offload": "",
+ "compute:unshelve": "",
+
+ "compute:snapshot": "",
+ "compute:snapshot_volume_backed": "",
+ "compute:backup": "",
+
+ "compute:resize": "",
+ "compute:confirm_resize": "",
+ "compute:revert_resize": "",
+
+ "compute:rebuild": "",
+ "compute:reboot": "",
+ "compute:delete": "rule:admin_or_owner",
+ "compute:soft_delete": "rule:admin_or_owner",
+ "compute:force_delete": "rule:admin_or_owner",
+
+ "compute:security_groups:add_to_instance": "",
+ "compute:security_groups:remove_from_instance": "",
+
+ "compute:delete": "",
+ "compute:soft_delete": "",
+ "compute:force_delete": "",
+ "compute:restore": "",
+
+ "compute:volume_snapshot_create": "",
+ "compute:volume_snapshot_delete": "",
+
+ "admin_api": "is_admin:True",
+ "compute_extension:accounts": "rule:admin_api",
+ "compute_extension:admin_actions": "rule:admin_api",
+ "compute_extension:admin_actions:pause": "rule:admin_or_owner",
+ "compute_extension:admin_actions:unpause": "rule:admin_or_owner",
+ "compute_extension:admin_actions:suspend": "rule:admin_or_owner",
+ "compute_extension:admin_actions:resume": "rule:admin_or_owner",
+ "compute_extension:admin_actions:lock": "rule:admin_or_owner",
+ "compute_extension:admin_actions:unlock": "rule:admin_or_owner",
+ "compute_extension:admin_actions:resetNetwork": "rule:admin_api",
+ "compute_extension:admin_actions:injectNetworkInfo": "rule:admin_api",
+ "compute_extension:admin_actions:createBackup": "rule:admin_or_owner",
+ "compute_extension:admin_actions:migrateLive": "rule:admin_api",
+ "compute_extension:admin_actions:resetState": "rule:admin_api",
+ "compute_extension:admin_actions:migrate": "rule:admin_api",
+ "compute_extension:aggregates": "rule:admin_api",
+ "compute_extension:agents": "rule:admin_api",
+ "compute_extension:attach_interfaces": "",
+ "compute_extension:baremetal_nodes": "rule:admin_api",
+ "compute_extension:cells": "rule:admin_api",
+ "compute_extension:cells:create": "rule:admin_api",
+ "compute_extension:cells:delete": "rule:admin_api",
+ "compute_extension:cells:update": "rule:admin_api",
+ "compute_extension:cells:sync_instances": "rule:admin_api",
+ "compute_extension:certificates": "",
+ "compute_extension:cloudpipe": "rule:admin_api",
+ "compute_extension:cloudpipe_update": "rule:admin_api",
+ "compute_extension:config_drive": "",
+ "compute_extension:console_output": "",
+ "compute_extension:consoles": "",
+ "compute_extension:createserverext": "",
+ "compute_extension:deferred_delete": "",
+ "compute_extension:disk_config": "",
+ "compute_extension:evacuate": "rule:admin_api",
+ "compute_extension:extended_server_attributes": "rule:admin_api",
+ "compute_extension:extended_status": "",
+ "compute_extension:extended_availability_zone": "",
+ "compute_extension:extended_ips": "",
+ "compute_extension:extended_ips_mac": "",
+ "compute_extension:extended_vif_net": "",
+ "compute_extension:extended_volumes": "",
+ "compute_extension:fixed_ips": "rule:admin_api",
+ "compute_extension:flavor_access": "",
+ "compute_extension:flavor_access:addTenantAccess": "rule:admin_api",
+ "compute_extension:flavor_access:removeTenantAccess": "rule:admin_api",
+ "compute_extension:flavor_disabled": "",
+ "compute_extension:flavor_rxtx": "",
+ "compute_extension:flavor_swap": "",
+ "compute_extension:flavorextradata": "",
+ "compute_extension:flavorextraspecs:index": "",
+ "compute_extension:flavorextraspecs:show": "",
+ "compute_extension:flavorextraspecs:create": "rule:admin_api",
+ "compute_extension:flavorextraspecs:update": "rule:admin_api",
+ "compute_extension:flavorextraspecs:delete": "rule:admin_api",
+ "compute_extension:flavormanage": "rule:admin_api",
+ "compute_extension:floating_ip_dns": "",
+ "compute_extension:floating_ip_pools": "",
+ "compute_extension:floating_ips": "",
+ "compute_extension:floating_ips_bulk": "rule:admin_api",
+ "compute_extension:fping": "",
+ "compute_extension:fping:all_tenants": "rule:admin_api",
+ "compute_extension:hide_server_addresses": "is_admin:False",
+ "compute_extension:hosts": "rule:admin_api",
+ "compute_extension:hypervisors": "rule:admin_api",
+ "compute_extension:image_size": "",
+ "compute_extension:instance_actions": "",
+ "compute_extension:instance_actions:events": "rule:admin_api",
+ "compute_extension:instance_usage_audit_log": "rule:admin_api",
+ "compute_extension:keypairs": "",
+ "compute_extension:keypairs:index": "",
+ "compute_extension:keypairs:show": "",
+ "compute_extension:keypairs:create": "",
+ "compute_extension:keypairs:delete": "",
+ "compute_extension:multinic": "",
+ "compute_extension:networks": "rule:admin_api",
+ "compute_extension:networks:view": "",
+ "compute_extension:networks_associate": "rule:admin_api",
+ "compute_extension:os-tenant-networks": "",
+ "compute_extension:quotas:show": "",
+ "compute_extension:quotas:update": "rule:admin_api",
+ "compute_extension:quotas:delete": "rule:admin_api",
+ "compute_extension:quota_classes": "",
+ "compute_extension:rescue": "",
+ "compute_extension:security_group_default_rules": "rule:admin_api",
+ "compute_extension:security_groups": "",
+ "compute_extension:server_diagnostics": "rule:admin_api",
+ "compute_extension:server_groups": "",
+ "compute_extension:server_password": "",
+ "compute_extension:server_usage": "",
+ "compute_extension:services": "rule:admin_api",
+ "compute_extension:shelve": "",
+ "compute_extension:shelveOffload": "rule:admin_api",
+ "compute_extension:simple_tenant_usage:show": "rule:admin_or_owner",
+ "compute_extension:simple_tenant_usage:list": "rule:admin_api",
+ "compute_extension:unshelve": "",
+ "compute_extension:users": "rule:admin_api",
+ "compute_extension:virtual_interfaces": "",
+ "compute_extension:virtual_storage_arrays": "",
+ "compute_extension:volumes": "",
+ "compute_extension:volume_attachments:index": "",
+ "compute_extension:volume_attachments:show": "",
+ "compute_extension:volume_attachments:create": "",
+ "compute_extension:volume_attachments:update": "",
+ "compute_extension:volume_attachments:delete": "",
+ "compute_extension:volumetypes": "",
+ "compute_extension:availability_zone:list": "",
+ "compute_extension:availability_zone:detail": "rule:admin_api",
+ "compute_extension:used_limits_for_admin": "rule:admin_api",
+ "compute_extension:migrations:index": "rule:admin_api",
+ "compute_extension:os-assisted-volume-snapshots:create": "rule:admin_api",
+ "compute_extension:os-assisted-volume-snapshots:delete": "rule:admin_api",
+ "compute_extension:console_auth_tokens": "rule:admin_api",
+ "compute_extension:os-server-external-events:create": "rule:admin_api",
+
+ "network:get_all": "",
+ "network:get": "",
+ "network:create": "",
+ "network:delete": "",
+ "network:associate": "",
+ "network:disassociate": "",
+ "network:get_vifs_by_instance": "",
+ "network:allocate_for_instance": "",
+ "network:deallocate_for_instance": "",
+ "network:validate_networks": "",
+ "network:get_instance_uuids_by_ip_filter": "",
+ "network:get_instance_id_by_floating_address": "",
+ "network:setup_networks_on_host": "",
+ "network:get_backdoor_port": "",
+
+ "network:get_floating_ip": "",
+ "network:get_floating_ip_pools": "",
+ "network:get_floating_ip_by_address": "",
+ "network:get_floating_ips_by_project": "",
+ "network:get_floating_ips_by_fixed_address": "",
+ "network:allocate_floating_ip": "",
+ "network:associate_floating_ip": "",
+ "network:disassociate_floating_ip": "",
+ "network:release_floating_ip": "",
+ "network:migrate_instance_start": "",
+ "network:migrate_instance_finish": "",
+
+ "network:get_fixed_ip": "",
+ "network:get_fixed_ip_by_address": "",
+ "network:add_fixed_ip_to_instance": "",
+ "network:remove_fixed_ip_from_instance": "",
+ "network:add_network_to_project": "",
+ "network:get_instance_nw_info": "",
+
+ "network:get_dns_domains": "",
+ "network:add_dns_entry": "",
+ "network:modify_dns_entry": "",
+ "network:delete_dns_entry": "",
+ "network:get_dns_entries_by_address": "",
+ "network:get_dns_entries_by_name": "",
+ "network:create_private_dns_domain": "",
+ "network:create_public_dns_domain": "",
+ "network:delete_dns_domain": "",
+ "network:attach_external_network": "rule:admin_api",
+ "network:get_vif_by_mac_address": "",
+
+ "os_compute_api:servers:detail:get_all_tenants": "is_admin:True",
+ "os_compute_api:servers:index:get_all_tenants": "is_admin:True",
+ "os_compute_api:servers:confirm_resize": "",
+ "os_compute_api:servers:create": "http://my_hostname:31001/authz",
+ "os_compute_api:servers:create:attach_network": "",
+ "os_compute_api:servers:create:attach_volume": "",
+ "os_compute_api:servers:create:forced_host": "rule:admin_api",
+ "os_compute_api:servers:delete": "http://my_hostname:31001/authz",
+ "os_compute_api:servers:update": "http://my_hostname:31001/authz",
+ "os_compute_api:servers:detail": "http://my_hostname:31001/authz",
+ "os_compute_api:servers:index": "http://my_hostname:31001/authz",
+ "os_compute_api:servers:reboot": "http://my_hostname:31001/authz",
+ "os_compute_api:servers:rebuild": "http://my_hostname:31001/authz",
+ "os_compute_api:servers:resize": "http://my_hostname:31001/authz",
+ "os_compute_api:servers:revert_resize": "http://my_hostname:31001/authz",
+ "os_compute_api:servers:show": "http://my_hostname:31001/authz",
+ "os_compute_api:servers:create_image": "",
+ "os_compute_api:servers:create_image:allow_volume_backed": "",
+ "os_compute_api:servers:start": "rule:admin_or_owner",
+ "os_compute_api:servers:stop": "rule:admin_or_owner",
+ "os_compute_api:os-access-ips:discoverable": "",
+ "os_compute_api:os-access-ips": "",
+ "os_compute_api:os-admin-actions": "rule:admin_api",
+ "os_compute_api:os-admin-actions:discoverable": "",
+ "os_compute_api:os-admin-actions:reset_network": "rule:admin_api",
+ "os_compute_api:os-admin-actions:inject_network_info": "rule:admin_api",
+ "os_compute_api:os-admin-actions:reset_state": "rule:admin_api",
+ "os_compute_api:os-admin-password": "",
+ "os_compute_api:os-admin-password:discoverable": "",
+ "os_compute_api:os-aggregates:discoverable": "",
+ "os_compute_api:os-aggregates:index": "rule:admin_api",
+ "os_compute_api:os-aggregates:create": "rule:admin_api",
+ "os_compute_api:os-aggregates:show": "rule:admin_api",
+ "os_compute_api:os-aggregates:update": "rule:admin_api",
+ "os_compute_api:os-aggregates:delete": "rule:admin_api",
+ "os_compute_api:os-aggregates:add_host": "rule:admin_api",
+ "os_compute_api:os-aggregates:remove_host": "rule:admin_api",
+ "os_compute_api:os-aggregates:set_metadata": "rule:admin_api",
+ "os_compute_api:os-agents": "rule:admin_api",
+ "os_compute_api:os-agents:discoverable": "",
+ "os_compute_api:os-attach-interfaces": "",
+ "os_compute_api:os-attach-interfaces:discoverable": "",
+ "os_compute_api:os-baremetal-nodes": "rule:admin_api",
+ "os_compute_api:os-baremetal-nodes:discoverable": "",
+ "os_compute_api:os-block-device-mapping-v1:discoverable": "",
+ "os_compute_api:os-cells": "rule:admin_api",
+ "os_compute_api:os-cells:create": "rule:admin_api",
+ "os_compute_api:os-cells:delete": "rule:admin_api",
+ "os_compute_api:os-cells:update": "rule:admin_api",
+ "os_compute_api:os-cells:sync_instances": "rule:admin_api",
+ "os_compute_api:os-cells:discoverable": "",
+ "os_compute_api:os-certificates:create": "",
+ "os_compute_api:os-certificates:show": "",
+ "os_compute_api:os-certificates:discoverable": "",
+ "os_compute_api:os-cloudpipe": "rule:admin_api",
+ "os_compute_api:os-cloudpipe:discoverable": "",
+ "os_compute_api:os-config-drive": "",
+ "os_compute_api:os-consoles:discoverable": "",
+ "os_compute_api:os-consoles:create": "",
+ "os_compute_api:os-consoles:delete": "",
+ "os_compute_api:os-consoles:index": "",
+ "os_compute_api:os-consoles:show": "",
+ "os_compute_api:os-console-output:discoverable": "",
+ "os_compute_api:os-console-output": "",
+ "os_compute_api:os-remote-consoles": "",
+ "os_compute_api:os-remote-consoles:discoverable": "",
+ "os_compute_api:os-create-backup:discoverable": "",
+ "os_compute_api:os-create-backup": "rule:admin_or_owner",
+ "os_compute_api:os-deferred-delete": "",
+ "os_compute_api:os-deferred-delete:discoverable": "",
+ "os_compute_api:os-disk-config": "",
+ "os_compute_api:os-disk-config:discoverable": "",
+ "os_compute_api:os-evacuate": "rule:admin_api",
+ "os_compute_api:os-evacuate:discoverable": "",
+ "os_compute_api:os-extended-server-attributes": "rule:admin_api",
+ "os_compute_api:os-extended-server-attributes:discoverable": "",
+ "os_compute_api:os-extended-status": "",
+ "os_compute_api:os-extended-status:discoverable": "",
+ "os_compute_api:os-extended-availability-zone": "",
+ "os_compute_api:os-extended-availability-zone:discoverable": "",
+ "os_compute_api:extensions": "",
+ "os_compute_api:extension_info:discoverable": "",
+ "os_compute_api:os-extended-volumes": "",
+ "os_compute_api:os-extended-volumes:discoverable": "",
+ "os_compute_api:os-fixed-ips": "rule:admin_api",
+ "os_compute_api:os-fixed-ips:discoverable": "",
+ "os_compute_api:os-flavor-access": "",
+ "os_compute_api:os-flavor-access:discoverable": "",
+ "os_compute_api:os-flavor-access:remove_tenant_access": "rule:admin_api",
+ "os_compute_api:os-flavor-access:add_tenant_access": "rule:admin_api",
+ "os_compute_api:os-flavor-rxtx": "",
+ "os_compute_api:os-flavor-rxtx:discoverable": "",
+ "os_compute_api:flavors:discoverable": "",
+ "os_compute_api:os-flavor-extra-specs:discoverable": "",
+ "os_compute_api:os-flavor-extra-specs:index": "",
+ "os_compute_api:os-flavor-extra-specs:show": "",
+ "os_compute_api:os-flavor-extra-specs:create": "rule:admin_api",
+ "os_compute_api:os-flavor-extra-specs:update": "rule:admin_api",
+ "os_compute_api:os-flavor-extra-specs:delete": "rule:admin_api",
+ "os_compute_api:os-flavor-manage:discoverable": "",
+ "os_compute_api:os-flavor-manage": "rule:admin_api",
+ "os_compute_api:os-floating-ip-dns": "",
+ "os_compute_api:os-floating-ip-dns:discoverable": "",
+ "os_compute_api:os-floating-ip-dns:domain:update": "rule:admin_api",
+ "os_compute_api:os-floating-ip-dns:domain:delete": "rule:admin_api",
+ "os_compute_api:os-floating-ip-pools": "",
+ "os_compute_api:os-floating-ip-pools:discoverable": "",
+ "os_compute_api:os-floating-ips": "",
+ "os_compute_api:os-floating-ips:discoverable": "",
+ "os_compute_api:os-floating-ips-bulk": "rule:admin_api",
+ "os_compute_api:os-floating-ips-bulk:discoverable": "",
+ "os_compute_api:os-fping": "",
+ "os_compute_api:os-fping:discoverable": "",
+ "os_compute_api:os-fping:all_tenants": "rule:admin_api",
+ "os_compute_api:os-hide-server-addresses": "is_admin:False",
+ "os_compute_api:os-hide-server-addresses:discoverable": "",
+ "os_compute_api:os-hosts": "rule:admin_api",
+ "os_compute_api:os-hosts:discoverable": "",
+ "os_compute_api:os-hypervisors": "rule:admin_api",
+ "os_compute_api:os-hypervisors:discoverable": "",
+ "os_compute_api:images:discoverable": "",
+ "os_compute_api:image-size": "",
+ "os_compute_api:image-size:discoverable": "",
+ "os_compute_api:os-instance-actions": "",
+ "os_compute_api:os-instance-actions:discoverable": "",
+ "os_compute_api:os-instance-actions:events": "rule:admin_api",
+ "os_compute_api:os-instance-usage-audit-log": "rule:admin_api",
+ "os_compute_api:os-instance-usage-audit-log:discoverable": "",
+ "os_compute_api:ips:discoverable": "",
+ "os_compute_api:ips:index": "rule:admin_or_owner",
+ "os_compute_api:ips:show": "rule:admin_or_owner",
+ "os_compute_api:os-keypairs:discoverable": "",
+ "os_compute_api:os-keypairs": "",
+ "os_compute_api:os-keypairs:index": "rule:admin_api or user_id:%(user_id)s",
+ "os_compute_api:os-keypairs:show": "rule:admin_api or user_id:%(user_id)s",
+ "os_compute_api:os-keypairs:create": "rule:admin_api or user_id:%(user_id)s",
+ "os_compute_api:os-keypairs:delete": "rule:admin_api or user_id:%(user_id)s",
+ "os_compute_api:limits:discoverable": "",
+ "os_compute_api:limits": "",
+ "os_compute_api:os-lock-server:discoverable": "",
+ "os_compute_api:os-lock-server:lock": "rule:admin_or_owner",
+ "os_compute_api:os-lock-server:unlock": "rule:admin_or_owner",
+ "os_compute_api:os-lock-server:unlock:unlock_override": "rule:admin_api",
+ "os_compute_api:os-migrate-server:discoverable": "",
+ "os_compute_api:os-migrate-server:migrate": "rule:admin_api",
+ "os_compute_api:os-migrate-server:migrate_live": "rule:admin_api",
+ "os_compute_api:os-multinic": "",
+ "os_compute_api:os-multinic:discoverable": "",
+ "os_compute_api:os-networks": "rule:admin_api",
+ "os_compute_api:os-networks:view": "",
+ "os_compute_api:os-networks:discoverable": "",
+ "os_compute_api:os-networks-associate": "rule:admin_api",
+ "os_compute_api:os-networks-associate:discoverable": "",
+ "os_compute_api:os-pause-server:discoverable": "",
+ "os_compute_api:os-pause-server:pause": "rule:admin_or_owner",
+ "os_compute_api:os-pause-server:unpause": "rule:admin_or_owner",
+ "os_compute_api:os-pci:pci_servers": "",
+ "os_compute_api:os-pci:discoverable": "",
+ "os_compute_api:os-pci:index": "rule:admin_api",
+ "os_compute_api:os-pci:detail": "rule:admin_api",
+ "os_compute_api:os-pci:show": "rule:admin_api",
+ "os_compute_api:os-personality:discoverable": "",
+ "os_compute_api:os-preserve-ephemeral-rebuild:discoverable": "",
+ "os_compute_api:os-quota-sets:discoverable": "",
+ "os_compute_api:os-quota-sets:show": "rule:admin_or_owner",
+ "os_compute_api:os-quota-sets:defaults": "",
+ "os_compute_api:os-quota-sets:update": "rule:admin_api",
+ "os_compute_api:os-quota-sets:delete": "rule:admin_api",
+ "os_compute_api:os-quota-sets:detail": "rule:admin_api",
+ "os_compute_api:os-quota-class-sets:update": "rule:admin_api",
+ "os_compute_api:os-quota-class-sets:show": "is_admin:True or quota_class:%(quota_class)s",
+ "os_compute_api:os-quota-class-sets:discoverable": "",
+ "os_compute_api:os-rescue": "",
+ "os_compute_api:os-rescue:discoverable": "",
+ "os_compute_api:os-scheduler-hints:discoverable": "",
+ "os_compute_api:os-security-group-default-rules:discoverable": "",
+ "os_compute_api:os-security-group-default-rules": "rule:admin_api",
+ "os_compute_api:os-security-groups": "",
+ "os_compute_api:os-security-groups:discoverable": "",
+ "os_compute_api:os-server-diagnostics": "rule:admin_api",
+ "os_compute_api:os-server-diagnostics:discoverable": "",
+ "os_compute_api:os-server-password": "",
+ "os_compute_api:os-server-password:discoverable": "",
+ "os_compute_api:os-server-usage": "",
+ "os_compute_api:os-server-usage:discoverable": "",
+ "os_compute_api:os-server-groups": "",
+ "os_compute_api:os-server-groups:discoverable": "",
+ "os_compute_api:os-services": "rule:admin_api",
+ "os_compute_api:os-services:discoverable": "",
+ "os_compute_api:server-metadata:discoverable": "",
+ "os_compute_api:server-metadata:index": "rule:admin_or_owner",
+ "os_compute_api:server-metadata:show": "rule:admin_or_owner",
+ "os_compute_api:server-metadata:delete": "rule:admin_or_owner",
+ "os_compute_api:server-metadata:create": "rule:admin_or_owner",
+ "os_compute_api:server-metadata:update": "rule:admin_or_owner",
+ "os_compute_api:server-metadata:update_all": "rule:admin_or_owner",
+ "os_compute_api:servers:discoverable": "",
+ "os_compute_api:os-shelve:shelve": "",
+ "os_compute_api:os-shelve:shelve:discoverable": "",
+ "os_compute_api:os-shelve:shelve_offload": "rule:admin_api",
+ "os_compute_api:os-simple-tenant-usage:discoverable": "",
+ "os_compute_api:os-simple-tenant-usage:show": "rule:admin_or_owner",
+ "os_compute_api:os-simple-tenant-usage:list": "rule:admin_api",
+ "os_compute_api:os-suspend-server:discoverable": "",
+ "os_compute_api:os-suspend-server:suspend": "rule:admin_or_owner",
+ "os_compute_api:os-suspend-server:resume": "rule:admin_or_owner",
+ "os_compute_api:os-tenant-networks": "rule:admin_or_owner",
+ "os_compute_api:os-tenant-networks:discoverable": "",
+ "os_compute_api:os-shelve:unshelve": "",
+ "os_compute_api:os-user-data:discoverable": "",
+ "os_compute_api:os-virtual-interfaces": "",
+ "os_compute_api:os-virtual-interfaces:discoverable": "",
+ "os_compute_api:os-volumes": "",
+ "os_compute_api:os-volumes:discoverable": "",
+ "os_compute_api:os-volumes-attachments:index": "",
+ "os_compute_api:os-volumes-attachments:show": "",
+ "os_compute_api:os-volumes-attachments:create": "",
+ "os_compute_api:os-volumes-attachments:update": "",
+ "os_compute_api:os-volumes-attachments:delete": "",
+ "os_compute_api:os-volumes-attachments:discoverable": "",
+ "os_compute_api:os-availability-zone:list": "",
+ "os_compute_api:os-availability-zone:discoverable": "",
+ "os_compute_api:os-availability-zone:detail": "rule:admin_api",
+ "os_compute_api:os-used-limits": "rule:admin_api",
+ "os_compute_api:os-used-limits:discoverable": "",
+ "os_compute_api:os-migrations:index": "rule:admin_api",
+ "os_compute_api:os-migrations:discoverable": "",
+ "os_compute_api:os-assisted-volume-snapshots:create": "rule:admin_api",
+ "os_compute_api:os-assisted-volume-snapshots:delete": "rule:admin_api",
+ "os_compute_api:os-assisted-volume-snapshots:discoverable": "",
+ "os_compute_api:os-console-auth-tokens": "rule:admin_api",
+ "os_compute_api:os-server-external-events:create": "rule:admin_api"
+}
diff --git a/old/tools/policies/generate_opst_policy.py b/old/tools/policies/generate_opst_policy.py
new file mode 100644
index 00000000..dd01d1c1
--- /dev/null
+++ b/old/tools/policies/generate_opst_policy.py
@@ -0,0 +1,167 @@
+import json
+import os
+import logging
+import argparse
+
+
+FILES = [
+ "cinder.policy.json",
+ "glance.policy.json",
+ "keystone.policy.json",
+ "neutron.policy.json",
+ "nova.policy.json",
+]
+policy = {
+ "pdps": [{
+ "name": "external_pdp",
+ "keystone_project_id": "",
+ "description": "",
+ "policies": [{"name": "OpenStack RBAC Policy"}]}
+ ],
+
+ "policies": [{
+ "name": "OpenStack RBAC Policy",
+ "genre": "authz",
+ "description": "A RBAC policy similar of what you can find through policy.json files",
+ "model": {"name": "OPST_RBAC"}, "mandatory": True, "override": True}
+ ],
+
+ "models": [{"name": "OPST_RBAC", "description": "", "meta_rules": [{"name": "rbac"}], "override": True}],
+
+ "subjects": [
+ {"name": "admin", "description": "", "extra": {}, "policies": [{"name": "OpenStack RBAC Policy"}]},
+ {"name": "demo", "description": "", "extra": {}, "policies": [{"name": "OpenStack RBAC Policy"}]}
+ ],
+
+ "subject_categories": [{"name": "role", "description": "a role in OpenStack"}],
+
+ "subject_data": [
+ {"name": "admin", "description": "the admin role", "policies": [], "category": {"name": "role"}},
+ {"name": "member", "description": "the member role", "policies": [], "category": {"name": "role"}}
+ ],
+
+ "subject_assignments": [
+ {"subject": {"name": "admin"}, "category": {"name": "role"}, "assignments": [{"name": "admin"}, {"name": "member"}]},
+ {"subject": {"name": "demo"}, "category": {"name": "role"}, "assignments": [{"name": "member"}]}
+ ],
+
+ "objects": [],
+
+ "object_categories": [{"name": "id", "description": "the UID of each virtual machine"}],
+
+ "object_data": [
+ {
+ "name": "all_vm",
+ "description": "represents all virtual machines in this project",
+ "policies": [],
+ "category": {"name": "id"}},
+ ],
+
+ "object_assignments": [],
+
+ "actions": [],
+
+ "action_categories": [{"name": "action_id", "description": ""}],
+
+ "action_data": [],
+
+ "action_assignments": [],
+
+ "meta_rules": [
+ {
+ "name": "rbac", "description": "",
+ "subject_categories": [{"name": "role"}],
+ "object_categories": [{"name": "id"}],
+ "action_categories": [{"name": "action_id"}]
+ }
+ ],
+
+ "rules": [],
+
+}
+logger = logging.getLogger(__name__)
+
+
+def init():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--verbose", '-v', action='store_true', help='verbose mode')
+ parser.add_argument("--debug", '-d', action='store_true', help='debug mode')
+ parser.add_argument("--dir", help='directory containing policy files', default="./policy.json.d")
+ parser.add_argument("--indent", '-i', help='indent the output (default:None)', type=int, default=None)
+ parser.add_argument("--output", '-o', help='output name', type=str, default="opst_default_policy.json")
+ args = parser.parse_args()
+ logging_format = "%(levelname)s: %(message)s"
+ if args.verbose:
+ logging.basicConfig(level=logging.INFO, format=logging_format)
+ if args.debug:
+ logging.basicConfig(level=logging.DEBUG, format=logging_format)
+ else:
+ logging.basicConfig(format=logging_format)
+ return args
+
+
+def get_rules(args):
+ results = {}
+ for f in FILES:
+ _json_file = json.loads(open(os.path.join(args.dir, f)).read())
+ keys = list(_json_file.keys())
+ values = list(_json_file.values())
+ for value in values:
+ if value in keys:
+ keys.remove(value)
+ component = os.path.basename(f).split(".")[0]
+ results[component] = keys
+ return results
+
+
+def build_dict(results):
+ for key in results:
+ for rule in results[key]:
+ _output = {
+ "name": rule,
+ "description": "{} action for {}".format(rule, key),
+ "extra": {"component": key},
+ "policies": []
+ }
+ policy['actions'].append(_output)
+ _output = {
+ "name": rule,
+ "description": "{} action for {}".format(rule, key),
+ "policies": [],
+ "category": {"name": "action_id"}
+ }
+ policy['action_data'].append(_output)
+ _output = {
+ "action": {"name": rule},
+ "category": {"name": "action_id"},
+ "assignments": [{"name": rule}, ]}
+ policy['action_assignments'].append(_output)
+ _output = {
+ "meta_rule": {"name": "rbac"},
+ "rule": {
+ "subject_data": [{"name": "admin"}],
+ "object_data": [{"name": "all_vm"}],
+ "action_data": [{"name": rule}]
+ },
+ "policy": {"name": "OpenStack RBAC Policy"},
+ "instructions": {"decision": "grant"},
+ "enabled": True
+ }
+ policy['rules'].append(_output)
+ # TODO: add rules for member only
+ # TODO: add rules for everyone
+
+
+def write_dict(args):
+ json.dump(policy, open(args.output, "w"), indent=args.indent)
+
+
+def main():
+ args = init()
+ rules = get_rules(args)
+ build_dict(rules)
+ write_dict(args)
+
+
+if __name__ == "__main__":
+ main() \ No newline at end of file
diff --git a/old/tools/policies/policy.json.d/cinder.policy.json b/old/tools/policies/policy.json.d/cinder.policy.json
new file mode 100644
index 00000000..02af88bd
--- /dev/null
+++ b/old/tools/policies/policy.json.d/cinder.policy.json
@@ -0,0 +1,104 @@
+{
+ "context_is_admin": "role:admin",
+ "admin_or_owner": "is_admin:True or project_id:%(project_id)s",
+ "default": "rule:admin_or_owner",
+
+ "admin_api": "is_admin:True",
+
+ "volume:create": "",
+ "volume:delete": "rule:admin_or_owner",
+ "volume:get": "rule:admin_or_owner",
+ "volume:get_all": "rule:admin_or_owner",
+ "volume:get_volume_metadata": "rule:admin_or_owner",
+ "volume:delete_volume_metadata": "rule:admin_or_owner",
+ "volume:update_volume_metadata": "rule:admin_or_owner",
+ "volume:get_volume_admin_metadata": "rule:admin_api",
+ "volume:update_volume_admin_metadata": "rule:admin_api",
+ "volume:get_snapshot": "rule:admin_or_owner",
+ "volume:get_all_snapshots": "rule:admin_or_owner",
+ "volume:create_snapshot": "rule:admin_or_owner",
+ "volume:delete_snapshot": "rule:admin_or_owner",
+ "volume:update_snapshot": "rule:admin_or_owner",
+ "volume:extend": "rule:admin_or_owner",
+ "volume:update_readonly_flag": "rule:admin_or_owner",
+ "volume:retype": "rule:admin_or_owner",
+ "volume:update": "rule:admin_or_owner",
+
+ "volume_extension:types_manage": "rule:admin_api",
+ "volume_extension:types_extra_specs": "rule:admin_api",
+ "volume_extension:access_types_qos_specs_id": "rule:admin_api",
+ "volume_extension:access_types_extra_specs": "rule:admin_api",
+ "volume_extension:volume_type_access": "rule:admin_or_owner",
+ "volume_extension:volume_type_access:addProjectAccess": "rule:admin_api",
+ "volume_extension:volume_type_access:removeProjectAccess": "rule:admin_api",
+ "volume_extension:volume_type_encryption": "rule:admin_api",
+ "volume_extension:volume_encryption_metadata": "rule:admin_or_owner",
+ "volume_extension:extended_snapshot_attributes": "rule:admin_or_owner",
+ "volume_extension:volume_image_metadata": "rule:admin_or_owner",
+
+ "volume_extension:quotas:show": "",
+ "volume_extension:quotas:update": "rule:admin_api",
+ "volume_extension:quotas:delete": "rule:admin_api",
+ "volume_extension:quota_classes": "rule:admin_api",
+ "volume_extension:quota_classes:validate_setup_for_nested_quota_use": "rule:admin_api",
+
+ "volume_extension:volume_admin_actions:reset_status": "rule:admin_api",
+ "volume_extension:snapshot_admin_actions:reset_status": "rule:admin_api",
+ "volume_extension:backup_admin_actions:reset_status": "rule:admin_api",
+ "volume_extension:volume_admin_actions:force_delete": "rule:admin_api",
+ "volume_extension:volume_admin_actions:force_detach": "rule:admin_api",
+ "volume_extension:snapshot_admin_actions:force_delete": "rule:admin_api",
+ "volume_extension:backup_admin_actions:force_delete": "rule:admin_api",
+ "volume_extension:volume_admin_actions:migrate_volume": "rule:admin_api",
+ "volume_extension:volume_admin_actions:migrate_volume_completion": "rule:admin_api",
+
+ "volume_extension:volume_host_attribute": "rule:admin_api",
+ "volume_extension:volume_tenant_attribute": "rule:admin_or_owner",
+ "volume_extension:volume_mig_status_attribute": "rule:admin_api",
+ "volume_extension:hosts": "rule:admin_api",
+ "volume_extension:services:index": "rule:admin_api",
+ "volume_extension:services:update" : "rule:admin_api",
+
+ "volume_extension:volume_manage": "rule:admin_api",
+ "volume_extension:volume_unmanage": "rule:admin_api",
+
+ "volume_extension:capabilities": "rule:admin_api",
+
+ "volume:create_transfer": "rule:admin_or_owner",
+ "volume:accept_transfer": "",
+ "volume:delete_transfer": "rule:admin_or_owner",
+ "volume:get_all_transfers": "rule:admin_or_owner",
+
+ "volume_extension:replication:promote": "rule:admin_api",
+ "volume_extension:replication:reenable": "rule:admin_api",
+
+ "volume:enable_replication": "rule:admin_api",
+ "volume:disable_replication": "rule:admin_api",
+ "volume:failover_replication": "rule:admin_api",
+ "volume:list_replication_targets": "rule:admin_api",
+
+ "backup:create" : "",
+ "backup:delete": "rule:admin_or_owner",
+ "backup:get": "rule:admin_or_owner",
+ "backup:get_all": "rule:admin_or_owner",
+ "backup:restore": "rule:admin_or_owner",
+ "backup:backup-import": "rule:admin_api",
+ "backup:backup-export": "rule:admin_api",
+
+ "snapshot_extension:snapshot_actions:update_snapshot_status": "",
+ "snapshot_extension:snapshot_manage": "rule:admin_api",
+ "snapshot_extension:snapshot_unmanage": "rule:admin_api",
+
+ "consistencygroup:create" : "group:nobody",
+ "consistencygroup:delete": "group:nobody",
+ "consistencygroup:update": "group:nobody",
+ "consistencygroup:get": "group:nobody",
+ "consistencygroup:get_all": "group:nobody",
+
+ "consistencygroup:create_cgsnapshot" : "group:nobody",
+ "consistencygroup:delete_cgsnapshot": "group:nobody",
+ "consistencygroup:get_cgsnapshot": "group:nobody",
+ "consistencygroup:get_all_cgsnapshots": "group:nobody",
+
+ "scheduler_extension:scheduler_stats:get_pools" : "rule:admin_api"
+}
diff --git a/old/tools/policies/policy.json.d/glance.policy.json b/old/tools/policies/policy.json.d/glance.policy.json
new file mode 100644
index 00000000..5b1f6be7
--- /dev/null
+++ b/old/tools/policies/policy.json.d/glance.policy.json
@@ -0,0 +1,63 @@
+{
+ "context_is_admin": "role:admin",
+ "default": "role:admin",
+
+ "add_image": "",
+ "delete_image": "",
+ "get_image": "",
+ "get_images": "",
+ "modify_image": "",
+ "publicize_image": "role:admin",
+ "communitize_image": "",
+ "copy_from": "",
+
+ "download_image": "",
+ "upload_image": "",
+
+ "delete_image_location": "",
+ "get_image_location": "",
+ "set_image_location": "",
+
+ "add_member": "",
+ "delete_member": "",
+ "get_member": "",
+ "get_members": "",
+ "modify_member": "",
+
+ "manage_image_cache": "role:admin",
+
+ "get_task": "",
+ "get_tasks": "",
+ "add_task": "",
+ "modify_task": "",
+ "tasks_api_access": "role:admin",
+
+ "deactivate": "",
+ "reactivate": "",
+
+ "get_metadef_namespace": "",
+ "get_metadef_namespaces":"",
+ "modify_metadef_namespace":"",
+ "add_metadef_namespace":"",
+
+ "get_metadef_object":"",
+ "get_metadef_objects":"",
+ "modify_metadef_object":"",
+ "add_metadef_object":"",
+
+ "list_metadef_resource_types":"",
+ "get_metadef_resource_type":"",
+ "add_metadef_resource_type_association":"",
+
+ "get_metadef_property":"",
+ "get_metadef_properties":"",
+ "modify_metadef_property":"",
+ "add_metadef_property":"",
+
+ "get_metadef_tag":"",
+ "get_metadef_tags":"",
+ "modify_metadef_tag":"",
+ "add_metadef_tag":"",
+ "add_metadef_tags":""
+
+}
diff --git a/old/tools/policies/policy.json.d/keystone.policy.json b/old/tools/policies/policy.json.d/keystone.policy.json
new file mode 100644
index 00000000..263912bf
--- /dev/null
+++ b/old/tools/policies/policy.json.d/keystone.policy.json
@@ -0,0 +1,260 @@
+{
+ "admin_required": "role:admin",
+ "cloud_admin": "role:admin and (is_admin_project:True or domain_id:admin_domain_id)",
+ "service_role": "role:service",
+ "service_or_admin": "rule:admin_required or rule:service_role",
+ "owner": "user_id:%(user_id)s or user_id:%(target.token.user_id)s",
+ "admin_or_owner": "(rule:admin_required and domain_id:%(target.token.user.domain.id)s) or rule:owner",
+ "admin_and_matching_domain_id": "rule:admin_required and domain_id:%(domain_id)s",
+ "service_admin_or_owner": "rule:service_or_admin or rule:owner",
+
+ "default": "rule:admin_required",
+
+ "identity:get_region": "",
+ "identity:list_regions": "",
+ "identity:create_region": "rule:cloud_admin",
+ "identity:update_region": "rule:cloud_admin",
+ "identity:delete_region": "rule:cloud_admin",
+
+ "identity:get_service": "rule:admin_required",
+ "identity:list_services": "rule:admin_required",
+ "identity:create_service": "rule:cloud_admin",
+ "identity:update_service": "rule:cloud_admin",
+ "identity:delete_service": "rule:cloud_admin",
+
+ "identity:get_endpoint": "rule:admin_required",
+ "identity:list_endpoints": "rule:admin_required",
+ "identity:create_endpoint": "rule:cloud_admin",
+ "identity:update_endpoint": "rule:cloud_admin",
+ "identity:delete_endpoint": "rule:cloud_admin",
+
+ "identity:get_registered_limit": "",
+ "identity:list_registered_limits": "",
+ "identity:create_registered_limits": "rule:admin_required",
+ "identity:update_registered_limits": "rule:admin_required",
+ "identity:delete_registered_limit": "rule:admin_required",
+
+ "identity:get_limit": "",
+ "identity:list_limits": "",
+ "identity:create_limits": "rule:admin_required",
+ "identity:update_limits": "rule:admin_required",
+ "identity:delete_limit": "rule:admin_required",
+
+ "identity:get_domain": "rule:cloud_admin or rule:admin_and_matching_domain_id or token.project.domain.id:%(target.domain.id)s",
+ "identity:list_domains": "rule:cloud_admin",
+ "identity:create_domain": "rule:cloud_admin",
+ "identity:update_domain": "rule:cloud_admin",
+ "identity:delete_domain": "rule:cloud_admin",
+
+ "admin_and_matching_target_project_domain_id": "rule:admin_required and domain_id:%(target.project.domain_id)s",
+ "admin_and_matching_project_domain_id": "rule:admin_required and domain_id:%(project.domain_id)s",
+ "identity:get_project": "rule:cloud_admin or rule:admin_and_matching_target_project_domain_id or project_id:%(target.project.id)s",
+ "identity:list_projects": "rule:cloud_admin or rule:admin_and_matching_domain_id",
+ "identity:list_user_projects": "rule:owner or rule:admin_and_matching_domain_id",
+ "identity:create_project": "rule:cloud_admin or rule:admin_and_matching_project_domain_id",
+ "identity:update_project": "rule:cloud_admin or rule:admin_and_matching_target_project_domain_id",
+ "identity:delete_project": "rule:cloud_admin or rule:admin_and_matching_target_project_domain_id",
+ "identity:create_project_tag": "rule:admin_required",
+ "identity:delete_project_tag": "rule:admin_required",
+ "identity:get_project_tag": "rule:admin_required",
+ "identity:list_project_tags": "rule:admin_required",
+ "identity:delete_project_tags": "rule:admin_required",
+ "identity:update_project_tags": "rule:admin_required",
+
+ "admin_and_matching_target_user_domain_id": "rule:admin_required and domain_id:%(target.user.domain_id)s",
+ "admin_and_matching_user_domain_id": "rule:admin_required and domain_id:%(user.domain_id)s",
+ "identity:get_user": "rule:cloud_admin or rule:admin_and_matching_target_user_domain_id or rule:owner",
+ "identity:list_users": "rule:cloud_admin or rule:admin_and_matching_domain_id",
+ "identity:create_user": "rule:cloud_admin or rule:admin_and_matching_user_domain_id",
+ "identity:update_user": "rule:cloud_admin or rule:admin_and_matching_target_user_domain_id",
+ "identity:delete_user": "rule:cloud_admin or rule:admin_and_matching_target_user_domain_id",
+
+ "admin_and_matching_target_group_domain_id": "rule:admin_required and domain_id:%(target.group.domain_id)s",
+ "admin_and_matching_group_domain_id": "rule:admin_required and domain_id:%(group.domain_id)s",
+ "identity:get_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+ "identity:list_groups": "rule:cloud_admin or rule:admin_and_matching_domain_id",
+ "identity:list_groups_for_user": "rule:owner or rule:admin_and_matching_target_user_domain_id",
+ "identity:create_group": "rule:cloud_admin or rule:admin_and_matching_group_domain_id",
+ "identity:update_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+ "identity:delete_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+ "identity:list_users_in_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+ "identity:remove_user_from_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+ "identity:check_user_in_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+ "identity:add_user_to_group": "rule:cloud_admin or rule:admin_and_matching_target_group_domain_id",
+
+ "identity:get_credential": "rule:admin_required",
+ "identity:list_credentials": "rule:admin_required or user_id:%(user_id)s",
+ "identity:create_credential": "rule:admin_required",
+ "identity:update_credential": "rule:admin_required",
+ "identity:delete_credential": "rule:admin_required",
+
+ "identity:ec2_get_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)",
+ "identity:ec2_list_credentials": "rule:admin_required or rule:owner",
+ "identity:ec2_create_credential": "rule:admin_required or rule:owner",
+ "identity:ec2_delete_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)",
+
+ "identity:get_role": "rule:admin_required",
+ "identity:list_roles": "rule:admin_required",
+ "identity:create_role": "rule:cloud_admin",
+ "identity:update_role": "rule:cloud_admin",
+ "identity:delete_role": "rule:cloud_admin",
+
+ "identity:get_domain_role": "rule:cloud_admin or rule:get_domain_roles",
+ "identity:list_domain_roles": "rule:cloud_admin or rule:list_domain_roles",
+ "identity:create_domain_role": "rule:cloud_admin or rule:domain_admin_matches_domain_role",
+ "identity:update_domain_role": "rule:cloud_admin or rule:domain_admin_matches_target_domain_role",
+ "identity:delete_domain_role": "rule:cloud_admin or rule:domain_admin_matches_target_domain_role",
+ "domain_admin_matches_domain_role": "rule:admin_required and domain_id:%(role.domain_id)s",
+ "get_domain_roles": "rule:domain_admin_matches_target_domain_role or rule:project_admin_matches_target_domain_role",
+ "domain_admin_matches_target_domain_role": "rule:admin_required and domain_id:%(target.role.domain_id)s",
+ "project_admin_matches_target_domain_role": "rule:admin_required and project_domain_id:%(target.role.domain_id)s",
+ "list_domain_roles": "rule:domain_admin_matches_filter_on_list_domain_roles or rule:project_admin_matches_filter_on_list_domain_roles",
+ "domain_admin_matches_filter_on_list_domain_roles": "rule:admin_required and domain_id:%(domain_id)s",
+ "project_admin_matches_filter_on_list_domain_roles": "rule:admin_required and project_domain_id:%(domain_id)s",
+ "admin_and_matching_prior_role_domain_id": "rule:admin_required and domain_id:%(target.prior_role.domain_id)s",
+ "implied_role_matches_prior_role_domain_or_global": "(domain_id:%(target.implied_role.domain_id)s or None:%(target.implied_role.domain_id)s)",
+
+ "identity:get_implied_role": "rule:cloud_admin or rule:admin_and_matching_prior_role_domain_id",
+ "identity:list_implied_roles": "rule:cloud_admin or rule:admin_and_matching_prior_role_domain_id",
+ "identity:create_implied_role": "rule:cloud_admin or (rule:admin_and_matching_prior_role_domain_id and rule:implied_role_matches_prior_role_domain_or_global)",
+ "identity:delete_implied_role": "rule:cloud_admin or rule:admin_and_matching_prior_role_domain_id",
+ "identity:list_role_inference_rules": "rule:cloud_admin",
+ "identity:check_implied_role": "rule:cloud_admin or rule:admin_and_matching_prior_role_domain_id",
+
+ "identity:list_system_grants_for_user": "rule:admin_required",
+ "identity:check_system_grant_for_user": "rule:admin_required",
+ "identity:create_system_grant_for_user": "rule:admin_required",
+ "identity:revoke_system_grant_for_user": "rule:admin_required",
+
+ "identity:list_system_grants_for_group": "rule:admin_required",
+ "identity:check_system_grant_for_group": "rule:admin_required",
+ "identity:create_system_grant_for_group": "rule:admin_required",
+ "identity:revoke_system_grant_for_group": "rule:admin_required",
+
+ "identity:check_grant": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants",
+ "identity:list_grants": "rule:cloud_admin or rule:domain_admin_for_list_grants or rule:project_admin_for_list_grants",
+ "identity:create_grant": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants",
+ "identity:revoke_grant": "rule:cloud_admin or rule:domain_admin_for_grants or rule:project_admin_for_grants",
+ "domain_admin_for_grants": "rule:domain_admin_for_global_role_grants or rule:domain_admin_for_domain_role_grants",
+ "domain_admin_for_global_role_grants": "rule:admin_required and None:%(target.role.domain_id)s and rule:domain_admin_grant_match",
+ "domain_admin_for_domain_role_grants": "rule:admin_required and domain_id:%(target.role.domain_id)s and rule:domain_admin_grant_match",
+ "domain_admin_grant_match": "domain_id:%(domain_id)s or domain_id:%(target.project.domain_id)s",
+ "project_admin_for_grants": "rule:project_admin_for_global_role_grants or rule:project_admin_for_domain_role_grants",
+ "project_admin_for_global_role_grants": "rule:admin_required and None:%(target.role.domain_id)s and project_id:%(project_id)s",
+ "project_admin_for_domain_role_grants": "rule:admin_required and project_domain_id:%(target.role.domain_id)s and project_id:%(project_id)s",
+ "domain_admin_for_list_grants": "rule:admin_required and rule:domain_admin_grant_match",
+ "project_admin_for_list_grants": "rule:admin_required and project_id:%(project_id)s",
+
+ "admin_on_domain_filter": "rule:admin_required and domain_id:%(scope.domain.id)s",
+ "admin_on_project_filter": "rule:admin_required and project_id:%(scope.project.id)s",
+ "admin_on_domain_of_project_filter": "rule:admin_required and domain_id:%(target.project.domain_id)s",
+ "identity:list_role_assignments": "rule:cloud_admin or rule:admin_on_domain_filter or rule:admin_on_project_filter",
+ "identity:list_role_assignments_for_tree": "rule:cloud_admin or rule:admin_on_domain_of_project_filter",
+ "identity:get_policy": "rule:cloud_admin",
+ "identity:list_policies": "rule:cloud_admin",
+ "identity:create_policy": "rule:cloud_admin",
+ "identity:update_policy": "rule:cloud_admin",
+ "identity:delete_policy": "rule:cloud_admin",
+
+ "identity:check_token": "rule:admin_or_owner",
+ "identity:validate_token": "rule:service_admin_or_owner",
+ "identity:validate_token_head": "rule:service_or_admin",
+ "identity:revocation_list": "rule:service_or_admin",
+ "identity:revoke_token": "rule:admin_or_owner",
+
+ "identity:create_trust": "user_id:%(trust.trustor_user_id)s",
+ "identity:list_trusts": "",
+ "identity:list_roles_for_trust": "",
+ "identity:get_role_for_trust": "",
+ "identity:delete_trust": "",
+ "identity:get_trust": "",
+
+ "identity:create_consumer": "rule:admin_required",
+ "identity:get_consumer": "rule:admin_required",
+ "identity:list_consumers": "rule:admin_required",
+ "identity:delete_consumer": "rule:admin_required",
+ "identity:update_consumer": "rule:admin_required",
+
+ "identity:authorize_request_token": "rule:admin_required",
+ "identity:list_access_token_roles": "rule:admin_required",
+ "identity:get_access_token_role": "rule:admin_required",
+ "identity:list_access_tokens": "rule:admin_required",
+ "identity:get_access_token": "rule:admin_required",
+ "identity:delete_access_token": "rule:admin_required",
+
+ "identity:list_projects_for_endpoint": "rule:admin_required",
+ "identity:add_endpoint_to_project": "rule:admin_required",
+ "identity:check_endpoint_in_project": "rule:admin_required",
+ "identity:list_endpoints_for_project": "rule:admin_required",
+ "identity:remove_endpoint_from_project": "rule:admin_required",
+
+ "identity:create_endpoint_group": "rule:admin_required",
+ "identity:list_endpoint_groups": "rule:admin_required",
+ "identity:get_endpoint_group": "rule:admin_required",
+ "identity:update_endpoint_group": "rule:admin_required",
+ "identity:delete_endpoint_group": "rule:admin_required",
+ "identity:list_projects_associated_with_endpoint_group": "rule:admin_required",
+ "identity:list_endpoints_associated_with_endpoint_group": "rule:admin_required",
+ "identity:get_endpoint_group_in_project": "rule:admin_required",
+ "identity:list_endpoint_groups_for_project": "rule:admin_required",
+ "identity:add_endpoint_group_to_project": "rule:admin_required",
+ "identity:remove_endpoint_group_from_project": "rule:admin_required",
+
+ "identity:create_identity_provider": "rule:cloud_admin",
+ "identity:list_identity_providers": "rule:cloud_admin",
+ "identity:get_identity_provider": "rule:cloud_admin",
+ "identity:update_identity_provider": "rule:cloud_admin",
+ "identity:delete_identity_provider": "rule:cloud_admin",
+
+ "identity:create_protocol": "rule:cloud_admin",
+ "identity:update_protocol": "rule:cloud_admin",
+ "identity:get_protocol": "rule:cloud_admin",
+ "identity:list_protocols": "rule:cloud_admin",
+ "identity:delete_protocol": "rule:cloud_admin",
+
+ "identity:create_mapping": "rule:cloud_admin",
+ "identity:get_mapping": "rule:cloud_admin",
+ "identity:list_mappings": "rule:cloud_admin",
+ "identity:delete_mapping": "rule:cloud_admin",
+ "identity:update_mapping": "rule:cloud_admin",
+
+ "identity:create_service_provider": "rule:cloud_admin",
+ "identity:list_service_providers": "rule:cloud_admin",
+ "identity:get_service_provider": "rule:cloud_admin",
+ "identity:update_service_provider": "rule:cloud_admin",
+ "identity:delete_service_provider": "rule:cloud_admin",
+
+ "identity:get_auth_catalog": "",
+ "identity:get_auth_projects": "",
+ "identity:get_auth_domains": "",
+ "identity:get_auth_system": "",
+
+ "identity:list_projects_for_user": "",
+ "identity:list_domains_for_user": "",
+
+ "identity:list_revoke_events": "rule:service_or_admin",
+
+ "identity:create_policy_association_for_endpoint": "rule:cloud_admin",
+ "identity:check_policy_association_for_endpoint": "rule:cloud_admin",
+ "identity:delete_policy_association_for_endpoint": "rule:cloud_admin",
+ "identity:create_policy_association_for_service": "rule:cloud_admin",
+ "identity:check_policy_association_for_service": "rule:cloud_admin",
+ "identity:delete_policy_association_for_service": "rule:cloud_admin",
+ "identity:create_policy_association_for_region_and_service": "rule:cloud_admin",
+ "identity:check_policy_association_for_region_and_service": "rule:cloud_admin",
+ "identity:delete_policy_association_for_region_and_service": "rule:cloud_admin",
+ "identity:get_policy_for_endpoint": "rule:cloud_admin",
+ "identity:list_endpoints_for_policy": "rule:cloud_admin",
+
+ "identity:create_domain_config": "rule:cloud_admin",
+ "identity:get_domain_config": "rule:cloud_admin",
+ "identity:get_security_compliance_domain_config": "",
+ "identity:update_domain_config": "rule:cloud_admin",
+ "identity:delete_domain_config": "rule:cloud_admin",
+ "identity:get_domain_config_default": "rule:cloud_admin",
+
+ "identity:get_application_credential": "rule:admin_or_owner",
+ "identity:list_application_credentials": "rule:admin_or_owner",
+ "identity:create_application_credential": "rule:admin_or_owner",
+ "identity:delete_application_credential": "rule:admin_or_owner"
+}
diff --git a/old/tools/policies/policy.json.d/neutron.policy.json b/old/tools/policies/policy.json.d/neutron.policy.json
new file mode 100644
index 00000000..15f17203
--- /dev/null
+++ b/old/tools/policies/policy.json.d/neutron.policy.json
@@ -0,0 +1,235 @@
+{
+ "context_is_admin": "role:admin or user_name:neutron",
+ "owner": "tenant_id:%(tenant_id)s",
+ "admin_or_owner": "rule:context_is_admin or rule:owner",
+ "context_is_advsvc": "role:advsvc",
+ "admin_or_network_owner": "rule:context_is_admin or tenant_id:%(network:tenant_id)s",
+ "admin_owner_or_network_owner": "rule:owner or rule:admin_or_network_owner",
+ "admin_only": "rule:context_is_admin",
+ "regular_user": "",
+ "admin_or_data_plane_int": "rule:context_is_admin or role:data_plane_integrator",
+ "shared": "field:networks:shared=True",
+ "shared_subnetpools": "field:subnetpools:shared=True",
+ "shared_address_scopes": "field:address_scopes:shared=True",
+ "external": "field:networks:router:external=True",
+ "default": "rule:admin_or_owner",
+
+ "create_subnet": "rule:admin_or_network_owner",
+ "create_subnet:segment_id": "rule:admin_only",
+ "create_subnet:service_types": "rule:admin_only",
+ "get_subnet": "rule:admin_or_owner or rule:shared",
+ "get_subnet:segment_id": "rule:admin_only",
+ "update_subnet": "rule:admin_or_network_owner",
+ "update_subnet:service_types": "rule:admin_only",
+ "delete_subnet": "rule:admin_or_network_owner",
+
+ "create_subnetpool": "",
+ "create_subnetpool:shared": "rule:admin_only",
+ "create_subnetpool:is_default": "rule:admin_only",
+ "get_subnetpool": "rule:admin_or_owner or rule:shared_subnetpools",
+ "update_subnetpool": "rule:admin_or_owner",
+ "update_subnetpool:is_default": "rule:admin_only",
+ "delete_subnetpool": "rule:admin_or_owner",
+
+ "create_address_scope": "",
+ "create_address_scope:shared": "rule:admin_only",
+ "get_address_scope": "rule:admin_or_owner or rule:shared_address_scopes",
+ "update_address_scope": "rule:admin_or_owner",
+ "update_address_scope:shared": "rule:admin_only",
+ "delete_address_scope": "rule:admin_or_owner",
+
+ "create_network": "",
+ "get_network": "rule:admin_or_owner or rule:shared or rule:external or rule:context_is_advsvc",
+ "get_network:router:external": "rule:regular_user",
+ "get_network:segments": "rule:admin_only",
+ "get_network:provider:network_type": "rule:admin_only",
+ "get_network:provider:physical_network": "rule:admin_only",
+ "get_network:provider:segmentation_id": "rule:admin_only",
+ "get_network:queue_id": "rule:admin_only",
+ "get_network_ip_availabilities": "rule:admin_only",
+ "get_network_ip_availability": "rule:admin_only",
+ "create_network:shared": "rule:admin_only",
+ "create_network:router:external": "rule:admin_only",
+ "create_network:is_default": "rule:admin_only",
+ "create_network:segments": "rule:admin_only",
+ "create_network:provider:network_type": "rule:admin_only",
+ "create_network:provider:physical_network": "rule:admin_only",
+ "create_network:provider:segmentation_id": "rule:admin_only",
+ "update_network": "rule:admin_or_owner",
+ "update_network:segments": "rule:admin_only",
+ "update_network:shared": "rule:admin_only",
+ "update_network:provider:network_type": "rule:admin_only",
+ "update_network:provider:physical_network": "rule:admin_only",
+ "update_network:provider:segmentation_id": "rule:admin_only",
+ "update_network:router:external": "rule:admin_only",
+ "delete_network": "rule:admin_or_owner",
+
+ "create_segment": "rule:admin_only",
+ "get_segment": "rule:admin_only",
+ "update_segment": "rule:admin_only",
+ "delete_segment": "rule:admin_only",
+
+ "network_device": "field:port:device_owner=~^network:",
+ "create_port": "",
+ "create_port:device_owner": "not rule:network_device or rule:context_is_advsvc or rule:admin_or_network_owner",
+ "create_port:mac_address": "rule:context_is_advsvc or rule:admin_or_network_owner",
+ "create_port:fixed_ips:ip_address": "rule:context_is_advsvc or rule:admin_or_network_owner",
+ "create_port:fixed_ips:subnet_id": "rule:context_is_advsvc or rule:admin_or_network_owner or rule:shared",
+ "create_port:port_security_enabled": "rule:context_is_advsvc or rule:admin_or_network_owner",
+ "create_port:binding:host_id": "rule:admin_only",
+ "create_port:binding:profile": "rule:admin_only",
+ "create_port:mac_learning_enabled": "rule:context_is_advsvc or rule:admin_or_network_owner",
+ "create_port:allowed_address_pairs": "rule:admin_or_network_owner",
+ "get_port": "rule:context_is_advsvc or rule:admin_owner_or_network_owner",
+ "get_port:queue_id": "rule:admin_only",
+ "get_port:binding:vif_type": "rule:admin_only",
+ "get_port:binding:vif_details": "rule:admin_only",
+ "get_port:binding:host_id": "rule:admin_only",
+ "get_port:binding:profile": "rule:admin_only",
+ "update_port": "rule:admin_or_owner or rule:context_is_advsvc",
+ "update_port:device_owner": "not rule:network_device or rule:context_is_advsvc or rule:admin_or_network_owner",
+ "update_port:mac_address": "rule:admin_only or rule:context_is_advsvc",
+ "update_port:fixed_ips:ip_address": "rule:context_is_advsvc or rule:admin_or_network_owner",
+ "update_port:fixed_ips:subnet_id": "rule:context_is_advsvc or rule:admin_or_network_owner or rule:shared",
+ "update_port:port_security_enabled": "rule:context_is_advsvc or rule:admin_or_network_owner",
+ "update_port:binding:host_id": "rule:admin_only",
+ "update_port:binding:profile": "rule:admin_only",
+ "update_port:mac_learning_enabled": "rule:context_is_advsvc or rule:admin_or_network_owner",
+ "update_port:allowed_address_pairs": "rule:admin_or_network_owner",
+ "update_port:data_plane_status": "rule:admin_or_data_plane_int",
+ "delete_port": "rule:context_is_advsvc or rule:admin_owner_or_network_owner",
+
+ "get_router:ha": "rule:admin_only",
+ "create_router": "rule:regular_user",
+ "create_router:external_gateway_info:enable_snat": "rule:admin_only",
+ "create_router:distributed": "rule:admin_only",
+ "create_router:ha": "rule:admin_only",
+ "get_router": "http://192.168.1.50:31002/wrapper/authz/grant",
+ "get_router:distributed": "rule:admin_only",
+ "update_router": "rule:admin_or_owner",
+ "update_router:external_gateway_info": "rule:admin_or_owner",
+ "update_router:external_gateway_info:network_id": "rule:admin_or_owner",
+ "update_router:external_gateway_info:enable_snat": "rule:admin_only",
+ "update_router:distributed": "rule:admin_only",
+ "update_router:ha": "rule:admin_only",
+ "delete_router": "rule:admin_or_owner",
+
+ "add_router_interface": "rule:admin_or_owner",
+ "remove_router_interface": "rule:admin_or_owner",
+
+ "create_router:external_gateway_info:external_fixed_ips": "rule:admin_only",
+ "update_router:external_gateway_info:external_fixed_ips": "rule:admin_only",
+
+ "create_qos_queue": "rule:admin_only",
+ "get_qos_queue": "rule:admin_only",
+
+ "update_agent": "rule:admin_only",
+ "delete_agent": "rule:admin_only",
+ "get_agent": "rule:admin_only",
+
+ "create_dhcp-network": "rule:admin_only",
+ "delete_dhcp-network": "rule:admin_only",
+ "get_dhcp-networks": "rule:admin_only",
+ "create_l3-router": "rule:admin_only",
+ "delete_l3-router": "rule:admin_only",
+ "get_l3-routers": "rule:admin_only",
+ "get_dhcp-agents": "rule:admin_only",
+ "get_l3-agents": "rule:admin_only",
+ "get_loadbalancer-agent": "rule:admin_only",
+ "get_loadbalancer-pools": "rule:admin_only",
+ "get_agent-loadbalancers": "rule:admin_only",
+ "get_loadbalancer-hosting-agent": "rule:admin_only",
+
+ "create_floatingip": "rule:regular_user",
+ "create_floatingip:floating_ip_address": "rule:admin_only",
+ "update_floatingip": "rule:admin_or_owner",
+ "delete_floatingip": "rule:admin_or_owner",
+ "get_floatingip": "rule:admin_or_owner",
+
+ "create_network_profile": "rule:admin_only",
+ "update_network_profile": "rule:admin_only",
+ "delete_network_profile": "rule:admin_only",
+ "get_network_profiles": "",
+ "get_network_profile": "",
+ "update_policy_profiles": "rule:admin_only",
+ "get_policy_profiles": "",
+ "get_policy_profile": "",
+
+ "create_metering_label": "rule:admin_only",
+ "delete_metering_label": "rule:admin_only",
+ "get_metering_label": "rule:admin_only",
+
+ "create_metering_label_rule": "rule:admin_only",
+ "delete_metering_label_rule": "rule:admin_only",
+ "get_metering_label_rule": "rule:admin_only",
+
+ "get_service_provider": "rule:regular_user",
+ "get_lsn": "rule:admin_only",
+ "create_lsn": "rule:admin_only",
+
+ "create_flavor": "rule:admin_only",
+ "update_flavor": "rule:admin_only",
+ "delete_flavor": "rule:admin_only",
+ "get_flavors": "rule:regular_user",
+ "get_flavor": "rule:regular_user",
+ "create_service_profile": "rule:admin_only",
+ "update_service_profile": "rule:admin_only",
+ "delete_service_profile": "rule:admin_only",
+ "get_service_profiles": "rule:admin_only",
+ "get_service_profile": "rule:admin_only",
+
+ "get_policy": "rule:regular_user",
+ "create_policy": "rule:admin_only",
+ "update_policy": "rule:admin_only",
+ "delete_policy": "rule:admin_only",
+ "get_policy_bandwidth_limit_rule": "rule:regular_user",
+ "create_policy_bandwidth_limit_rule": "rule:admin_only",
+ "delete_policy_bandwidth_limit_rule": "rule:admin_only",
+ "update_policy_bandwidth_limit_rule": "rule:admin_only",
+ "get_policy_dscp_marking_rule": "rule:regular_user",
+ "create_policy_dscp_marking_rule": "rule:admin_only",
+ "delete_policy_dscp_marking_rule": "rule:admin_only",
+ "update_policy_dscp_marking_rule": "rule:admin_only",
+ "get_rule_type": "rule:regular_user",
+ "get_policy_minimum_bandwidth_rule": "rule:regular_user",
+ "create_policy_minimum_bandwidth_rule": "rule:admin_only",
+ "delete_policy_minimum_bandwidth_rule": "rule:admin_only",
+ "update_policy_minimum_bandwidth_rule": "rule:admin_only",
+
+ "restrict_wildcard": "(not field:rbac_policy:target_tenant=*) or rule:admin_only",
+ "create_rbac_policy": "",
+ "create_rbac_policy:target_tenant": "rule:restrict_wildcard",
+ "update_rbac_policy": "rule:admin_or_owner",
+ "update_rbac_policy:target_tenant": "rule:restrict_wildcard and rule:admin_or_owner",
+ "get_rbac_policy": "rule:admin_or_owner",
+ "delete_rbac_policy": "rule:admin_or_owner",
+
+ "create_flavor_service_profile": "rule:admin_only",
+ "delete_flavor_service_profile": "rule:admin_only",
+ "get_flavor_service_profile": "rule:regular_user",
+ "get_auto_allocated_topology": "rule:admin_or_owner",
+
+ "create_trunk": "rule:regular_user",
+ "get_trunk": "rule:admin_or_owner",
+ "delete_trunk": "rule:admin_or_owner",
+ "get_subports": "",
+ "add_subports": "rule:admin_or_owner",
+ "remove_subports": "rule:admin_or_owner",
+
+ "get_security_groups": "rule:admin_or_owner",
+ "get_security_group": "rule:admin_or_owner",
+ "create_security_group": "rule:admin_or_owner",
+ "update_security_group": "rule:admin_or_owner",
+ "delete_security_group": "rule:admin_or_owner",
+ "get_security_group_rules": "rule:admin_or_owner",
+ "get_security_group_rule": "rule:admin_or_owner",
+ "create_security_group_rule": "rule:admin_or_owner",
+ "delete_security_group_rule": "rule:admin_or_owner",
+
+ "get_loggable_resources": "rule:admin_only",
+ "create_log": "rule:admin_only",
+ "update_log": "rule:admin_only",
+ "delete_log": "rule:admin_only",
+ "get_logs": "rule:admin_only",
+ "get_log": "rule:admin_only"
+}
diff --git a/old/tools/policies/policy.json.d/nova.policy.json b/old/tools/policies/policy.json.d/nova.policy.json
new file mode 100644
index 00000000..da8f5740
--- /dev/null
+++ b/old/tools/policies/policy.json.d/nova.policy.json
@@ -0,0 +1,485 @@
+{
+ "context_is_admin": "role:admin",
+ "admin_or_owner": "is_admin:True or project_id:%(project_id)s",
+ "default": "rule:admin_or_owner",
+
+ "cells_scheduler_filter:TargetCellFilter": "is_admin:True",
+
+ "compute:create": "",
+ "compute:create:attach_network": "",
+ "compute:create:attach_volume": "",
+ "compute:create:forced_host": "is_admin:True",
+
+ "compute:get": "",
+ "compute:get_all": "",
+ "compute:get_all_tenants": "is_admin:True",
+
+ "compute:update": "",
+
+ "compute:get_instance_metadata": "",
+ "compute:get_all_instance_metadata": "",
+ "compute:get_all_instance_system_metadata": "",
+ "compute:update_instance_metadata": "",
+ "compute:delete_instance_metadata": "",
+
+ "compute:get_instance_faults": "",
+ "compute:get_diagnostics": "",
+ "compute:get_instance_diagnostics": "",
+
+ "compute:start": "rule:admin_or_owner",
+ "compute:stop": "rule:admin_or_owner",
+
+ "compute:get_lock": "",
+ "compute:lock": "rule:admin_or_owner",
+ "compute:unlock": "rule:admin_or_owner",
+ "compute:unlock_override": "rule:admin_api",
+
+ "compute:get_vnc_console": "",
+ "compute:get_spice_console": "",
+ "compute:get_rdp_console": "",
+ "compute:get_serial_console": "",
+ "compute:get_mks_console": "",
+ "compute:get_console_output": "",
+
+ "compute:reset_network": "",
+ "compute:inject_network_info": "",
+ "compute:add_fixed_ip": "",
+ "compute:remove_fixed_ip": "",
+
+ "compute:attach_volume": "",
+ "compute:detach_volume": "",
+ "compute:swap_volume": "",
+
+ "compute:attach_interface": "",
+ "compute:detach_interface": "",
+
+ "compute:set_admin_password": "",
+
+ "compute:rescue": "",
+ "compute:unrescue": "",
+
+ "compute:suspend": "",
+ "compute:resume": "",
+
+ "compute:pause": "",
+ "compute:unpause": "",
+
+ "compute:shelve": "",
+ "compute:shelve_offload": "",
+ "compute:unshelve": "",
+
+ "compute:snapshot": "",
+ "compute:snapshot_volume_backed": "",
+ "compute:backup": "",
+
+ "compute:resize": "",
+ "compute:confirm_resize": "",
+ "compute:revert_resize": "",
+
+ "compute:rebuild": "",
+ "compute:reboot": "",
+ "compute:delete": "rule:admin_or_owner",
+ "compute:soft_delete": "rule:admin_or_owner",
+ "compute:force_delete": "rule:admin_or_owner",
+
+ "compute:security_groups:add_to_instance": "",
+ "compute:security_groups:remove_from_instance": "",
+
+ "compute:restore": "",
+
+ "compute:volume_snapshot_create": "",
+ "compute:volume_snapshot_delete": "",
+
+ "admin_api": "is_admin:True",
+ "compute_extension:accounts": "rule:admin_api",
+ "compute_extension:admin_actions": "rule:admin_api",
+ "compute_extension:admin_actions:pause": "rule:admin_or_owner",
+ "compute_extension:admin_actions:unpause": "rule:admin_or_owner",
+ "compute_extension:admin_actions:suspend": "rule:admin_or_owner",
+ "compute_extension:admin_actions:resume": "rule:admin_or_owner",
+ "compute_extension:admin_actions:lock": "rule:admin_or_owner",
+ "compute_extension:admin_actions:unlock": "rule:admin_or_owner",
+ "compute_extension:admin_actions:resetNetwork": "rule:admin_api",
+ "compute_extension:admin_actions:injectNetworkInfo": "rule:admin_api",
+ "compute_extension:admin_actions:createBackup": "rule:admin_or_owner",
+ "compute_extension:admin_actions:migrateLive": "rule:admin_api",
+ "compute_extension:admin_actions:resetState": "rule:admin_api",
+ "compute_extension:admin_actions:migrate": "rule:admin_api",
+ "compute_extension:aggregates": "rule:admin_api",
+ "compute_extension:agents": "rule:admin_api",
+ "compute_extension:attach_interfaces": "",
+ "compute_extension:baremetal_nodes": "rule:admin_api",
+ "compute_extension:cells": "rule:admin_api",
+ "compute_extension:cells:create": "rule:admin_api",
+ "compute_extension:cells:delete": "rule:admin_api",
+ "compute_extension:cells:update": "rule:admin_api",
+ "compute_extension:cells:sync_instances": "rule:admin_api",
+ "compute_extension:certificates": "",
+ "compute_extension:cloudpipe": "rule:admin_api",
+ "compute_extension:cloudpipe_update": "rule:admin_api",
+ "compute_extension:config_drive": "",
+ "compute_extension:console_output": "",
+ "compute_extension:consoles": "",
+ "compute_extension:createserverext": "",
+ "compute_extension:deferred_delete": "",
+ "compute_extension:disk_config": "",
+ "compute_extension:evacuate": "rule:admin_api",
+ "compute_extension:extended_server_attributes": "rule:admin_api",
+ "compute_extension:extended_status": "",
+ "compute_extension:extended_availability_zone": "",
+ "compute_extension:extended_ips": "",
+ "compute_extension:extended_ips_mac": "",
+ "compute_extension:extended_vif_net": "",
+ "compute_extension:extended_volumes": "",
+ "compute_extension:fixed_ips": "rule:admin_api",
+ "compute_extension:flavor_access": "",
+ "compute_extension:flavor_access:addTenantAccess": "rule:admin_api",
+ "compute_extension:flavor_access:removeTenantAccess": "rule:admin_api",
+ "compute_extension:flavor_disabled": "",
+ "compute_extension:flavor_rxtx": "",
+ "compute_extension:flavor_swap": "",
+ "compute_extension:flavorextradata": "",
+ "compute_extension:flavorextraspecs:index": "",
+ "compute_extension:flavorextraspecs:show": "",
+ "compute_extension:flavorextraspecs:create": "rule:admin_api",
+ "compute_extension:flavorextraspecs:update": "rule:admin_api",
+ "compute_extension:flavorextraspecs:delete": "rule:admin_api",
+ "compute_extension:flavormanage": "rule:admin_api",
+ "compute_extension:floating_ip_dns": "",
+ "compute_extension:floating_ip_pools": "",
+ "compute_extension:floating_ips": "",
+ "compute_extension:floating_ips_bulk": "rule:admin_api",
+ "compute_extension:fping": "",
+ "compute_extension:fping:all_tenants": "rule:admin_api",
+ "compute_extension:hide_server_addresses": "is_admin:False",
+ "compute_extension:hosts": "rule:admin_api",
+ "compute_extension:hypervisors": "rule:admin_api",
+ "compute_extension:image_size": "",
+ "compute_extension:instance_actions": "",
+ "compute_extension:instance_actions:events": "rule:admin_api",
+ "compute_extension:instance_usage_audit_log": "rule:admin_api",
+ "compute_extension:keypairs": "",
+ "compute_extension:keypairs:index": "",
+ "compute_extension:keypairs:show": "",
+ "compute_extension:keypairs:create": "",
+ "compute_extension:keypairs:delete": "",
+ "compute_extension:multinic": "",
+ "compute_extension:networks": "rule:admin_api",
+ "compute_extension:networks:view": "",
+ "compute_extension:networks_associate": "rule:admin_api",
+ "compute_extension:os-tenant-networks": "",
+ "compute_extension:quotas:show": "",
+ "compute_extension:quotas:update": "rule:admin_api",
+ "compute_extension:quotas:delete": "rule:admin_api",
+ "compute_extension:quota_classes": "",
+ "compute_extension:rescue": "",
+ "compute_extension:security_group_default_rules": "rule:admin_api",
+ "compute_extension:security_groups": "",
+ "compute_extension:server_diagnostics": "rule:admin_api",
+ "compute_extension:server_groups": "",
+ "compute_extension:server_password": "",
+ "compute_extension:server_usage": "",
+ "compute_extension:services": "rule:admin_api",
+ "compute_extension:shelve": "",
+ "compute_extension:shelveOffload": "rule:admin_api",
+ "compute_extension:simple_tenant_usage:show": "rule:admin_or_owner",
+ "compute_extension:simple_tenant_usage:list": "rule:admin_api",
+ "compute_extension:unshelve": "",
+ "compute_extension:users": "rule:admin_api",
+ "compute_extension:virtual_interfaces": "",
+ "compute_extension:virtual_storage_arrays": "",
+ "compute_extension:volumes": "",
+ "compute_extension:volume_attachments:index": "",
+ "compute_extension:volume_attachments:show": "",
+ "compute_extension:volume_attachments:create": "",
+ "compute_extension:volume_attachments:update": "",
+ "compute_extension:volume_attachments:delete": "",
+ "compute_extension:volumetypes": "",
+ "compute_extension:availability_zone:list": "",
+ "compute_extension:availability_zone:detail": "rule:admin_api",
+ "compute_extension:used_limits_for_admin": "rule:admin_api",
+ "compute_extension:migrations:index": "rule:admin_api",
+ "compute_extension:os-assisted-volume-snapshots:create": "rule:admin_api",
+ "compute_extension:os-assisted-volume-snapshots:delete": "rule:admin_api",
+ "compute_extension:console_auth_tokens": "rule:admin_api",
+ "compute_extension:os-server-external-events:create": "rule:admin_api",
+
+ "network:get_all": "",
+ "network:get": "",
+ "network:create": "",
+ "network:delete": "",
+ "network:associate": "",
+ "network:disassociate": "",
+ "network:get_vifs_by_instance": "",
+ "network:allocate_for_instance": "",
+ "network:deallocate_for_instance": "",
+ "network:validate_networks": "",
+ "network:get_instance_uuids_by_ip_filter": "",
+ "network:get_instance_id_by_floating_address": "",
+ "network:setup_networks_on_host": "",
+ "network:get_backdoor_port": "",
+
+ "network:get_floating_ip": "",
+ "network:get_floating_ip_pools": "",
+ "network:get_floating_ip_by_address": "",
+ "network:get_floating_ips_by_project": "",
+ "network:get_floating_ips_by_fixed_address": "",
+ "network:allocate_floating_ip": "",
+ "network:associate_floating_ip": "",
+ "network:disassociate_floating_ip": "",
+ "network:release_floating_ip": "",
+ "network:migrate_instance_start": "",
+ "network:migrate_instance_finish": "",
+
+ "network:get_fixed_ip": "",
+ "network:get_fixed_ip_by_address": "",
+ "network:add_fixed_ip_to_instance": "",
+ "network:remove_fixed_ip_from_instance": "",
+ "network:add_network_to_project": "",
+ "network:get_instance_nw_info": "",
+
+ "network:get_dns_domains": "",
+ "network:add_dns_entry": "",
+ "network:modify_dns_entry": "",
+ "network:delete_dns_entry": "",
+ "network:get_dns_entries_by_address": "",
+ "network:get_dns_entries_by_name": "",
+ "network:create_private_dns_domain": "",
+ "network:create_public_dns_domain": "",
+ "network:delete_dns_domain": "",
+ "network:attach_external_network": "rule:admin_api",
+ "network:get_vif_by_mac_address": "",
+
+ "os_compute_api:servers:detail:get_all_tenants": "is_admin:True",
+ "os_compute_api:servers:index:get_all_tenants": "is_admin:True",
+ "os_compute_api:servers:confirm_resize": "",
+ "os_compute_api:servers:create": "",
+ "os_compute_api:servers:create:attach_network": "",
+ "os_compute_api:servers:create:attach_volume": "",
+ "os_compute_api:servers:create:forced_host": "rule:admin_api",
+ "os_compute_api:servers:delete": "",
+ "os_compute_api:servers:update": "",
+ "os_compute_api:servers:detail": "",
+ "os_compute_api:servers:index": "",
+ "os_compute_api:servers:reboot": "",
+ "os_compute_api:servers:rebuild": "",
+ "os_compute_api:servers:resize": "",
+ "os_compute_api:servers:revert_resize": "",
+ "os_compute_api:servers:show": "",
+ "os_compute_api:servers:create_image": "",
+ "os_compute_api:servers:create_image:allow_volume_backed": "",
+ "os_compute_api:servers:start": "rule:admin_or_owner",
+ "os_compute_api:servers:stop": "rule:admin_or_owner",
+ "os_compute_api:os-access-ips:discoverable": "",
+ "os_compute_api:os-access-ips": "",
+ "os_compute_api:os-admin-actions": "rule:admin_api",
+ "os_compute_api:os-admin-actions:discoverable": "",
+ "os_compute_api:os-admin-actions:reset_network": "rule:admin_api",
+ "os_compute_api:os-admin-actions:inject_network_info": "rule:admin_api",
+ "os_compute_api:os-admin-actions:reset_state": "rule:admin_api",
+ "os_compute_api:os-admin-password": "",
+ "os_compute_api:os-admin-password:discoverable": "",
+ "os_compute_api:os-aggregates:discoverable": "",
+ "os_compute_api:os-aggregates:index": "rule:admin_api",
+ "os_compute_api:os-aggregates:create": "rule:admin_api",
+ "os_compute_api:os-aggregates:show": "rule:admin_api",
+ "os_compute_api:os-aggregates:update": "rule:admin_api",
+ "os_compute_api:os-aggregates:delete": "rule:admin_api",
+ "os_compute_api:os-aggregates:add_host": "rule:admin_api",
+ "os_compute_api:os-aggregates:remove_host": "rule:admin_api",
+ "os_compute_api:os-aggregates:set_metadata": "rule:admin_api",
+ "os_compute_api:os-agents": "rule:admin_api",
+ "os_compute_api:os-agents:discoverable": "",
+ "os_compute_api:os-attach-interfaces": "",
+ "os_compute_api:os-attach-interfaces:discoverable": "",
+ "os_compute_api:os-baremetal-nodes": "rule:admin_api",
+ "os_compute_api:os-baremetal-nodes:discoverable": "",
+ "os_compute_api:os-block-device-mapping-v1:discoverable": "",
+ "os_compute_api:os-cells": "rule:admin_api",
+ "os_compute_api:os-cells:create": "rule:admin_api",
+ "os_compute_api:os-cells:delete": "rule:admin_api",
+ "os_compute_api:os-cells:update": "rule:admin_api",
+ "os_compute_api:os-cells:sync_instances": "rule:admin_api",
+ "os_compute_api:os-cells:discoverable": "",
+ "os_compute_api:os-certificates:create": "",
+ "os_compute_api:os-certificates:show": "",
+ "os_compute_api:os-certificates:discoverable": "",
+ "os_compute_api:os-cloudpipe": "rule:admin_api",
+ "os_compute_api:os-cloudpipe:discoverable": "",
+ "os_compute_api:os-config-drive": "",
+ "os_compute_api:os-consoles:discoverable": "",
+ "os_compute_api:os-consoles:create": "",
+ "os_compute_api:os-consoles:delete": "",
+ "os_compute_api:os-consoles:index": "",
+ "os_compute_api:os-consoles:show": "",
+ "os_compute_api:os-console-output:discoverable": "",
+ "os_compute_api:os-console-output": "",
+ "os_compute_api:os-remote-consoles": "",
+ "os_compute_api:os-remote-consoles:discoverable": "",
+ "os_compute_api:os-create-backup:discoverable": "",
+ "os_compute_api:os-create-backup": "rule:admin_or_owner",
+ "os_compute_api:os-deferred-delete": "",
+ "os_compute_api:os-deferred-delete:discoverable": "",
+ "os_compute_api:os-disk-config": "",
+ "os_compute_api:os-disk-config:discoverable": "",
+ "os_compute_api:os-evacuate": "rule:admin_api",
+ "os_compute_api:os-evacuate:discoverable": "",
+ "os_compute_api:os-extended-server-attributes": "rule:admin_api",
+ "os_compute_api:os-extended-server-attributes:discoverable": "",
+ "os_compute_api:os-extended-status": "",
+ "os_compute_api:os-extended-status:discoverable": "",
+ "os_compute_api:os-extended-availability-zone": "",
+ "os_compute_api:os-extended-availability-zone:discoverable": "",
+ "os_compute_api:extensions": "",
+ "os_compute_api:extension_info:discoverable": "",
+ "os_compute_api:os-extended-volumes": "",
+ "os_compute_api:os-extended-volumes:discoverable": "",
+ "os_compute_api:os-fixed-ips": "rule:admin_api",
+ "os_compute_api:os-fixed-ips:discoverable": "",
+ "os_compute_api:os-flavor-access": "",
+ "os_compute_api:os-flavor-access:discoverable": "",
+ "os_compute_api:os-flavor-access:remove_tenant_access": "rule:admin_api",
+ "os_compute_api:os-flavor-access:add_tenant_access": "rule:admin_api",
+ "os_compute_api:os-flavor-rxtx": "",
+ "os_compute_api:os-flavor-rxtx:discoverable": "",
+ "os_compute_api:flavors:discoverable": "",
+ "os_compute_api:os-flavor-extra-specs:discoverable": "",
+ "os_compute_api:os-flavor-extra-specs:index": "",
+ "os_compute_api:os-flavor-extra-specs:show": "",
+ "os_compute_api:os-flavor-extra-specs:create": "rule:admin_api",
+ "os_compute_api:os-flavor-extra-specs:update": "rule:admin_api",
+ "os_compute_api:os-flavor-extra-specs:delete": "rule:admin_api",
+ "os_compute_api:os-flavor-manage:discoverable": "",
+ "os_compute_api:os-flavor-manage": "rule:admin_api",
+ "os_compute_api:os-floating-ip-dns": "",
+ "os_compute_api:os-floating-ip-dns:discoverable": "",
+ "os_compute_api:os-floating-ip-dns:domain:update": "rule:admin_api",
+ "os_compute_api:os-floating-ip-dns:domain:delete": "rule:admin_api",
+ "os_compute_api:os-floating-ip-pools": "",
+ "os_compute_api:os-floating-ip-pools:discoverable": "",
+ "os_compute_api:os-floating-ips": "",
+ "os_compute_api:os-floating-ips:discoverable": "",
+ "os_compute_api:os-floating-ips-bulk": "rule:admin_api",
+ "os_compute_api:os-floating-ips-bulk:discoverable": "",
+ "os_compute_api:os-fping": "",
+ "os_compute_api:os-fping:discoverable": "",
+ "os_compute_api:os-fping:all_tenants": "rule:admin_api",
+ "os_compute_api:os-hide-server-addresses": "is_admin:False",
+ "os_compute_api:os-hide-server-addresses:discoverable": "",
+ "os_compute_api:os-hosts": "rule:admin_api",
+ "os_compute_api:os-hosts:discoverable": "",
+ "os_compute_api:os-hypervisors": "rule:admin_api",
+ "os_compute_api:os-hypervisors:discoverable": "",
+ "os_compute_api:images:discoverable": "",
+ "os_compute_api:image-size": "",
+ "os_compute_api:image-size:discoverable": "",
+ "os_compute_api:os-instance-actions": "",
+ "os_compute_api:os-instance-actions:discoverable": "",
+ "os_compute_api:os-instance-actions:events": "rule:admin_api",
+ "os_compute_api:os-instance-usage-audit-log": "rule:admin_api",
+ "os_compute_api:os-instance-usage-audit-log:discoverable": "",
+ "os_compute_api:ips:discoverable": "",
+ "os_compute_api:ips:index": "rule:admin_or_owner",
+ "os_compute_api:ips:show": "rule:admin_or_owner",
+ "os_compute_api:os-keypairs:discoverable": "",
+ "os_compute_api:os-keypairs": "",
+ "os_compute_api:os-keypairs:index": "rule:admin_api or user_id:%(user_id)s",
+ "os_compute_api:os-keypairs:show": "rule:admin_api or user_id:%(user_id)s",
+ "os_compute_api:os-keypairs:create": "rule:admin_api or user_id:%(user_id)s",
+ "os_compute_api:os-keypairs:delete": "rule:admin_api or user_id:%(user_id)s",
+ "os_compute_api:limits:discoverable": "",
+ "os_compute_api:limits": "",
+ "os_compute_api:os-lock-server:discoverable": "",
+ "os_compute_api:os-lock-server:lock": "rule:admin_or_owner",
+ "os_compute_api:os-lock-server:unlock": "rule:admin_or_owner",
+ "os_compute_api:os-lock-server:unlock:unlock_override": "rule:admin_api",
+ "os_compute_api:os-migrate-server:discoverable": "",
+ "os_compute_api:os-migrate-server:migrate": "rule:admin_api",
+ "os_compute_api:os-migrate-server:migrate_live": "rule:admin_api",
+ "os_compute_api:os-multinic": "",
+ "os_compute_api:os-multinic:discoverable": "",
+ "os_compute_api:os-networks": "rule:admin_api",
+ "os_compute_api:os-networks:view": "",
+ "os_compute_api:os-networks:discoverable": "",
+ "os_compute_api:os-networks-associate": "rule:admin_api",
+ "os_compute_api:os-networks-associate:discoverable": "",
+ "os_compute_api:os-pause-server:discoverable": "",
+ "os_compute_api:os-pause-server:pause": "rule:admin_or_owner",
+ "os_compute_api:os-pause-server:unpause": "rule:admin_or_owner",
+ "os_compute_api:os-pci:pci_servers": "",
+ "os_compute_api:os-pci:discoverable": "",
+ "os_compute_api:os-pci:index": "rule:admin_api",
+ "os_compute_api:os-pci:detail": "rule:admin_api",
+ "os_compute_api:os-pci:show": "rule:admin_api",
+ "os_compute_api:os-personality:discoverable": "",
+ "os_compute_api:os-preserve-ephemeral-rebuild:discoverable": "",
+ "os_compute_api:os-quota-sets:discoverable": "",
+ "os_compute_api:os-quota-sets:show": "rule:admin_or_owner",
+ "os_compute_api:os-quota-sets:defaults": "",
+ "os_compute_api:os-quota-sets:update": "rule:admin_api",
+ "os_compute_api:os-quota-sets:delete": "rule:admin_api",
+ "os_compute_api:os-quota-sets:detail": "rule:admin_api",
+ "os_compute_api:os-quota-class-sets:update": "rule:admin_api",
+ "os_compute_api:os-quota-class-sets:show": "is_admin:True or quota_class:%(quota_class)s",
+ "os_compute_api:os-quota-class-sets:discoverable": "",
+ "os_compute_api:os-rescue": "",
+ "os_compute_api:os-rescue:discoverable": "",
+ "os_compute_api:os-scheduler-hints:discoverable": "",
+ "os_compute_api:os-security-group-default-rules:discoverable": "",
+ "os_compute_api:os-security-group-default-rules": "rule:admin_api",
+ "os_compute_api:os-security-groups": "",
+ "os_compute_api:os-security-groups:discoverable": "",
+ "os_compute_api:os-server-diagnostics": "rule:admin_api",
+ "os_compute_api:os-server-diagnostics:discoverable": "",
+ "os_compute_api:os-server-password": "",
+ "os_compute_api:os-server-password:discoverable": "",
+ "os_compute_api:os-server-usage": "",
+ "os_compute_api:os-server-usage:discoverable": "",
+ "os_compute_api:os-server-groups": "",
+ "os_compute_api:os-server-groups:discoverable": "",
+ "os_compute_api:os-services": "rule:admin_api",
+ "os_compute_api:os-services:discoverable": "",
+ "os_compute_api:server-metadata:discoverable": "",
+ "os_compute_api:server-metadata:index": "rule:admin_or_owner",
+ "os_compute_api:server-metadata:show": "rule:admin_or_owner",
+ "os_compute_api:server-metadata:delete": "rule:admin_or_owner",
+ "os_compute_api:server-metadata:create": "rule:admin_or_owner",
+ "os_compute_api:server-metadata:update": "rule:admin_or_owner",
+ "os_compute_api:server-metadata:update_all": "rule:admin_or_owner",
+ "os_compute_api:servers:discoverable": "",
+ "os_compute_api:os-shelve:shelve": "",
+ "os_compute_api:os-shelve:shelve:discoverable": "",
+ "os_compute_api:os-shelve:shelve_offload": "rule:admin_api",
+ "os_compute_api:os-simple-tenant-usage:discoverable": "",
+ "os_compute_api:os-simple-tenant-usage:show": "rule:admin_or_owner",
+ "os_compute_api:os-simple-tenant-usage:list": "rule:admin_api",
+ "os_compute_api:os-suspend-server:discoverable": "",
+ "os_compute_api:os-suspend-server:suspend": "rule:admin_or_owner",
+ "os_compute_api:os-suspend-server:resume": "rule:admin_or_owner",
+ "os_compute_api:os-tenant-networks": "rule:admin_or_owner",
+ "os_compute_api:os-tenant-networks:discoverable": "",
+ "os_compute_api:os-shelve:unshelve": "",
+ "os_compute_api:os-user-data:discoverable": "",
+ "os_compute_api:os-virtual-interfaces": "",
+ "os_compute_api:os-virtual-interfaces:discoverable": "",
+ "os_compute_api:os-volumes": "",
+ "os_compute_api:os-volumes:discoverable": "",
+ "os_compute_api:os-volumes-attachments:index": "",
+ "os_compute_api:os-volumes-attachments:show": "",
+ "os_compute_api:os-volumes-attachments:create": "",
+ "os_compute_api:os-volumes-attachments:update": "",
+ "os_compute_api:os-volumes-attachments:delete": "",
+ "os_compute_api:os-volumes-attachments:discoverable": "",
+ "os_compute_api:os-availability-zone:list": "",
+ "os_compute_api:os-availability-zone:discoverable": "",
+ "os_compute_api:os-availability-zone:detail": "rule:admin_api",
+ "os_compute_api:os-used-limits": "rule:admin_api",
+ "os_compute_api:os-used-limits:discoverable": "",
+ "os_compute_api:os-migrations:index": "rule:admin_api",
+ "os_compute_api:os-migrations:discoverable": "",
+ "os_compute_api:os-assisted-volume-snapshots:create": "rule:admin_api",
+ "os_compute_api:os-assisted-volume-snapshots:delete": "rule:admin_api",
+ "os_compute_api:os-assisted-volume-snapshots:discoverable": "",
+ "os_compute_api:os-console-auth-tokens": "rule:admin_api",
+ "os_compute_api:os-server-external-events:create": "rule:admin_api"
+}