Add additional files for the GUI component. 85/46785/1
authorThomas Duval <thomas.duval@orange.com>
Tue, 7 Nov 2017 10:20:15 +0000 (11:20 +0100)
committerThomas Duval <thomas.duval@orange.com>
Tue, 7 Nov 2017 10:20:15 +0000 (11:20 +0100)
Change-Id: I3753740b42501fa5f370e57c9e0284230438c13d

moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments-edit.tpl.html [new file with mode: 0755]
moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments.edit.dir.js [new file with mode: 0755]
moonv4/moon_gui/static/app/policy/edit/parameter/data/data-edit.tpl.html [new file with mode: 0755]
moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-edit.tpl.html [new file with mode: 0755]
moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.edit.dir.js [new file with mode: 0755]
moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules-edit.tpl.html [new file with mode: 0755]
moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules.edit.dir.js [new file with mode: 0755]
moonv4/moon_gui/static/app/services/moon/policy/parameters/rules.service.js [new file with mode: 0755]

diff --git a/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments-edit.tpl.html b/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments-edit.tpl.html
new file mode 100755 (executable)
index 0000000..9069dcd
--- /dev/null
@@ -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/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments.edit.dir.js b/moonv4/moon_gui/static/app/policy/edit/parameter/assignments/assignments.edit.dir.js
new file mode 100755 (executable)
index 0000000..5297ecc
--- /dev/null
@@ -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/moonv4/moon_gui/static/app/policy/edit/parameter/data/data-edit.tpl.html b/moonv4/moon_gui/static/app/policy/edit/parameter/data/data-edit.tpl.html
new file mode 100755 (executable)
index 0000000..3f11a64
--- /dev/null
@@ -0,0 +1,110 @@
+<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.policyList.$invalid && edit.form.policyList.$dirty}">
+
+                <label for="policyList" class="col-sm-3 control-label" data-translate="moon.policy.data.edit.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.data.edit.check.policy.required">Policy is required
+                        </small>
+                    </div>
+
+                </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/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-edit.tpl.html b/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter-edit.tpl.html
new file mode 100755 (executable)
index 0000000..fa2f93c
--- /dev/null
@@ -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/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.edit.dir.js b/moonv4/moon_gui/static/app/policy/edit/parameter/perimeter/perimeter.edit.dir.js
new file mode 100755 (executable)
index 0000000..a96741f
--- /dev/null
@@ -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() {
+
+            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/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules-edit.tpl.html b/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules-edit.tpl.html
new file mode 100755 (executable)
index 0000000..685046a
--- /dev/null
@@ -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/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules.edit.dir.js b/moonv4/moon_gui/static/app/policy/edit/parameter/rules/rules.edit.dir.js
new file mode 100755 (executable)
index 0000000..b7bb761
--- /dev/null
@@ -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/moonv4/moon_gui/static/app/services/moon/policy/parameters/rules.service.js b/moonv4/moon_gui/static/app/services/moon/policy/parameters/rules.service.js
new file mode 100755 (executable)
index 0000000..76b2401
--- /dev/null
@@ -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