diff options
Diffstat (limited to 'old')
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 Binary files differnew file mode 100644 index 00000000..4a4ca865 --- /dev/null +++ b/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.eot 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="
" /> +<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=" " /> +<glyph unicode=" " horiz-adv-x="652" /> +<glyph unicode=" " horiz-adv-x="1304" /> +<glyph unicode=" " horiz-adv-x="652" /> +<glyph unicode=" " horiz-adv-x="1304" /> +<glyph unicode=" " horiz-adv-x="434" /> +<glyph unicode=" " horiz-adv-x="326" /> +<glyph unicode=" " horiz-adv-x="217" /> +<glyph unicode=" " horiz-adv-x="217" /> +<glyph unicode=" " horiz-adv-x="163" /> +<glyph unicode=" " horiz-adv-x="260" /> +<glyph unicode=" " horiz-adv-x="72" /> +<glyph unicode=" " horiz-adv-x="260" /> +<glyph unicode=" " horiz-adv-x="326" /> +<glyph unicode="€" 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="−" d="M200 400h900v300h-900v-300z" /> +<glyph unicode="◼" horiz-adv-x="500" d="M0 0z" /> +<glyph unicode="☁" 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="✉" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" /> +<glyph unicode="✏" 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="" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" /> +<glyph unicode="" 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="" 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="" 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="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" /> +<glyph unicode="" 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="" 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="" 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="" 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="" 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="" 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="" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" /> +<glyph unicode="" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" /> +<glyph unicode="" 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="" 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="" 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="" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" /> +<glyph unicode="" 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="" 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="" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" /> +<glyph unicode="" 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="" 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="" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" /> +<glyph unicode="" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" /> +<glyph unicode="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" /> +<glyph unicode="" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" /> +<glyph unicode="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" /> +<glyph unicode="" 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="" 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="" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" /> +<glyph unicode="" d="M200 0l900 550l-900 550v-1100z" /> +<glyph unicode="" 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="" 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="" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" /> +<glyph unicode="" 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="" 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="" 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="" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" /> +<glyph unicode="" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" /> +<glyph unicode="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" d="M0 547l600 453v-300h600v-300h-600v-301z" /> +<glyph unicode="" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" /> +<glyph unicode="" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" /> +<glyph unicode="" d="M104 600h296v600h300v-600h298l-449 -600z" /> +<glyph unicode="" 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="" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" /> +<glyph unicode="" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" /> +<glyph unicode="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" /> +<glyph unicode="" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" /> +<glyph unicode="" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" /> +<glyph unicode="" 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="" 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="" 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="" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" /> +<glyph unicode="" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" /> +<glyph unicode="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" /> +<glyph unicode="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" /> +<glyph unicode="" 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="" 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="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" /> +<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" /> +<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" /> +<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" /> +<glyph unicode="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" /> +<glyph unicode="" 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="" 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="" 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="" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" /> +<glyph unicode="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" /> +<glyph unicode="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" 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="" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" /> +<glyph unicode="" 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 Binary files differnew file mode 100644 index 00000000..67fa00bf --- /dev/null +++ b/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.ttf diff --git a/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.woff b/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.woff Binary files differnew file mode 100644 index 00000000..8c54182a --- /dev/null +++ b/old/moon_gui/delivery/assets/fonts/glyphicons-halflings-regular.woff 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 Binary files differnew file mode 100755 index 00000000..d0bce154 --- /dev/null +++ b/old/moon_gui/delivery/assets/img/ajax-loader.gif diff --git a/old/moon_gui/delivery/assets/img/ajax-waiting.gif b/old/moon_gui/delivery/assets/img/ajax-waiting.gif Binary files differnew file mode 100755 index 00000000..d84f6537 --- /dev/null +++ b/old/moon_gui/delivery/assets/img/ajax-waiting.gif diff --git a/old/moon_gui/delivery/assets/img/arrow-link.gif b/old/moon_gui/delivery/assets/img/arrow-link.gif Binary files differnew file mode 100755 index 00000000..ca17f44b --- /dev/null +++ b/old/moon_gui/delivery/assets/img/arrow-link.gif diff --git a/old/moon_gui/delivery/assets/img/et.jpg b/old/moon_gui/delivery/assets/img/et.jpg Binary files differnew file mode 100644 index 00000000..67cc0a9d --- /dev/null +++ b/old/moon_gui/delivery/assets/img/et.jpg diff --git a/old/moon_gui/delivery/assets/img/favicon.ico b/old/moon_gui/delivery/assets/img/favicon.ico Binary files differnew file mode 100755 index 00000000..a7910bf5 --- /dev/null +++ b/old/moon_gui/delivery/assets/img/favicon.ico diff --git a/old/moon_gui/delivery/assets/img/logo-openstack.png b/old/moon_gui/delivery/assets/img/logo-openstack.png Binary files differnew file mode 100755 index 00000000..60ab0e1e --- /dev/null +++ b/old/moon_gui/delivery/assets/img/logo-openstack.png diff --git a/old/moon_gui/delivery/assets/img/logo-orange.gif b/old/moon_gui/delivery/assets/img/logo-orange.gif Binary files differnew file mode 100755 index 00000000..9c612291 --- /dev/null +++ b/old/moon_gui/delivery/assets/img/logo-orange.gif 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()">×</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()">×</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()">×</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()">×</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()">×</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()">×</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()">×</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> </div><div> </div><div> </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()">×</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()">×</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> </div><div> </div><div> </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()">×</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()">×</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()">×</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()">×</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">, </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">, </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">, </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> </div><div> </div><div> </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()">×</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()">×</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()">×</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()">×</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()">×</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">--><!----><!--<!– objects –>--><!----><!--<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>--><!----><!--<!– subjects –>--><!----><!--<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>--><!----><!--<!– roles –>--><!----><!--<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>--><!----><!--<!– groups –>--><!----><!--<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> </div><div> </div><div> </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={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},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(/</,"<").replace(/>/,">"))}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">×</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> </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> </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:' <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()">×</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()">×</button> <strong ng-bind="title"></strong> <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">×</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> </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"> </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"> </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> </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"> </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)">×</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="">«</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="">…</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="">»</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={"\\":"\","&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};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'> </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)"> ×</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()">×</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()">×</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()">×</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()">×</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()">×</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()">×</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()">×</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> </div> + <div> </div> + <div> </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()">×</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()">×</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> </div> + <div> </div> + <div> </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()">×</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()">×</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()">×</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()">×</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">, </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">, </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">, </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> </div> + <div> </div> + <div> </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()">×</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()">×</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()">×</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()">×</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()">×</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">--> + <!----> + <!--<!– objects –>--> + <!----> + <!--<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>--> + <!----> + <!--<!– subjects –>--> + <!----> + <!--<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>--> + <!----> + <!--<!– roles –>--> + <!----> + <!--<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>--> + <!----> + <!--<!– groups –>--> + <!----> + <!--<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> </div> + <div> </div> + <div> </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 Binary files differnew file mode 100755 index 00000000..a7910bf5 --- /dev/null +++ b/old/moon_gui/static/favicon.ico 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 Binary files differnew file mode 100755 index 00000000..d0bce154 --- /dev/null +++ b/old/moon_gui/static/img/ajax-loader.gif diff --git a/old/moon_gui/static/img/ajax-waiting.gif b/old/moon_gui/static/img/ajax-waiting.gif Binary files differnew file mode 100755 index 00000000..d84f6537 --- /dev/null +++ b/old/moon_gui/static/img/ajax-waiting.gif diff --git a/old/moon_gui/static/img/arrow-link.gif b/old/moon_gui/static/img/arrow-link.gif Binary files differnew file mode 100755 index 00000000..ca17f44b --- /dev/null +++ b/old/moon_gui/static/img/arrow-link.gif diff --git a/old/moon_gui/static/img/et.jpg b/old/moon_gui/static/img/et.jpg Binary files differnew file mode 100644 index 00000000..67cc0a9d --- /dev/null +++ b/old/moon_gui/static/img/et.jpg diff --git a/old/moon_gui/static/img/logo-openstack.png b/old/moon_gui/static/img/logo-openstack.png Binary files differnew file mode 100755 index 00000000..60ab0e1e --- /dev/null +++ b/old/moon_gui/static/img/logo-openstack.png diff --git a/old/moon_gui/static/img/logo-orange.gif b/old/moon_gui/static/img/logo-orange.gif Binary files differnew file mode 100755 index 00000000..9c612291 --- /dev/null +++ b/old/moon_gui/static/img/logo-orange.gif 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 Binary files differnew file mode 100644 index 00000000..c71415c0 --- /dev/null +++ b/old/tools/moon_jenkins/images/Create Multibranch Pipeline.png diff --git a/old/tools/moon_jenkins/images/Git Source Multibranch Pipeline.png b/old/tools/moon_jenkins/images/Git Source Multibranch Pipeline.png Binary files differnew file mode 100644 index 00000000..dd37f217 --- /dev/null +++ b/old/tools/moon_jenkins/images/Git Source Multibranch Pipeline.png diff --git a/old/tools/moon_jenkins/images/Multibranch Pipeline Log.png b/old/tools/moon_jenkins/images/Multibranch Pipeline Log.png Binary files differnew file mode 100644 index 00000000..a1905934 --- /dev/null +++ b/old/tools/moon_jenkins/images/Multibranch Pipeline Log.png diff --git a/old/tools/moon_jenkins/images/Select Source Multibranch Pipeline.png b/old/tools/moon_jenkins/images/Select Source Multibranch Pipeline.png Binary files differnew file mode 100644 index 00000000..eadbe916 --- /dev/null +++ b/old/tools/moon_jenkins/images/Select Source Multibranch Pipeline.png 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" +} |