diff --git a/gecoscc/api/__init__.py b/gecoscc/api/__init__.py index c737af1f..b6c82ff1 100644 --- a/gecoscc/api/__init__.py +++ b/gecoscc/api/__init__.py @@ -28,13 +28,13 @@ from gecoscc.tasks import object_created, object_changed, object_deleted, object_moved from gecoscc.utils import (get_computer_of_user, get_filter_nodes_parents_ou, oids_filter, check_unique_node_name_by_type_at_domain, - visibility_object_related, visibility_group) - + visibility_object_related, visibility_group, + RESOURCES_EMITTERS_TYPES, get_object_related_list) from gecoscc.i18n import gettext as _ - + import logging logger = logging.getLogger(__name__) - + SAFE_METHODS = ('GET', 'OPTIONS', 'HEAD',) UNSAFE_METHODS = ('POST', 'PUT', 'PATCH', 'DELETE', ) SCHEMA_METHODS = ('POST', 'PUT', ) @@ -179,8 +179,15 @@ def get(self): node = self.collection.find_one(collection_filter) if not node: raise HTTPNotFound() + node = self.parse_item(node) + if node.get('type', None) in RESOURCES_EMITTERS_TYPES: + node['is_assigned'] = self.is_assigned(node) + return node + return node - return self.parse_item(node) + def is_assigned(self, related_object): + node_with_related_object = get_object_related_list(self.request.db, related_object) + return bool(node_with_related_object.count()) class ResourcePaginated(ResourcePaginatedReadOnly): @@ -202,7 +209,7 @@ def integrity_validation(self, obj, real_obj=None): def pre_save(self, obj, old_obj=None): if old_obj and 'name' in old_obj: obj['name'] = old_obj['name'] - + # Check he policies "object_related_list" attribute if 'policies' in obj: policies = obj['policies'] @@ -210,9 +217,9 @@ def pre_save(self, obj, old_obj=None): # Get the policy policyobj = self.request.db.policies.find_one({"_id": ObjectId(str(policy))}) if policyobj is None: - logger.warning("Unknown policy: %s"%(str(policy))) + logger.warning("Unknown policy: %s" % (str(policy))) else: - # Get the related object collection + # Get the related object collection ro_collection = None if policyobj['slug'] == 'printer_can_view': ro_collection = self.request.db.nodes @@ -225,22 +232,21 @@ def pre_save(self, obj, old_obj=None): elif policyobj['slug'] == 'package_profile_res': ro_collection = self.request.db.software_profiles else: - logger.warning("Unrecognized slug: %s"%(str(policyobj['slug']))) - + logger.warning("Unrecognized slug: %s" % (str(policyobj['slug']))) + # Check the related objects if ro_collection is not None: ro_list = policies[str(policy)]['object_related_list'] for ro_id in ro_list: ro_obj = ro_collection.find_one({"_id": ObjectId(str(ro_id))}) if ro_obj is None: - logger.error("Can't find related object: %s:%s"%(str(policyobj['slug']), str(ro_id))) - self.request.errors.add('body', 'object', "Can't find related object: %s:%s"%(str(policyobj['slug']), str(ro_id))) + logger.error("Can't find related object: %s:%s" % (str(policyobj['slug']), str(ro_id))) + self.request.errors.add('body', 'object', "Can't find related object: %s:%s" % (str(policyobj['slug']), str(ro_id))) return None - - + else: logger.debug("No policies in this object") - + return obj def post_save(self, obj, old_obj=None): @@ -386,9 +392,8 @@ class TreeResourcePaginated(ResourcePaginated): def check_unique_node_name_by_type_at_domain(self, obj): unique = check_unique_node_name_by_type_at_domain(self.request.db.nodes, obj) if not unique: - self.request.errors.add( - 'body', 'name', - "Name must be unique in domain.") + self.request.errors.add('body', 'name', + "Name must be unique in domain.") return unique def integrity_validation(self, obj, real_obj=None): @@ -446,24 +451,28 @@ def check_memberof_integrity(self, obj): return False return True - def check_policies_integrity(self, obj): + def check_policies_integrity(self, obj, is_moved=False): """ Check if the policie is out of scope """ obj_original = deepcopy(obj) visibility_object_related(self.request.db, obj) - if obj != obj_original: - self.request.errors.add(unicode(obj[self.key]), 'policies', - "The related object is out of scope") - return False + if not is_moved: + if obj != obj_original: + self.request.errors.add(unicode(obj[self.key]), 'policies', + "The related object is out of scope") + return False return True def integrity_validation(self, obj, real_obj=None): result = super(TreeLeafResourcePaginated, self).integrity_validation( obj, real_obj) result = result and self.check_memberof_integrity(obj) - result = result and self.check_policies_integrity(obj) result = result and self.check_unique_node_name_by_type_at_domain(obj) + if real_obj is not None and real_obj['path'] == obj['path']: + result = result and self.check_policies_integrity(obj) + else: + result = result and self.check_policies_integrity(obj, is_moved=True) return result def computers_to_group(self, obj): @@ -527,3 +536,37 @@ def get_objects_filter(self): filters.append({'path': get_filter_nodes_parents_ou(self.request.db, ou_id, item_id)}) return filters + + def check_obj_is_related(self, obj): + ''' + Check if the emitter object is related with any object + ''' + if obj.get('_id'): + if obj['type'] == 'printer': + slug = 'printer_can_view' + elif obj['type'] == 'repository': + slug = 'repository_can_view' + elif obj['type'] == 'storage': + slug = 'storage_can_view' + elif obj['type'] == 'group': + members_group = obj['members'] + if not members_group: + return True + return False + + policy_id = self.request.db.policies.find_one({'slug': slug}).get('_id') + nodes_related_with_obj = self.request.db.nodes.find({"policies.%s.object_related_list" + % unicode(policy_id): {'$in': [unicode(obj['_id'])]}}) + + if nodes_related_with_obj.count() == 0: + return True + + return False + return True + + def integrity_validation(self, obj, real_obj=None): + result = super(PassiveResourcePaginated, self).integrity_validation( + obj, real_obj) + result = result and (self.request.user.get('is_superuser', False) or self.check_obj_is_related(obj)) + + return result diff --git a/gecoscc/api/organisationalunits.py b/gecoscc/api/organisationalunits.py index 96499213..cc49b7b4 100644 --- a/gecoscc/api/organisationalunits.py +++ b/gecoscc/api/organisationalunits.py @@ -36,17 +36,23 @@ class OrganisationalUnitResource(TreeResourcePaginated): def integrity_validation(self, obj, real_obj=None): status = super(OrganisationalUnitResource, self).integrity_validation(obj, real_obj) - if (real_obj is not None and obj['path'] != real_obj['path']): - # Check if the ou is moving to self depth, that is not correct. - if obj['path'] in real_obj['path']: - self.request.errors.add( - obj[self.key], 'path', - "the ou is moving to self depth position, " - "that is not allowed") - return False - status = status and self.check_unique_node_name_by_type_at_domain(obj) + + if real_obj is not None and obj['path'] != real_obj['path']: + status_user = self.request.user.get('is_superuser', False) or self.is_ou_empty(obj) + status = status and status_user return status + def is_ou_empty(self, obj): + ''' + Check if the Ou contains any object + ''' + ou_children = self.collection.find({'path': {'$regex': '.*' + unicode(obj['_id']) + '.*'}}).count() + + if ou_children == 0: + return True + else: + return False + def post_save(self, obj, old_obj=None): """ Check if path has changed to refresh children nodes """ if (self.request.method == 'PUT' and old_obj and diff --git a/gecoscc/api/printer_models.py b/gecoscc/api/printer_models.py index 43bdb7c4..e23cc2e1 100644 --- a/gecoscc/api/printer_models.py +++ b/gecoscc/api/printer_models.py @@ -36,7 +36,7 @@ def get_distinct_filter(self, objects): if self.request.GET.get('manufacturers_list'): objects = objects.distinct('manufacturer') objects.sort() - objects = [{'manufacturer':m, 'model':''} for m in objects] + objects = [{'manufacturer': m, 'model': ''} for m in objects] return objects def set_name_filter(self, query, key_name='manufacturer'): diff --git a/gecoscc/locale/en/LC_MESSAGES/gecoscc.mo b/gecoscc/locale/en/LC_MESSAGES/gecoscc.mo index d0ad1563..e6a805a3 100644 Binary files a/gecoscc/locale/en/LC_MESSAGES/gecoscc.mo and b/gecoscc/locale/en/LC_MESSAGES/gecoscc.mo differ diff --git a/gecoscc/locale/en/LC_MESSAGES/gecoscc.po b/gecoscc/locale/en/LC_MESSAGES/gecoscc.po index eecfb339..2d7b4869 100644 --- a/gecoscc/locale/en/LC_MESSAGES/gecoscc.po +++ b/gecoscc/locale/en/LC_MESSAGES/gecoscc.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: gecoscc 0.2.2\n" "Report-Msgid-Bugs-To: gecos@guadalinex.org\n" -"POT-Creation-Date: 2015-11-18 12:08+0100\n" +"POT-Creation-Date: 2015-12-14 09:02+0100\n" "PO-Revision-Date: 2014-03-19 11:03+0100\n" "Last-Translator: FULL NAME \n" "Language-Team: en \n" @@ -72,200 +72,200 @@ msgstr "" msgid "Type" msgstr "" -#: gecoscc/models.py:229 gecoscc/templates/bb-user.html:40 +#: gecoscc/models.py:230 gecoscc/templates/bb-user.html:40 #: gecoscc/templates/admins/list.jinja2:33 gecoscc/views/reports.py:80 msgid "First name" msgstr "" -#: gecoscc/models.py:233 gecoscc/templates/bb-user.html:44 +#: gecoscc/models.py:234 gecoscc/templates/bb-user.html:44 #: gecoscc/templates/admins/list.jinja2:34 gecoscc/views/reports.py:81 msgid "Last name" msgstr "" -#: gecoscc/models.py:326 gecoscc/templates/bb-user.html:36 +#: gecoscc/models.py:327 gecoscc/templates/bb-user.html:36 #: gecoscc/templates/login.jinja2:26 gecoscc/templates/admins/list.jinja2:31 #: gecoscc/views/reports.py:79 msgid "Username" msgstr "" -#: gecoscc/models.py:332 gecoscc/templates/login.jinja2:29 +#: gecoscc/models.py:333 gecoscc/templates/login.jinja2:29 msgid "Password" msgstr "" -#: gecoscc/models.py:337 +#: gecoscc/models.py:338 msgid "Repeat the password" msgstr "" -#: gecoscc/models.py:341 gecoscc/templates/bb-user.html:50 +#: gecoscc/models.py:342 gecoscc/templates/bb-user.html:50 #: gecoscc/views/reports.py:82 msgid "Email" msgstr "" -#: gecoscc/models.py:348 +#: gecoscc/models.py:349 msgid "There is a user with this email: ${val}" msgstr "" -#: gecoscc/models.py:349 +#: gecoscc/models.py:350 msgid "There is a user with this username: ${val}" msgstr "" -#: gecoscc/models.py:354 +#: gecoscc/models.py:355 msgid "This user can register workstation under these Organitation Units" msgstr "" -#: gecoscc/models.py:357 +#: gecoscc/models.py:358 msgid "Organitation Unit availables to register workstations by this user" msgstr "" -#: gecoscc/models.py:367 +#: gecoscc/models.py:368 msgid "uri" msgstr "" -#: gecoscc/models.py:370 +#: gecoscc/models.py:371 msgid "base" msgstr "" -#: gecoscc/models.py:373 +#: gecoscc/models.py:374 msgid "base group" msgstr "" -#: gecoscc/models.py:376 +#: gecoscc/models.py:377 msgid "binddn" msgstr "" -#: gecoscc/models.py:379 +#: gecoscc/models.py:380 msgid "bindpwd" msgstr "" -#: gecoscc/models.py:385 +#: gecoscc/models.py:386 msgid "FQDN" msgstr "" -#: gecoscc/models.py:387 +#: gecoscc/models.py:388 msgid "WORKGROUP" msgstr "" -#: gecoscc/models.py:393 +#: gecoscc/models.py:394 msgid "SSSD conf" msgstr "" -#: gecoscc/models.py:396 +#: gecoscc/models.py:397 msgid "KRB5 conf" msgstr "" -#: gecoscc/models.py:399 +#: gecoscc/models.py:400 msgid "SMB conf" msgstr "" -#: gecoscc/models.py:402 +#: gecoscc/models.py:403 msgid "PAM conf" msgstr "" -#: gecoscc/models.py:411 +#: gecoscc/models.py:412 msgid "URI ntp" msgstr "" -#: gecoscc/models.py:413 +#: gecoscc/models.py:414 msgid "Auth type" msgstr "" -#: gecoscc/models.py:417 +#: gecoscc/models.py:418 msgid "Specific conf" msgstr "" -#: gecoscc/models.py:419 +#: gecoscc/models.py:420 msgid "Auth LDAP" msgstr "" -#: gecoscc/models.py:420 gecoscc/models.py:421 +#: gecoscc/models.py:421 gecoscc/models.py:422 msgid "Auth Active directory" msgstr "" -#: gecoscc/models.py:461 gecoscc/templates/bb-computer.html:59 +#: gecoscc/models.py:462 gecoscc/templates/bb-computer.html:59 msgid "Desktop" msgstr "" -#: gecoscc/models.py:462 gecoscc/templates/bb-computer.html:60 +#: gecoscc/models.py:463 gecoscc/templates/bb-computer.html:60 msgid "Laptop" msgstr "" -#: gecoscc/models.py:463 gecoscc/templates/bb-computer.html:61 +#: gecoscc/models.py:464 gecoscc/templates/bb-computer.html:61 msgid "Netbook" msgstr "" -#: gecoscc/models.py:464 gecoscc/templates/bb-computer.html:62 +#: gecoscc/models.py:465 gecoscc/templates/bb-computer.html:62 msgid "Tablet" msgstr "" -#: gecoscc/models.py:500 gecoscc/templates/bb-printer.html:69 +#: gecoscc/models.py:501 gecoscc/templates/bb-printer.html:69 msgid "Laser" msgstr "" -#: gecoscc/models.py:501 gecoscc/templates/bb-printer.html:70 +#: gecoscc/models.py:502 gecoscc/templates/bb-printer.html:70 msgid "Ink" msgstr "" -#: gecoscc/models.py:502 gecoscc/templates/bb-printer.html:71 +#: gecoscc/models.py:503 gecoscc/templates/bb-printer.html:71 msgid "Dot matrix" msgstr "" -#: gecoscc/models.py:506 gecoscc/templates/bb-printer.html:35 +#: gecoscc/models.py:507 gecoscc/templates/bb-printer.html:35 msgid "Network" msgstr "" -#: gecoscc/models.py:507 gecoscc/templates/bb-printer.html:36 +#: gecoscc/models.py:508 gecoscc/templates/bb-printer.html:36 msgid "Local" msgstr "" -#: gecoscc/models.py:511 gecoscc/templates/bb-printer.html:52 +#: gecoscc/models.py:512 gecoscc/templates/bb-printer.html:52 msgid "Default" msgstr "" -#: gecoscc/models.py:512 gecoscc/templates/bb-printer.html:53 +#: gecoscc/models.py:513 gecoscc/templates/bb-printer.html:53 msgid "Authenticated" msgstr "" -#: gecoscc/models.py:557 +#: gecoscc/models.py:558 msgid "FTP" msgstr "" -#: gecoscc/models.py:558 +#: gecoscc/models.py:559 msgid "SSHFS" msgstr "" -#: gecoscc/models.py:559 +#: gecoscc/models.py:560 msgid "NFS" msgstr "" -#: gecoscc/models.py:560 +#: gecoscc/models.py:561 msgid "SAMBA v3" msgstr "" -#: gecoscc/models.py:561 +#: gecoscc/models.py:562 msgid "SAMBA v4" msgstr "" -#: gecoscc/models.py:565 +#: gecoscc/models.py:566 msgid "System mounts (fstab)" msgstr "" -#: gecoscc/models.py:566 +#: gecoscc/models.py:567 msgid "User space mounts (gvfs)" msgstr "" -#: gecoscc/models.py:597 +#: gecoscc/models.py:598 msgid "Processing" msgstr "" -#: gecoscc/models.py:600 +#: gecoscc/models.py:601 msgid "Applying changes" msgstr "" -#: gecoscc/models.py:603 +#: gecoscc/models.py:604 msgid "Changes applied" msgstr "" -#: gecoscc/models.py:606 gecoscc/models.py:609 +#: gecoscc/models.py:607 gecoscc/models.py:610 msgid "There were errors" msgstr "" @@ -368,7 +368,25 @@ msgstr "" msgid "Search" msgstr "" -#: gecoscc/templates/base_tree.jinja2:206 gecoscc/templates/bb-computer.html:93 +#: gecoscc/templates/base_tree.jinja2:136 +msgid "This action requires a little time" +msgstr "" + +#: gecoscc/templates/base_tree.jinja2:139 +msgid "Is the website maintenance?" +msgstr "" + +#: gecoscc/templates/base_tree.jinja2:142 +#: gecoscc/templates/admins/list.jinja2:49 +msgid "No" +msgstr "" + +#: gecoscc/templates/base_tree.jinja2:143 +#: gecoscc/templates/admins/list.jinja2:47 +msgid "Yes" +msgstr "" + +#: gecoscc/templates/base_tree.jinja2:224 gecoscc/templates/bb-computer.html:93 #: gecoscc/templates/bb-groups-form.html:27 gecoscc/templates/bb-user.html:74 msgid "Loading" msgstr "" @@ -525,7 +543,11 @@ msgstr "" msgid "Save" msgstr "" -#: gecoscc/templates/bb-computer.html:111 gecoscc/templates/bb-user.html:91 +#: gecoscc/templates/bb-computer.html:111 +#: gecoscc/templates/bb-groups-form.html:37 gecoscc/templates/bb-ou.html:62 +#: gecoscc/templates/bb-printer.html:108 +#: gecoscc/templates/bb-repository.html:72 gecoscc/templates/bb-storage.html:30 +#: gecoscc/templates/bb-user.html:91 msgid "Cut" msgstr "" @@ -579,7 +601,7 @@ msgid "Data retrieved from workstation" msgstr "" #: gecoscc/templates/bb-computer.html:202 -#: gecoscc/templates/bb-groups-form.html:48 gecoscc/templates/bb-ou.html:73 +#: gecoscc/templates/bb-groups-form.html:49 gecoscc/templates/bb-ou.html:74 #: gecoscc/templates/bb-user.html:103 msgid "Policies list" msgstr "" @@ -1034,14 +1056,6 @@ msgstr "" msgid "Is superuser?" msgstr "" -#: gecoscc/templates/admins/list.jinja2:47 -msgid "Yes" -msgstr "" - -#: gecoscc/templates/admins/list.jinja2:49 -msgid "No" -msgstr "" - #: gecoscc/templates/admins/ou_manage.jinja2:52 msgid "Select an Organisational Unit" msgstr "" diff --git a/gecoscc/locale/en/LC_MESSAGES/gecoscc_js.mo b/gecoscc/locale/en/LC_MESSAGES/gecoscc_js.mo index 483007bd..356fcd09 100644 Binary files a/gecoscc/locale/en/LC_MESSAGES/gecoscc_js.mo and b/gecoscc/locale/en/LC_MESSAGES/gecoscc_js.mo differ diff --git a/gecoscc/locale/en/LC_MESSAGES/gecoscc_js.po b/gecoscc/locale/en/LC_MESSAGES/gecoscc_js.po index 2a814a7c..4b8e3422 100644 --- a/gecoscc/locale/en/LC_MESSAGES/gecoscc_js.po +++ b/gecoscc/locale/en/LC_MESSAGES/gecoscc_js.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: gecoscc 0.2.2\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2015-11-18 12:08+0100\n" +"POT-Creation-Date: 2015-12-14 09:02+0100\n" "PO-Revision-Date: 2014-03-19 11:03+0100\n" "Last-Translator: FULL NAME \n" "Language-Team: en \n" @@ -85,6 +85,10 @@ msgstr "" msgid "Please, fix the errors in the fields below and try again." msgstr "" +#: gecoscc/static/js/app-utils.js:422 gecoscc/static/js/ou.js:81 +msgid "Only the super admin can cut this object" +msgstr "" + #: gecoscc/static/js/app.js:322 msgid "New element" msgstr "" diff --git a/gecoscc/locale/es/LC_MESSAGES/gecoscc.mo b/gecoscc/locale/es/LC_MESSAGES/gecoscc.mo index 7f92ebb6..afdab1c7 100644 Binary files a/gecoscc/locale/es/LC_MESSAGES/gecoscc.mo and b/gecoscc/locale/es/LC_MESSAGES/gecoscc.mo differ diff --git a/gecoscc/locale/es/LC_MESSAGES/gecoscc.po b/gecoscc/locale/es/LC_MESSAGES/gecoscc.po index 0430d33f..8be0e0f4 100644 --- a/gecoscc/locale/es/LC_MESSAGES/gecoscc.po +++ b/gecoscc/locale/es/LC_MESSAGES/gecoscc.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gecoscc 0.0\n" "Report-Msgid-Bugs-To: pmartin@yaco.es\n" -"POT-Creation-Date: 2015-11-18 12:08+0100\n" +"POT-Creation-Date: 2015-12-14 09:02+0100\n" "PO-Revision-Date: 2013-11-14 10:24+0100\n" "Last-Translator: Alejandro Blanco \n" "Language-Team: es \n" @@ -71,204 +71,204 @@ msgstr "Valor" msgid "Type" msgstr "Tipo" -#: gecoscc/models.py:229 gecoscc/templates/bb-user.html:40 +#: gecoscc/models.py:230 gecoscc/templates/bb-user.html:40 #: gecoscc/templates/admins/list.jinja2:33 gecoscc/views/reports.py:80 msgid "First name" msgstr "Nombre" -#: gecoscc/models.py:233 gecoscc/templates/bb-user.html:44 +#: gecoscc/models.py:234 gecoscc/templates/bb-user.html:44 #: gecoscc/templates/admins/list.jinja2:34 gecoscc/views/reports.py:81 msgid "Last name" msgstr "Apellidos" -#: gecoscc/models.py:326 gecoscc/templates/bb-user.html:36 +#: gecoscc/models.py:327 gecoscc/templates/bb-user.html:36 #: gecoscc/templates/login.jinja2:26 gecoscc/templates/admins/list.jinja2:31 #: gecoscc/views/reports.py:79 msgid "Username" msgstr "Nombre de usuario" -#: gecoscc/models.py:332 gecoscc/templates/login.jinja2:29 +#: gecoscc/models.py:333 gecoscc/templates/login.jinja2:29 msgid "Password" msgstr "Contraseña" -#: gecoscc/models.py:337 +#: gecoscc/models.py:338 msgid "Repeat the password" msgstr "Repite la contraseña" -#: gecoscc/models.py:341 gecoscc/templates/bb-user.html:50 +#: gecoscc/models.py:342 gecoscc/templates/bb-user.html:50 #: gecoscc/views/reports.py:82 msgid "Email" msgstr "Correo electrónico" -#: gecoscc/models.py:348 +#: gecoscc/models.py:349 msgid "There is a user with this email: ${val}" msgstr "Hay un usuario con este correo electrónico: ${val}" -#: gecoscc/models.py:349 +#: gecoscc/models.py:350 msgid "There is a user with this username: ${val}" msgstr "Hay un usuario con este nombre de usuario: ${val}" -#: gecoscc/models.py:354 +#: gecoscc/models.py:355 msgid "This user can register workstation under these Organitation Units" msgstr "" "Este usuario puede registrar estaciones de trabajo bajo estas unidades " "organizativas" -#: gecoscc/models.py:357 +#: gecoscc/models.py:358 msgid "Organitation Unit availables to register workstations by this user" msgstr "" "Unidades organizativas disponibles para que este usuario pueda registrar " "estaciones de trabajo" -#: gecoscc/models.py:367 +#: gecoscc/models.py:368 msgid "uri" msgstr "uri" -#: gecoscc/models.py:370 +#: gecoscc/models.py:371 msgid "base" msgstr "" -#: gecoscc/models.py:373 +#: gecoscc/models.py:374 msgid "base group" msgstr "" -#: gecoscc/models.py:376 +#: gecoscc/models.py:377 msgid "binddn" msgstr "" -#: gecoscc/models.py:379 +#: gecoscc/models.py:380 msgid "bindpwd" msgstr "" -#: gecoscc/models.py:385 +#: gecoscc/models.py:386 msgid "FQDN" msgstr "" -#: gecoscc/models.py:387 +#: gecoscc/models.py:388 msgid "WORKGROUP" msgstr "" -#: gecoscc/models.py:393 +#: gecoscc/models.py:394 msgid "SSSD conf" msgstr "" -#: gecoscc/models.py:396 +#: gecoscc/models.py:397 msgid "KRB5 conf" msgstr "" -#: gecoscc/models.py:399 +#: gecoscc/models.py:400 msgid "SMB conf" msgstr "" -#: gecoscc/models.py:402 +#: gecoscc/models.py:403 msgid "PAM conf" msgstr "" -#: gecoscc/models.py:411 +#: gecoscc/models.py:412 msgid "URI ntp" msgstr "" -#: gecoscc/models.py:413 +#: gecoscc/models.py:414 msgid "Auth type" msgstr "Tipo de autenticación" -#: gecoscc/models.py:417 +#: gecoscc/models.py:418 msgid "Specific conf" msgstr "Configuración específica" -#: gecoscc/models.py:419 +#: gecoscc/models.py:420 msgid "Auth LDAP" msgstr "Autenticación LDAP" -#: gecoscc/models.py:420 gecoscc/models.py:421 +#: gecoscc/models.py:421 gecoscc/models.py:422 msgid "Auth Active directory" msgstr "Autenticación Active directory" -#: gecoscc/models.py:461 gecoscc/templates/bb-computer.html:59 +#: gecoscc/models.py:462 gecoscc/templates/bb-computer.html:59 msgid "Desktop" msgstr "Sobremesa" -#: gecoscc/models.py:462 gecoscc/templates/bb-computer.html:60 +#: gecoscc/models.py:463 gecoscc/templates/bb-computer.html:60 msgid "Laptop" msgstr "Portátil" -#: gecoscc/models.py:463 gecoscc/templates/bb-computer.html:61 +#: gecoscc/models.py:464 gecoscc/templates/bb-computer.html:61 msgid "Netbook" msgstr "" -#: gecoscc/models.py:464 gecoscc/templates/bb-computer.html:62 +#: gecoscc/models.py:465 gecoscc/templates/bb-computer.html:62 msgid "Tablet" msgstr "Tableta" -#: gecoscc/models.py:500 gecoscc/templates/bb-printer.html:69 +#: gecoscc/models.py:501 gecoscc/templates/bb-printer.html:69 msgid "Laser" msgstr "Láser" -#: gecoscc/models.py:501 gecoscc/templates/bb-printer.html:70 +#: gecoscc/models.py:502 gecoscc/templates/bb-printer.html:70 msgid "Ink" msgstr "Tinta" -#: gecoscc/models.py:502 gecoscc/templates/bb-printer.html:71 +#: gecoscc/models.py:503 gecoscc/templates/bb-printer.html:71 msgid "Dot matrix" msgstr "Matricial" -#: gecoscc/models.py:506 gecoscc/templates/bb-printer.html:35 +#: gecoscc/models.py:507 gecoscc/templates/bb-printer.html:35 msgid "Network" msgstr "En red" -#: gecoscc/models.py:507 gecoscc/templates/bb-printer.html:36 +#: gecoscc/models.py:508 gecoscc/templates/bb-printer.html:36 msgid "Local" msgstr "Local" -#: gecoscc/models.py:511 gecoscc/templates/bb-printer.html:52 +#: gecoscc/models.py:512 gecoscc/templates/bb-printer.html:52 msgid "Default" msgstr "" -#: gecoscc/models.py:512 gecoscc/templates/bb-printer.html:53 +#: gecoscc/models.py:513 gecoscc/templates/bb-printer.html:53 msgid "Authenticated" msgstr "" -#: gecoscc/models.py:557 +#: gecoscc/models.py:558 msgid "FTP" msgstr "" -#: gecoscc/models.py:558 +#: gecoscc/models.py:559 msgid "SSHFS" msgstr "" -#: gecoscc/models.py:559 +#: gecoscc/models.py:560 msgid "NFS" msgstr "" -#: gecoscc/models.py:560 +#: gecoscc/models.py:561 msgid "SAMBA v3" msgstr "" -#: gecoscc/models.py:561 +#: gecoscc/models.py:562 msgid "SAMBA v4" msgstr "" -#: gecoscc/models.py:565 +#: gecoscc/models.py:566 msgid "System mounts (fstab)" msgstr "En el arranque del sistema (fstab)" -#: gecoscc/models.py:566 +#: gecoscc/models.py:567 msgid "User space mounts (gvfs)" msgstr "En espacio de usuario (gvfs)" -#: gecoscc/models.py:597 +#: gecoscc/models.py:598 msgid "Processing" msgstr "Procesando" -#: gecoscc/models.py:600 +#: gecoscc/models.py:601 msgid "Applying changes" msgstr "Aplicando cambios" -#: gecoscc/models.py:603 +#: gecoscc/models.py:604 msgid "Changes applied" msgstr "Cambios aplicados" -#: gecoscc/models.py:606 gecoscc/models.py:609 +#: gecoscc/models.py:607 gecoscc/models.py:610 msgid "There were errors" msgstr "Se produjeron errores" @@ -371,7 +371,25 @@ msgstr "Salir" msgid "Search" msgstr "Buscar" -#: gecoscc/templates/base_tree.jinja2:206 gecoscc/templates/bb-computer.html:93 +#: gecoscc/templates/base_tree.jinja2:136 +msgid "This action requires a little time" +msgstr "Esta acción puede llevar un tiempo" + +#: gecoscc/templates/base_tree.jinja2:139 +msgid "Is the website maintenance?" +msgstr "¿Esta el portal en mantenimiento?" + +#: gecoscc/templates/base_tree.jinja2:142 +#: gecoscc/templates/admins/list.jinja2:49 +msgid "No" +msgstr "" + +#: gecoscc/templates/base_tree.jinja2:143 +#: gecoscc/templates/admins/list.jinja2:47 +msgid "Yes" +msgstr "Si" + +#: gecoscc/templates/base_tree.jinja2:224 gecoscc/templates/bb-computer.html:93 #: gecoscc/templates/bb-groups-form.html:27 gecoscc/templates/bb-user.html:74 msgid "Loading" msgstr "Cargando" @@ -530,7 +548,11 @@ msgstr "Si tu quieres añadir un grupo, por favor encola los cambios" msgid "Save" msgstr "Guardar" -#: gecoscc/templates/bb-computer.html:111 gecoscc/templates/bb-user.html:91 +#: gecoscc/templates/bb-computer.html:111 +#: gecoscc/templates/bb-groups-form.html:37 gecoscc/templates/bb-ou.html:62 +#: gecoscc/templates/bb-printer.html:108 +#: gecoscc/templates/bb-repository.html:72 gecoscc/templates/bb-storage.html:30 +#: gecoscc/templates/bb-user.html:91 msgid "Cut" msgstr "Cortar" @@ -584,7 +606,7 @@ msgid "Data retrieved from workstation" msgstr "Datos extraidos del puesto" #: gecoscc/templates/bb-computer.html:202 -#: gecoscc/templates/bb-groups-form.html:48 gecoscc/templates/bb-ou.html:73 +#: gecoscc/templates/bb-groups-form.html:49 gecoscc/templates/bb-ou.html:74 #: gecoscc/templates/bb-user.html:103 msgid "Policies list" msgstr "Lista de políticas" @@ -1041,14 +1063,6 @@ msgstr "Correo electrónico" msgid "Is superuser?" msgstr "¿Es superusuario?" -#: gecoscc/templates/admins/list.jinja2:47 -msgid "Yes" -msgstr "Si" - -#: gecoscc/templates/admins/list.jinja2:49 -msgid "No" -msgstr "" - #: gecoscc/templates/admins/ou_manage.jinja2:52 msgid "Select an Organisational Unit" msgstr "Selecciona una Unidad Organizativa" diff --git a/gecoscc/locale/es/LC_MESSAGES/gecoscc_js.mo b/gecoscc/locale/es/LC_MESSAGES/gecoscc_js.mo index efa668e7..09b205e5 100644 Binary files a/gecoscc/locale/es/LC_MESSAGES/gecoscc_js.mo and b/gecoscc/locale/es/LC_MESSAGES/gecoscc_js.mo differ diff --git a/gecoscc/locale/es/LC_MESSAGES/gecoscc_js.po b/gecoscc/locale/es/LC_MESSAGES/gecoscc_js.po index f5852174..77cf199b 100644 --- a/gecoscc/locale/es/LC_MESSAGES/gecoscc_js.po +++ b/gecoscc/locale/es/LC_MESSAGES/gecoscc_js.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: gecoscc 0.2.1\n" "Report-Msgid-Bugs-To: gecos@guadalinex.org\n" -"POT-Creation-Date: 2015-11-18 12:08+0100\n" +"POT-Creation-Date: 2015-12-14 09:02+0100\n" "PO-Revision-Date: 2014-03-07 13:25+0100\n" "Last-Translator: Alejandro Blanco \n" "Language-Team: es \n" @@ -86,6 +86,10 @@ msgstr "Datos inválidos." msgid "Please, fix the errors in the fields below and try again." msgstr "Por favor, corrija los errores mostrados abajo y pruebe de nuevo." +#: gecoscc/static/js/app-utils.js:422 gecoscc/static/js/ou.js:81 +msgid "Only the super admin can cut this object" +msgstr "Solo el super administrador puede cortar este objeto" + #: gecoscc/static/js/app.js:322 msgid "New element" msgstr "Nuevo elemento" diff --git a/gecoscc/locale/gecoscc.pot b/gecoscc/locale/gecoscc.pot index 0d4c40b9..5b6f88c6 100644 --- a/gecoscc/locale/gecoscc.pot +++ b/gecoscc/locale/gecoscc.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: gecoscc 2.1.10\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2015-11-18 12:08+0100\n" +"POT-Creation-Date: 2015-12-14 09:02+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -72,200 +72,200 @@ msgstr "" msgid "Type" msgstr "" -#: gecoscc/models.py:229 gecoscc/templates/bb-user.html:40 +#: gecoscc/models.py:230 gecoscc/templates/bb-user.html:40 #: gecoscc/templates/admins/list.jinja2:33 gecoscc/views/reports.py:80 msgid "First name" msgstr "" -#: gecoscc/models.py:233 gecoscc/templates/bb-user.html:44 +#: gecoscc/models.py:234 gecoscc/templates/bb-user.html:44 #: gecoscc/templates/admins/list.jinja2:34 gecoscc/views/reports.py:81 msgid "Last name" msgstr "" -#: gecoscc/models.py:326 gecoscc/templates/bb-user.html:36 +#: gecoscc/models.py:327 gecoscc/templates/bb-user.html:36 #: gecoscc/templates/login.jinja2:26 gecoscc/templates/admins/list.jinja2:31 #: gecoscc/views/reports.py:79 msgid "Username" msgstr "" -#: gecoscc/models.py:332 gecoscc/templates/login.jinja2:29 +#: gecoscc/models.py:333 gecoscc/templates/login.jinja2:29 msgid "Password" msgstr "" -#: gecoscc/models.py:337 +#: gecoscc/models.py:338 msgid "Repeat the password" msgstr "" -#: gecoscc/models.py:341 gecoscc/templates/bb-user.html:50 +#: gecoscc/models.py:342 gecoscc/templates/bb-user.html:50 #: gecoscc/views/reports.py:82 msgid "Email" msgstr "" -#: gecoscc/models.py:348 +#: gecoscc/models.py:349 msgid "There is a user with this email: ${val}" msgstr "" -#: gecoscc/models.py:349 +#: gecoscc/models.py:350 msgid "There is a user with this username: ${val}" msgstr "" -#: gecoscc/models.py:354 +#: gecoscc/models.py:355 msgid "This user can register workstation under these Organitation Units" msgstr "" -#: gecoscc/models.py:357 +#: gecoscc/models.py:358 msgid "Organitation Unit availables to register workstations by this user" msgstr "" -#: gecoscc/models.py:367 +#: gecoscc/models.py:368 msgid "uri" msgstr "" -#: gecoscc/models.py:370 +#: gecoscc/models.py:371 msgid "base" msgstr "" -#: gecoscc/models.py:373 +#: gecoscc/models.py:374 msgid "base group" msgstr "" -#: gecoscc/models.py:376 +#: gecoscc/models.py:377 msgid "binddn" msgstr "" -#: gecoscc/models.py:379 +#: gecoscc/models.py:380 msgid "bindpwd" msgstr "" -#: gecoscc/models.py:385 +#: gecoscc/models.py:386 msgid "FQDN" msgstr "" -#: gecoscc/models.py:387 +#: gecoscc/models.py:388 msgid "WORKGROUP" msgstr "" -#: gecoscc/models.py:393 +#: gecoscc/models.py:394 msgid "SSSD conf" msgstr "" -#: gecoscc/models.py:396 +#: gecoscc/models.py:397 msgid "KRB5 conf" msgstr "" -#: gecoscc/models.py:399 +#: gecoscc/models.py:400 msgid "SMB conf" msgstr "" -#: gecoscc/models.py:402 +#: gecoscc/models.py:403 msgid "PAM conf" msgstr "" -#: gecoscc/models.py:411 +#: gecoscc/models.py:412 msgid "URI ntp" msgstr "" -#: gecoscc/models.py:413 +#: gecoscc/models.py:414 msgid "Auth type" msgstr "" -#: gecoscc/models.py:417 +#: gecoscc/models.py:418 msgid "Specific conf" msgstr "" -#: gecoscc/models.py:419 +#: gecoscc/models.py:420 msgid "Auth LDAP" msgstr "" -#: gecoscc/models.py:420 gecoscc/models.py:421 +#: gecoscc/models.py:421 gecoscc/models.py:422 msgid "Auth Active directory" msgstr "" -#: gecoscc/models.py:461 gecoscc/templates/bb-computer.html:59 +#: gecoscc/models.py:462 gecoscc/templates/bb-computer.html:59 msgid "Desktop" msgstr "" -#: gecoscc/models.py:462 gecoscc/templates/bb-computer.html:60 +#: gecoscc/models.py:463 gecoscc/templates/bb-computer.html:60 msgid "Laptop" msgstr "" -#: gecoscc/models.py:463 gecoscc/templates/bb-computer.html:61 +#: gecoscc/models.py:464 gecoscc/templates/bb-computer.html:61 msgid "Netbook" msgstr "" -#: gecoscc/models.py:464 gecoscc/templates/bb-computer.html:62 +#: gecoscc/models.py:465 gecoscc/templates/bb-computer.html:62 msgid "Tablet" msgstr "" -#: gecoscc/models.py:500 gecoscc/templates/bb-printer.html:69 +#: gecoscc/models.py:501 gecoscc/templates/bb-printer.html:69 msgid "Laser" msgstr "" -#: gecoscc/models.py:501 gecoscc/templates/bb-printer.html:70 +#: gecoscc/models.py:502 gecoscc/templates/bb-printer.html:70 msgid "Ink" msgstr "" -#: gecoscc/models.py:502 gecoscc/templates/bb-printer.html:71 +#: gecoscc/models.py:503 gecoscc/templates/bb-printer.html:71 msgid "Dot matrix" msgstr "" -#: gecoscc/models.py:506 gecoscc/templates/bb-printer.html:35 +#: gecoscc/models.py:507 gecoscc/templates/bb-printer.html:35 msgid "Network" msgstr "" -#: gecoscc/models.py:507 gecoscc/templates/bb-printer.html:36 +#: gecoscc/models.py:508 gecoscc/templates/bb-printer.html:36 msgid "Local" msgstr "" -#: gecoscc/models.py:511 gecoscc/templates/bb-printer.html:52 +#: gecoscc/models.py:512 gecoscc/templates/bb-printer.html:52 msgid "Default" msgstr "" -#: gecoscc/models.py:512 gecoscc/templates/bb-printer.html:53 +#: gecoscc/models.py:513 gecoscc/templates/bb-printer.html:53 msgid "Authenticated" msgstr "" -#: gecoscc/models.py:557 +#: gecoscc/models.py:558 msgid "FTP" msgstr "" -#: gecoscc/models.py:558 +#: gecoscc/models.py:559 msgid "SSHFS" msgstr "" -#: gecoscc/models.py:559 +#: gecoscc/models.py:560 msgid "NFS" msgstr "" -#: gecoscc/models.py:560 +#: gecoscc/models.py:561 msgid "SAMBA v3" msgstr "" -#: gecoscc/models.py:561 +#: gecoscc/models.py:562 msgid "SAMBA v4" msgstr "" -#: gecoscc/models.py:565 +#: gecoscc/models.py:566 msgid "System mounts (fstab)" msgstr "" -#: gecoscc/models.py:566 +#: gecoscc/models.py:567 msgid "User space mounts (gvfs)" msgstr "" -#: gecoscc/models.py:597 +#: gecoscc/models.py:598 msgid "Processing" msgstr "" -#: gecoscc/models.py:600 +#: gecoscc/models.py:601 msgid "Applying changes" msgstr "" -#: gecoscc/models.py:603 +#: gecoscc/models.py:604 msgid "Changes applied" msgstr "" -#: gecoscc/models.py:606 gecoscc/models.py:609 +#: gecoscc/models.py:607 gecoscc/models.py:610 msgid "There were errors" msgstr "" @@ -363,7 +363,23 @@ msgstr "" msgid "Search" msgstr "" -#: gecoscc/templates/base_tree.jinja2:206 gecoscc/templates/bb-computer.html:93 +#: gecoscc/templates/base_tree.jinja2:136 +msgid "This action requires a little time" +msgstr "" + +#: gecoscc/templates/base_tree.jinja2:139 +msgid "Is the website maintenance?" +msgstr "" + +#: gecoscc/templates/base_tree.jinja2:142 gecoscc/templates/admins/list.jinja2:49 +msgid "No" +msgstr "" + +#: gecoscc/templates/base_tree.jinja2:143 gecoscc/templates/admins/list.jinja2:47 +msgid "Yes" +msgstr "" + +#: gecoscc/templates/base_tree.jinja2:224 gecoscc/templates/bb-computer.html:93 #: gecoscc/templates/bb-groups-form.html:27 gecoscc/templates/bb-user.html:74 msgid "Loading" msgstr "" @@ -512,7 +528,10 @@ msgstr "" msgid "Save" msgstr "" -#: gecoscc/templates/bb-computer.html:111 gecoscc/templates/bb-user.html:91 +#: gecoscc/templates/bb-computer.html:111 gecoscc/templates/bb-groups-form.html:37 +#: gecoscc/templates/bb-ou.html:62 gecoscc/templates/bb-printer.html:108 +#: gecoscc/templates/bb-repository.html:72 gecoscc/templates/bb-storage.html:30 +#: gecoscc/templates/bb-user.html:91 msgid "Cut" msgstr "" @@ -560,8 +579,8 @@ msgstr "" msgid "Data retrieved from workstation" msgstr "" -#: gecoscc/templates/bb-computer.html:202 gecoscc/templates/bb-groups-form.html:48 -#: gecoscc/templates/bb-ou.html:73 gecoscc/templates/bb-user.html:103 +#: gecoscc/templates/bb-computer.html:202 gecoscc/templates/bb-groups-form.html:49 +#: gecoscc/templates/bb-ou.html:74 gecoscc/templates/bb-user.html:103 msgid "Policies list" msgstr "" @@ -1010,14 +1029,6 @@ msgstr "" msgid "Is superuser?" msgstr "" -#: gecoscc/templates/admins/list.jinja2:47 -msgid "Yes" -msgstr "" - -#: gecoscc/templates/admins/list.jinja2:49 -msgid "No" -msgstr "" - #: gecoscc/templates/admins/ou_manage.jinja2:52 msgid "Select an Organisational Unit" msgstr "" diff --git a/gecoscc/locale/gecoscc_js.pot b/gecoscc/locale/gecoscc_js.pot index a5bb3e1d..501d045d 100644 --- a/gecoscc/locale/gecoscc_js.pot +++ b/gecoscc/locale/gecoscc_js.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: gecoscc 2.1.10\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2015-11-18 12:08+0100\n" +"POT-Creation-Date: 2015-12-14 09:02+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -84,6 +84,10 @@ msgstr "" msgid "Please, fix the errors in the fields below and try again." msgstr "" +#: gecoscc/static/js/app-utils.js:422 gecoscc/static/js/ou.js:81 +msgid "Only the super admin can cut this object" +msgstr "" + #: gecoscc/static/js/app.js:322 msgid "New element" msgstr "" diff --git a/gecoscc/models.py b/gecoscc/models.py index 69a6edae..05aea65f 100644 --- a/gecoscc/models.py +++ b/gecoscc/models.py @@ -212,17 +212,18 @@ class Groups(colander.SequenceSchema): class Setting(colander.MappingSchema): _id = colander.SchemaNode(ObjectIdField()) key = colander.SchemaNode(colander.String(), - title=_('Key'), - default='', - missing='') + title=_('Key'), + default='', + missing='') value = colander.SchemaNode(colander.String('UTF-8'), - title=_('Value'), - default='', - missing='') + title=_('Value'), + default='', + missing='') type = colander.SchemaNode(colander.String(), - title=_('Type'), - default='', - missing='') + title=_('Type'), + default='', + missing='') + class BaseUser(colander.MappingSchema): first_name = colander.SchemaNode(colander.String(), @@ -247,8 +248,8 @@ class User(Node, BaseUser): default='', missing='') commentaries = colander.SchemaNode(colander.String(), - default='', - missing='') + default='', + missing='') memberof = ObjectIdList(missing=[], default=[]) policies = colander.SchemaNode(colander.Mapping(unknown='preserve'), default={}, @@ -478,8 +479,8 @@ class Computer(Node): default='', missing='') commentaries = colander.SchemaNode(colander.String(), - default='', - missing='') + default='', + missing='') policies = colander.SchemaNode(colander.Mapping(unknown='preserve'), default={}, missing={}) diff --git a/gecoscc/static/css/scp-gecos.css b/gecoscc/static/css/scp-gecos.css index 513d0915..28853467 100644 --- a/gecoscc/static/css/scp-gecos.css +++ b/gecoscc/static/css/scp-gecos.css @@ -462,3 +462,8 @@ legend { .btn.refresh, .btn.archiveTasks { margin-right: 3px; } + +.no-admin-message{ + float: right; + margin-right: 85px; +} \ No newline at end of file diff --git a/gecoscc/static/js/app-utils.js b/gecoscc/static/js/app-utils.js index ab730895..ff4c7a4a 100644 --- a/gecoscc/static/js/app-utils.js +++ b/gecoscc/static/js/app-utils.js @@ -375,16 +375,77 @@ }, cutModel: function (evt) { - evt.preventDefault(); - var $button = $(evt.target); - $button.attr("disabled", "disabled"); - App.instances.cut = this.model; - App.instances.tree.trigger("change"); + var that = this; + var $button = $('#cut'); + evt.preventDefault(); + var cutModel = function(){ + var $button = $(evt.target); + $button.attr("disabled", "disabled"); + App.instances.cut = that.model; + App.instances.tree.trigger("change"); - setTimeout(function () { - $button.attr("disabled", false); - }, 2000); + setTimeout(function () { + $button.attr("disabled", false); + }, 2000); + }; + + if($button.hasClass('admin') && !App.instances.noMaintenance[this.model.get('id')]){ + var $modal = $('#maintenance-modal'); + $modal.modal('show'); + $('#set-maintenance').click(function(){ + cutModel(); + $modal.modal('hide'); + }); + }else{ + cutModel(); + } + + + + }, + canMove: function(){ + var $button = this.$('#cut'); + if(typeof App.instances.noMaintenance == 'undefined'){ + App.instances.noMaintenance = []; + } + if(typeof App.instances.refresh == 'undefined'){ + App.instances.refresh = {}; + } + var disable = function(){ + $button.removeClass('btn-warning'); + $button.addClass('btn-group'); + $button.removeAttr('id'); + $button.unbind('click'); + $button.css('margin-right','5px'); + $button.click(function(e){ + e.preventDefault(); + App.showAlert('warning',gettext('Only the super admin can cut this object')); + }); + }; + + if(this.model.get('type')=='group'){ + if($button.hasClass('admin')==false && this.model.get('members').length != 0){ + disable(); + App.instances.noMaintenance[this.model.get('id')] = false; + } + if($button.hasClass('admin')==true && this.model.get('members').length == 0){ + App.instances.noMaintenance[this.model.get('id')] = true; + } + } + if(this.model.get('type')=='storage' || this.model.get('type')=='printer' || this.model.get('type')=='repository'){ + if(App.instances.refresh[this.model.get('id')]){ + this.refresh(); + delete App.instances.refresh[this.model.get('id')]; + } + if($button.hasClass('admin')==false && this.model.get('is_assigned') == true){ + disable(); + App.instances.noMaintenance[this.model.get('id')] = false; + } + if($button.hasClass('admin')==true && this.model.get('is_assigned') == false){ + App.instances.noMaintenance[this.model.get('id')] = true; + } + } }, getDomainAttrs: function () { diff --git a/gecoscc/static/js/group-form-views.js b/gecoscc/static/js/group-form-views.js index 513ad3b4..a1dc4d46 100644 --- a/gecoscc/static/js/group-form-views.js +++ b/gecoscc/static/js/group-form-views.js @@ -49,7 +49,8 @@ App.module("Group.Views", function (Views, App, Backbone, Marionette, $, _) { "click button#delete": "deleteModel", "click button#save": "save", "click button.refresh": "refresh", - "click ul.pagination a": "goToPage" + "click ul.pagination a": "goToPage", + "click #cut": "cutModel" }, policiesList: undefined, @@ -140,6 +141,8 @@ App.module("Group.Views", function (Views, App, Backbone, Marionette, $, _) { }, onRender: function () { + this.canMove(); + if (!_.isUndefined(this.model.id)) { this.$el.find("#name").attr('disabled', 'disabled'); } diff --git a/gecoscc/static/js/ou.js b/gecoscc/static/js/ou.js index 72e90fdc..44494e61 100644 --- a/gecoscc/static/js/ou.js +++ b/gecoscc/static/js/ou.js @@ -49,14 +49,50 @@ App.module("OU.Views", function (Views, App, Backbone, Marionette, $, _) { "click #submit": "saveForm", "click #delete": "deleteModel", "change input": "validate", - "click button.refresh": "refresh" + "click button.refresh": "refresh", + "click #cut": "cutModel" }, policiesList: undefined, onBeforeRender: function () { + var that = this; var path = this.model.get("path"); + //CHECK IS EMPTY + if(typeof App.instances.noMaintenance == 'undefined'){ + App.instances.noMaintenance = []; + } + var id = this.model.get("id"); + + var page = new App.Tree.Models.Container({path:path+','+id}); + + page.goTo(1, { + success: function (data) { + var $button = $('#cut'); + if($button.hasClass('admin')==false && data.models.length != 0){ + $button.removeClass('btn-warning'); + $button.addClass('btn-group'); + $button.removeAttr('id'); + $button.unbind('click'); + $button.css('margin-right','5px'); + $button.click(function (e){ + e.preventDefault(); + App.showAlert('warning',gettext('Only the super admin can cut this object')); + }); + App.instances.noMaintenance[that.model.get('id')] = false; + + } + + if($button.hasClass('admin')==true && data.models.length == 0){ + App.instances.noMaintenance[that.model.get('id')] = true; + } + + + } + }); + //END CHECK IS EMPTY + if (this.model.get("isEditable") !== undefined) { return; } if (path === "root") { diff --git a/gecoscc/static/js/policies.js b/gecoscc/static/js/policies.js index 71de7f54..01cef2ca 100644 --- a/gecoscc/static/js/policies.js +++ b/gecoscc/static/js/policies.js @@ -77,7 +77,18 @@ App.module("Policies.Models", function (Models, App, Backbone, Marionette, $, _) var that = this, promise; + if(typeof App.instances.refresh == 'undefined'){ + App.instances.refresh = {}; + } + + _.each(this.get("policies")[id],function(obj){ + _.each(obj,function(idAttach){ + App.instances.refresh[idAttach] = false; + }); + }); + this.get("policyCollection").remove(id); + delete this.get("policies")[id]; promise = this.saveWithToken(); @@ -91,6 +102,15 @@ App.module("Policies.Models", function (Models, App, Backbone, Marionette, $, _) var that = this, promise; + if(typeof App.instances.refresh == 'undefined'){ + App.instances.refresh = {}; + } + _.each(values,function(obj){ + _.each(obj,function(idAttach){ + App.instances.refresh[idAttach] = false; + }); + }); + this.get("policyCollection").add(policyModel); this.get("policies")[policyModel.get("id")] = values; diff --git a/gecoscc/static/js/printer.js b/gecoscc/static/js/printer.js index ed068552..e7d97be5 100644 --- a/gecoscc/static/js/printer.js +++ b/gecoscc/static/js/printer.js @@ -20,7 +20,7 @@ App.module("Printer.Models", function (Models, App, Backbone, Marionette, $, _) { "use strict"; - Models.PrinterModel = App.GecosResourceModel.extend({ + Models.PrinterModel = App.Policies.Models.GecosResourceModel.extend({ resourceType: "printer", defaults: { @@ -57,7 +57,8 @@ App.module("Printer.Views", function (Views, App, Backbone, Marionette, $, _) { "click #submit": "saveForm", "click #delete": "deleteModel", "change input": "validate", - "click button.refresh": "refresh" + "click button.refresh": "refresh", + "click #cut": "cutModel" }, onBeforeRender: function () { @@ -81,6 +82,7 @@ App.module("Printer.Views", function (Views, App, Backbone, Marionette, $, _) { }, onRender: function () { + this.canMove(); var promise = $.get(this.modelsAPIUrl + "?manufacturers_list=true"), that = this; diff --git a/gecoscc/static/js/repository.js b/gecoscc/static/js/repository.js index 825e6158..6b5736ac 100644 --- a/gecoscc/static/js/repository.js +++ b/gecoscc/static/js/repository.js @@ -17,7 +17,7 @@ App.module("Repository.Models", function (Models, App, Backbone, Marionette, $, _) { "use strict"; - Models.RepositoryModel = App.GecosResourceModel.extend({ + Models.RepositoryModel = App.Policies.Models.GecosResourceModel.extend({ resourceType: "repository", defaults: { @@ -56,7 +56,8 @@ App.module("Repository.Views", function (Views, App, Backbone, Marionette, $, _) "click #submit": "saveForm", "click #delete": "deleteModel", "change input": "validate", - "click button.refresh": "refresh" + "click button.refresh": "refresh", + "click #cut": "cutModel" }, onBeforeRender: function () { @@ -72,6 +73,8 @@ App.module("Repository.Views", function (Views, App, Backbone, Marionette, $, _) }, onRender: function () { + this.canMove(); + if (!_.isUndefined(this.model.id)) { this.$el.find("#name").attr('disabled', 'disabled'); } diff --git a/gecoscc/static/js/staging.js b/gecoscc/static/js/staging.js index a860173d..5fcca1af 100644 --- a/gecoscc/static/js/staging.js +++ b/gecoscc/static/js/staging.js @@ -273,9 +273,18 @@ App.module("Staging.Views", function (Views, App, Backbone, Marionette, $, _) { this.inProgress = true; $.when.apply($, promises) .done(function () { + if(typeof App.instances.refresh == 'undefined'){ + App.instances.refresh = {}; + } + App.tree.currentView.activeNode = null; App.instances.tree.trigger("change"); App.instances.router.navigate("", { trigger: true }); + + _.each(App.instances.refresh,function(value,key){ + App.instances.refresh[key] = true; + }); + }).always(function () { that.inProgress = false; that.render(); diff --git a/gecoscc/static/js/storage.js b/gecoscc/static/js/storage.js index 985b256b..a8b2cb28 100644 --- a/gecoscc/static/js/storage.js +++ b/gecoscc/static/js/storage.js @@ -16,7 +16,7 @@ App.module("Storage.Models", function (Models, App, Backbone, Marionette, $, _) { "use strict"; - Models.StorageModel = App.GecosResourceModel.extend({ + Models.StorageModel = App.Policies.Models.GecosResourceModel.extend({ resourceType: "storage", defaults: { @@ -54,7 +54,8 @@ App.module("Storage.Views", function (Views, App, Backbone, Marionette, $, _) { "click #submit": "saveForm", "click #delete": "deleteModel", "change input": "validate", - "click button.refresh": "refresh" + "click button.refresh": "refresh", + "click #cut": "cutModel" }, onBeforeRender: function () { @@ -70,6 +71,7 @@ App.module("Storage.Views", function (Views, App, Backbone, Marionette, $, _) { }, onRender: function () { + this.canMove(); if (!_.isUndefined(this.model.id)) { this.$el.find("#name").attr('disabled', 'disabled'); } diff --git a/gecoscc/tasks.py b/gecoscc/tasks.py index 66d5d6a4..1b64e8d3 100644 --- a/gecoscc/tasks.py +++ b/gecoscc/tasks.py @@ -29,15 +29,18 @@ from gecoscc.eventsmanager import JobStorage from gecoscc.rules import get_rules, is_user_policy, get_username_chef_format, object_related_list from gecoscc.socks import invalidate_jobs -# It is necessary import here: apply_policies_to_computer and apply_policies_to_user +# It is necessary import here: apply_policies_to_computer, apply_policies_to_printer and apply_policies_to_user... from gecoscc.utils import (get_chef_api, get_cookbook, get_filter_nodes_belonging_ou, emiter_police_slug, get_computer_of_user, delete_dotted, to_deep_dict, reserve_node_or_raise, save_node_and_free, NodeBusyException, NodeNotLinked, apply_policies_to_computer, apply_policies_to_user, - RESOURCES_RECEPTOR_TYPES, RESOURCES_EMITTERS_TYPES, - POLICY_EMITTER_SUBFIX) + apply_policies_to_printer, apply_policies_to_storage, + apply_policies_to_repository, apply_policies_to_group, + apply_policies_to_ou, RESOURCES_RECEPTOR_TYPES, + RESOURCES_EMITTERS_TYPES, POLICY_EMITTER_SUBFIX, + get_policy_emiter_id, get_object_related_list) DELETED_POLICY_ACTION = 'deleted' @@ -129,26 +132,13 @@ def get_related_computers_of_ou(self, ou, related_computers, related_objects): return related_computers - def get_policy_emiter_id(self, obj): - ''' - Get the id from a emitter policy - ''' - return self.db.policies.find_one({'slug': emiter_police_slug(obj['type'])})['_id'] - - def get_object_related_list(self, obj): - ''' - Get the objects related list to an object - ''' - policy_id = unicode(self.get_policy_emiter_id(obj)) - return self.db.nodes.find({"policies.%s.object_related_list" % policy_id: {'$in': [unicode(obj['_id'])]}}) - def get_related_computers_of_emiters(self, obj, related_computers, related_objects): ''' Get the related computers of emitter objects ''' if self.walking_here(obj, related_objects): return related_computers - object_related_list = self.get_object_related_list(obj) + object_related_list = get_object_related_list(self.db, obj) for object_related in object_related_list: self.get_related_computers(object_related, related_computers, related_objects) return related_computers @@ -348,9 +338,16 @@ def has_changed_ws_emitter_policy(self, node, obj_ui, field_chef): return False related_objs = obj_ui for field_value in field_chef_value: - if related_objs['name'] == field_value['name']: + if obj_ui['type'] == 'repository': + field_chef = field_value['repo_name'] + else: + field_chef = field_value['name'] + if related_objs['name'] == field_chef: for attribute in field_value.keys(): - if related_objs[attribute] != field_value[attribute]: + if attribute == 'repo_name': + if related_objs['name'] != field_value[attribute]: + return True + elif related_objs[attribute] != field_value[attribute]: return True return False @@ -868,12 +865,12 @@ def object_moved(self, user, objnew, objold): func = globals()['apply_policies_to_%s' % objnew['type']] except KeyError: raise NotImplementedError - func(self.db.nodes, objnew, user, api, initialize=True, use_celery=False) + func(self.db.nodes, objnew, user, api, initialize=True, use_celery=False, policies_collection=self.db.policies) def object_emiter_deleted(self, user, obj, computers=None): obj_id = unicode(obj['_id']) - policy_id = unicode(self.get_policy_emiter_id(obj)) - object_related_list = self.get_object_related_list(obj) + policy_id = unicode(get_policy_emiter_id(self.db, obj)) + object_related_list = get_object_related_list(self.db, obj) for obj_related in object_related_list: obj_old_related = deepcopy(obj_related) object_related_list = obj_related['policies'][policy_id]['object_related_list'] @@ -899,8 +896,8 @@ def group_changed(self, user, objnew, objold, computers=None): self.log_action('changed', 'Group', objnew) def group_moved(self, user, objnew, objold): - self.log_action('moved', 'Storage', objnew) - raise NotImplementedError + self.object_moved(user, objnew, objold) + self.log_action('moved', 'Group', objnew) def group_deleted(self, user, obj, computers=None, direct_deleted=True): self.object_deleted(user, obj, computers=computers) @@ -969,8 +966,8 @@ def ou_changed(self, user, objnew, objold, computers=None): self.log_action('changed', 'OU', objnew) def ou_moved(self, user, objnew, objold): + self.object_moved(user, objnew, objold) self.log_action('moved', 'OU', objnew) - raise NotImplementedError def ou_deleted(self, user, obj, computers=None, direct_deleted=True): ou_path = '%s,%s' % (obj['path'], unicode(obj['_id'])) @@ -993,8 +990,8 @@ def printer_changed(self, user, objnew, objold, computers=None): self.log_action('changed', 'Printer', objnew) def printer_moved(self, user, objnew, objold): + self.object_moved(user, objnew, objold) self.log_action('moved', 'Printer', objnew) - raise NotImplementedError def printer_deleted(self, user, obj, computers=None, direct_deleted=True): self.object_emiter_deleted(user, obj, computers=computers) @@ -1009,8 +1006,8 @@ def storage_changed(self, user, objnew, objold, computers=None): self.log_action('changed', 'Storage', objnew) def storage_moved(self, user, objnew, objold): + self.object_moved(user, objnew, objold) self.log_action('moved', 'Storage', objnew) - raise NotImplementedError def storage_deleted(self, user, obj, computers=None, direct_deleted=True): self.object_emiter_deleted(user, obj, computers=computers) @@ -1018,19 +1015,19 @@ def storage_deleted(self, user, obj, computers=None, direct_deleted=True): def repository_created(self, user, objnew, computers=None): self.object_created(user, objnew, computers=computers) - self.log_action('created', 'Storage', objnew) + self.log_action('created', 'Repository', objnew) def repository_changed(self, user, objnew, objold, computers=None): self.object_changed(user, objnew, objold, computers=computers) - self.log_action('changed', 'Storage', objnew) + self.log_action('changed', 'Repository', objnew) def repository_moved(self, user, objnew, objold): + self.object_moved(user, objnew, objold) self.log_action('moved', 'Repository', objnew) - raise NotImplementedError def repository_deleted(self, user, obj, computers=None, direct_deleted=True): self.object_emiter_deleted(user, obj, computers=computers) - self.log_action('deleted', 'Storage', obj) + self.log_action('deleted', 'Repository', obj) @task_prerun.connect diff --git a/gecoscc/templates/base_tree.jinja2 b/gecoscc/templates/base_tree.jinja2 index e3f8eaef..5ea2f3d8 100644 --- a/gecoscc/templates/base_tree.jinja2 +++ b/gecoscc/templates/base_tree.jinja2 @@ -127,6 +127,24 @@
+ + {% endblock %} {% block extrajs %} diff --git a/gecoscc/templates/bb-groups-form.html b/gecoscc/templates/bb-groups-form.html index 4c9dede3..120dc80f 100644 --- a/gecoscc/templates/bb-groups-form.html +++ b/gecoscc/templates/bb-groups-form.html @@ -34,6 +34,7 @@ <% if (typeof id !== "undefined") { %> + <% } %> <% } %> diff --git a/gecoscc/templates/bb-ou.html b/gecoscc/templates/bb-ou.html index 3acf4a37..7a5ffdde 100644 --- a/gecoscc/templates/bb-ou.html +++ b/gecoscc/templates/bb-ou.html @@ -59,6 +59,7 @@ <% if (typeof id !== "undefined") { %> + <% } %> <% } %> diff --git a/gecoscc/templates/bb-printer.html b/gecoscc/templates/bb-printer.html index 03e091d6..2ed6b112 100644 --- a/gecoscc/templates/bb-printer.html +++ b/gecoscc/templates/bb-printer.html @@ -105,6 +105,7 @@ <% if (typeof id !== "undefined") { %> + <% } %> <% } %> diff --git a/gecoscc/templates/bb-repository.html b/gecoscc/templates/bb-repository.html index f9923b6c..831e9efd 100644 --- a/gecoscc/templates/bb-repository.html +++ b/gecoscc/templates/bb-repository.html @@ -69,6 +69,7 @@ <% if (typeof id !== "undefined") { %> + <% } %> <% } %> diff --git a/gecoscc/templates/bb-storage.html b/gecoscc/templates/bb-storage.html index 3409a282..8ef90c9d 100644 --- a/gecoscc/templates/bb-storage.html +++ b/gecoscc/templates/bb-storage.html @@ -27,6 +27,7 @@ <% if (typeof id !== "undefined") { %> + <% } %> <% } %> diff --git a/gecoscc/tests.py b/gecoscc/tests.py index 8b89636e..ea865407 100644 --- a/gecoscc/tests.py +++ b/gecoscc/tests.py @@ -25,6 +25,7 @@ from paste.deploy import loadapp from pymongo import Connection from pyramid import testing +from pyramid.httpexceptions import HTTPForbidden from api.chef_status import USERS_OHAI from gecoscc.api.organisationalunits import OrganisationalUnitResource @@ -278,7 +279,7 @@ def drop_mock_nodes(self): global NODES NODES = {} - def get_dummy_request(self): + def get_dummy_request(self, is_superuser=True): ''' Useful method, returns a typical request, with the same request properties than pyramid add (see gecoscc/__init__) @@ -286,10 +287,17 @@ def get_dummy_request(self): request = testing.DummyRequest() request.db = get_db(request) request.userdb = get_userdb(request) - user = request.db.adminusers.find_one({'is_superuser': True}) - if not user: - user = request.userdb.create_user('test', 'test', 'test@example.com', {'is_superuser': True}) - request.user = request.db.adminusers.find_one({'is_superuser': True}) + if is_superuser is True: + user = request.db.adminusers.find_one({'is_superuser': True}) + if not user: + user = request.userdb.create_user('test', 'test', 'test@example.com', {'is_superuser': True}) + request.user = request.db.adminusers.find_one({'is_superuser': True}) + else: + user = request.db.adminusers.find_one({'is_superuser': False}) + if not user: + user = request.userdb.create_user('test_no_super', 'test_no_super', 'test_no_super@example.com', {'is_superuser': False}) + request.user = request.db.adminusers.find_one({'is_superuser': False}) + return request def dummy_get_request(self, data, schema=None): @@ -317,11 +325,11 @@ def get_dummy_json_post_request(self, data, schema=None): del request.validated['_id'] return request - def get_dummy_json_put_request(self, data, schema=None): + def get_dummy_json_put_request(self, data, schema=None, is_superuser=True): ''' Useful method, returns a typical put request ''' - request = self.get_dummy_request() + request = self.get_dummy_request(is_superuser) request.method = 'PUT' request.errors = Errors() if schema: @@ -552,13 +560,13 @@ def create_ou(self, ou_name, domain_name='Domain 1'): 'type': 'ou', 'path': '%s,%s' % (domain['path'], domain['_id']), 'source': 'gecos'} - return self.create_node(data, OrganisationalUnitResource, ou_name='Domain 1') + return self.create_node(data, OrganisationalUnitResource, ou_name=domain_name) def create_domain(self, ou_name, flag): ''' Useful method, create a Domain ''' - data = {'name': 'Domain 1', + data = {'name': ou_name, 'type': 'ou', 'path': '%s,%s' % (flag['path'], flag['_id']), 'master': 'gecos', @@ -579,7 +587,7 @@ def create_node(self, data, api_class, ou_name='OU 1'): return (data, object_api.collection_post()) - def update_node(self, obj, field_name, field_value, api_class): + def update_node(self, obj, field_name, field_value, api_class, is_superuser=True): ''' Useful method, update a node ''' @@ -587,7 +595,7 @@ def update_node(self, obj, field_name, field_value, api_class): obj[field_name].append(field_value) else: obj[field_name] = field_value - request_put = self.get_dummy_json_put_request(obj, api_class.schema_detail) + request_put = self.get_dummy_json_put_request(obj, api_class.schema_detail, is_superuser) api = api_class(request_put) return api.put() @@ -3100,3 +3108,571 @@ def test_30_recalc_command_cert_policy(self, get_cookbook_method, get_cookbook_m self.assertEquals(node_policy, [{u'name': u'cert_ou', u'uri': u'uri_ou'}, {u'name': u'cert_ws', u'uri': u'uri_ws'}]) self.assertNoErrorJobs() + + +class MovementsTests(BaseGecosTestCase): + + @mock.patch('gecoscc.api.chef_status.Node') + @mock.patch('gecoscc.forms.create_chef_admin_user') + @mock.patch('gecoscc.forms._') + @mock.patch('gecoscc.utils.isinstance') + @mock.patch('chef.Node') + @mock.patch('gecoscc.utils.ChefNode') + @mock.patch('gecoscc.tasks.get_cookbook') + @mock.patch('gecoscc.utils.get_cookbook') + def test_01_printers_movements(self, get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, + isinstance_method, gettext, create_chef_admin_user_method, ChefNodeStatusClass): + ''' + Test 01: + 1. Check the printers movements work + ''' + self.apply_mocks(get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, isinstance_method, gettext_mock, create_chef_admin_user_method, ChefNodeStatusClass) + + # 1 - Create printer + data, new_printer = self.create_printer('Testprinter') + + # 2 - Register workstation + db = self.get_db() + ou_1 = db.nodes.find_one({'name': 'OU 1'}) + chef_node_id = CHEF_NODE_ID + self.register_computer() + + # 3 - Add printer to workstation and check if it is applied in chef node + computer = db.nodes.find_one({'name': 'testing'}) + request = self.dummy_get_request(computer, ComputerResource.schema_detail) + computer_api = ComputerResource(request) + computer = computer_api.get() + + printer_policy = db.policies.find_one({'slug': 'printer_can_view'}) + computer['policies'] = {unicode(printer_policy['_id']): {'object_related_list': [new_printer['_id']]}} + policy_path = printer_policy['path'] + self.add_and_get_policy(node=computer, chef_node_id=chef_node_id, api_class=ComputerResource, policy_path=policy_path) + + printer = db.nodes.find_one({'name': 'Testprinter'}) + # 4 - Move printer to the OU path + try: + printer_update = self.update_node(obj=new_printer, field_name='path', + field_value=ou_1['path'], api_class=PrinterResource, + is_superuser=False) + except HTTPForbidden: + printer_update = printer + + # 5 - Checks if the printer has been moved and check if the policy has been updated + self.assertEqual(printer_update['path'], printer['path']) + node = NodeMock(CHEF_NODE_ID, None) + printer_policy = node.attributes.get_dotted(policy_path) + self.assertEqualsObjects(printer_policy[0], new_printer, fields=('oppolicy', + 'model', + 'uri', + 'name', + 'manufacturer')) + # 6 - Move printer to the OU path like superadmin + printer_update = self.update_node(obj=new_printer, field_name='path', + field_value=ou_1['path'], api_class=PrinterResource, + is_superuser=True) + + # 7 - Checks if the printer has been moved + self.assertNotEqual(printer_update['path'], printer['path']) + + # 8 - Create another OU + data, ou_2 = self.create_ou('OU 2') + + # 9 - Move printer to OU 2 like superadmin + printer_update = self.update_node(obj=new_printer, field_name='path', + field_value=ou_2['path'] + ',' + unicode(ou_2['_id']), + api_class=PrinterResource, + is_superuser=True) + + # 10 - Check if the printer is moved and the policy has been updated + self.assertNotEqual(printer_update['path'], printer['path']) + node = NodeMock(CHEF_NODE_ID, None) + printer_policy = node.attributes.get_dotted(policy_path) + self.assertEquals(printer_policy, []) + + self.assertNoErrorJobs() + + @mock.patch('gecoscc.api.chef_status.Node') + @mock.patch('gecoscc.forms.create_chef_admin_user') + @mock.patch('gecoscc.forms._') + @mock.patch('gecoscc.utils.isinstance') + @mock.patch('chef.Node') + @mock.patch('gecoscc.utils.ChefNode') + @mock.patch('gecoscc.tasks.get_cookbook') + @mock.patch('gecoscc.utils.get_cookbook') + def test_02_shared_folder_movements(self, get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, + isinstance_method, gettext, create_chef_admin_user_method, ChefNodeStatusClass): + ''' + Test 02: + 1. Check the shared folder movements work + ''' + self.apply_mocks(get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, isinstance_method, gettext_mock, create_chef_admin_user_method, ChefNodeStatusClass) + + # Register admin + admin_username = 'superuser' + self.add_admin_user(admin_username) + + # 1 - Create storage + db = self.get_db() + data, new_storage = self.create_storage('shared folder') + + # 2 - Create OU 2 + data, ou_2 = self.create_ou('OU 2') + # 3 - Create ws and user + username = 'testuser' + data, new_user = self.create_user(username) + self.assertEqualsObjects(data, new_user) + + db = self.get_db() + chef_node_id = CHEF_NODE_ID + self.register_computer() + + # 4 - Register user in ws + self.assign_user_to_node(gcc_superusername=admin_username, chef_node_id=chef_node_id, username=username) + + # 5 - Add storage to user and check if it is applied in chef node + user = db.nodes.find_one({'name': username}) + request = self.dummy_get_request(user, UserResource.schema_detail) + user_api = UserResource(request) + user = user_api.get() + + id_computer = user['computers'] + user['computers'] = [ObjectId(id_computer[0])] + + storage_policy = db.policies.find_one({'slug': 'storage_can_view'}) + + user['policies'] = {unicode(storage_policy['_id']): {'object_related_list': [new_storage['_id']]}} + policy_path = storage_policy['path'] + '.' + username + '.gtkbookmarks' + self.add_and_get_policy(node=user, chef_node_id=chef_node_id, api_class=UserResource, policy_path=policy_path) + + storage = db.nodes.find_one({'name': 'shared folder'}) + # 6 - Move storage + try: + storage_update = self.update_node(obj=new_storage, field_name='path', + field_value=ou_2['path'], api_class=StorageResource, + is_superuser=False) + except HTTPForbidden: + storage_update = storage + + # 7- Check if the storage has been moved + self.assertEqual(storage_update['path'], storage['path']) + + # 8 - Move storage to the OU path like admin + storage_update = self.update_node(obj=new_storage, field_name='path', + field_value=ou_2['path'], api_class=StorageResource, + is_superuser=True) + # 9 - Check if the storage is moved and the policy has been updated + self.assertNotEqual(storage_update['path'], storage['path']) + node = NodeMock(CHEF_NODE_ID, None) + printer_policy = node.attributes.get_dotted(policy_path) + self.assertEqualsObjects(printer_policy[0], storage, fields=('oppolicy', + 'model', + 'uri', + 'name', + 'manufacturer')) + # 10 - Create another OU + data, ou_3 = self.create_ou('OU 3') + + # 11 - Move storage in the OU 3 like admin + storage_update = self.update_node(obj=new_storage, field_name='path', + field_value=ou_3['path'] + ',' + ou_3['_id'], api_class=StorageResource, + is_superuser=True) + + # 12 - Check if the storage is moved and the policy has been updated + self.assertNotEqual(storage_update['path'], storage['path']) + node = NodeMock(CHEF_NODE_ID, None) + try: + printer_policy = node.attributes.get_dotted(policy_path) + self.assertEquals(printer_policy, []) + except KeyError: + self.assertEquals([], []) + + self.assertNoErrorJobs() + + @mock.patch('gecoscc.api.chef_status.Node') + @mock.patch('gecoscc.forms.create_chef_admin_user') + @mock.patch('gecoscc.forms._') + @mock.patch('gecoscc.utils.isinstance') + @mock.patch('chef.Node') + @mock.patch('gecoscc.utils.ChefNode') + @mock.patch('gecoscc.tasks.get_cookbook') + @mock.patch('gecoscc.utils.get_cookbook') + def test_03_repository_movements(self, get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, + isinstance_method, gettext, create_chef_admin_user_method, ChefNodeStatusClass): + ''' + Test 03: + 1. Check the repository movements work + ''' + self.apply_mocks(get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, isinstance_method, gettext_mock, create_chef_admin_user_method, ChefNodeStatusClass) + + # 1 - Create printer + data, new_repository = self.create_repository('Testrepo') + + # 2 - Register workstation + db = self.get_db() + ou_1 = db.nodes.find_one({'name': 'OU 1'}) + chef_node_id = CHEF_NODE_ID + self.register_computer() + + # 3 - Add repository to workstation + repository_policy = db.policies.find_one({'slug': 'repository_can_view'}) + policy_path = repository_policy['path'] + computer = db.nodes.find_one({'name': 'testing'}) + computer['policies'] = {unicode(repository_policy['_id']): {'object_related_list': [new_repository['_id']]}} + self.add_and_get_policy(node=computer, chef_node_id=chef_node_id, api_class=ComputerResource, policy_path=policy_path) + + repository = db.nodes.find_one({'name': 'Testrepo'}) + # 4 - Move repository to the OU path + try: + repository_update = self.update_node(obj=new_repository, field_name='path', + field_value=ou_1['path'], api_class=RepositoryResource, + is_superuser=False) + except HTTPForbidden: + repository_update = repository + # 5 - Checks if the repository has been moved + self.assertEqual(repository_update['path'], repository['path']) + + # 6 - Move repository to the OU path like admin + repository_update = self.update_node(obj=new_repository, field_name='path', + field_value=ou_1['path'], api_class=RepositoryResource, + is_superuser=True) + + # 7 - Checks if the repository has been moved + self.assertNotEqual(repository_update['path'], repository['path']) + + # 8 - Create another OU + data, ou_2 = self.create_ou('OU 2') + + # 9 - Move printer to OU 2 like superadmin + repository = db.nodes.find_one({'name': 'Testrepo'}) + repository_path = repository['path'] + repository_update = self.update_node(obj=repository, field_name='path', + field_value=ou_2['path'] + ',' + unicode(ou_2['_id']), + api_class=RepositoryResource, + is_superuser=True) + + # 10 - Check if the printer is moved and the policy has been updated + self.assertNotEqual(repository_update['path'], repository_path) + node = NodeMock(CHEF_NODE_ID, None) + printer_policy = node.attributes.get_dotted(policy_path) + self.assertEquals(printer_policy, []) + + self.assertNoErrorJobs() + + @mock.patch('gecoscc.api.chef_status.Node') + @mock.patch('gecoscc.forms.create_chef_admin_user') + @mock.patch('gecoscc.forms._') + @mock.patch('gecoscc.utils.isinstance') + @mock.patch('chef.Node') + @mock.patch('gecoscc.utils.ChefNode') + @mock.patch('gecoscc.tasks.get_cookbook') + @mock.patch('gecoscc.utils.get_cookbook') + def test_04_groups_movements(self, get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, + isinstance_method, gettext, create_chef_admin_user_method, ChefNodeStatusClass): + ''' + Test 04: + 1. Check the groups movements work + ''' + self.apply_mocks(get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, isinstance_method, gettext_mock, create_chef_admin_user_method, ChefNodeStatusClass) + + # 1- Create a group + data, new_group = self.create_group('testgroup') + + # 2 - Register a workstation + db = self.get_db() + ou_1 = db.nodes.find_one({'name': 'OU 1'}) + self.register_computer() + computer = db.nodes.find_one({'name': 'testing'}) + + # 3 - Assign group to computer + self.assign_group_to_node(node_name=computer['name'], api_class=ComputerResource, group=new_group) + + # Check if group's node is update in node chef + group = db.nodes.find_one({'name': 'testgroup'}) + self.assertEqual(group['members'][0], computer['_id']) + + # 4 - move group to the OU path + try: + group_update = self.update_node(obj=group, field_name='path', + field_value=ou_1['path'], api_class=GroupResource, + is_superuser=False) + except HTTPForbidden: + group_update = group + + # 5 - Check if the groups has been moved + self.assertEqual(group_update['path'], group['path']) + + # 6 - move group to the OU path like admin + group = db.nodes.find_one({'name': 'testgroup'}) + group_path = group['path'] + group_update = self.update_node(obj=group, field_name='path', + field_value=ou_1['path'], api_class=GroupResource, + is_superuser=True) + # 7 - Check if the groups has been moved + self.assertNotEqual(group_update['path'], group_path) + self.assertNotEqual(group_update['members'], []) + + # 8 - Create another OU + data, ou_2 = self.create_ou('OU 2') + + # 9 - Move group to OU 2 like superadmin + group = db.nodes.find_one({'name': 'testgroup'}) + group_path = group['path'] + group_update = self.update_node(obj=group, field_name='path', + field_value=ou_2['path'] + ',' + unicode(ou_2['_id']), + api_class=GroupResource, + is_superuser=True) + + # 10 - Check if the group is moved and the policy has been updated + self.assertNotEqual(group_update['path'], group_path) + self.assertEqual(group_update['members'], []) + + self.assertNoErrorJobs() + + @mock.patch('gecoscc.api.chef_status.Node') + @mock.patch('gecoscc.forms.create_chef_admin_user') + @mock.patch('gecoscc.forms._') + @mock.patch('gecoscc.utils.isinstance') + @mock.patch('chef.Node') + @mock.patch('gecoscc.utils.ChefNode') + @mock.patch('gecoscc.tasks.get_cookbook') + @mock.patch('gecoscc.utils.get_cookbook') + def test_05_groups_movements_domain(self, get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, + isinstance_method, gettext, create_chef_admin_user_method, ChefNodeStatusClass): + ''' + Test 05: + 1. Check the groups movements work + ''' + self.apply_mocks(get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, isinstance_method, gettext_mock, create_chef_admin_user_method, ChefNodeStatusClass) + + # 1- Create a group + data, new_group = self.create_group('testgroup') + + # 2 - Register a workstation + db = self.get_db() + self.register_computer() + computer = db.nodes.find_one({'name': 'testing'}) + + # 3 - Assign group to computer + self.assign_group_to_node(node_name=computer['name'], api_class=ComputerResource, group=new_group) + + # Check if group's node is update in node chef + group = db.nodes.find_one({'name': 'testgroup'}) + self.assertEqual(group['members'][0], computer['_id']) + + # 4 - Create domain + data = {'name': 'Flag', + 'type': 'ou', + 'path': 'root', + 'source': 'gecos'} + + request_post = self.get_dummy_json_post_request(data, OrganisationalUnitResource.schema_detail) + ou_api = OrganisationalUnitResource(request_post) + flag_new = ou_api.collection_post() + + data, domain = self.create_domain('Domain 2', flag_new) + + # 5 - move group to the OU path like admin + try: + group_update = self.update_node(obj=new_group, field_name='path', + field_value=domain['path'], api_class=GroupResource, + is_superuser=True) + except KeyError: + group_update = group + + # 6 - Check if the groups has been moved + self.assertEqual(group_update['path'], group['path']) + + self.assertNoErrorJobs() + + @mock.patch('gecoscc.api.chef_status.Node') + @mock.patch('gecoscc.forms.create_chef_admin_user') + @mock.patch('gecoscc.forms._') + @mock.patch('gecoscc.utils.isinstance') + @mock.patch('chef.Node') + @mock.patch('gecoscc.utils.ChefNode') + @mock.patch('gecoscc.tasks.get_cookbook') + @mock.patch('gecoscc.utils.get_cookbook') + def test_06_OUs_movements(self, get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, + isinstance_method, gettext, create_chef_admin_user_method, ChefNodeStatusClass): + ''' + Test 06: + 1. Check the ous movements work + ''' + self.apply_mocks(get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, isinstance_method, gettext_mock, create_chef_admin_user_method, ChefNodeStatusClass) + + # 1- Create OU 2 + data, new_ou = self.create_ou('OU 2', 'OU 1') + + # 2 - Register a workstation + db = self.get_db() + self.register_computer(ou_name=new_ou['name']) + + ou_1 = db.nodes.find_one({'name': 'OU 1'}) + ou_2 = db.nodes.find_one({'name': 'OU 2'}) + # 3 - Move OU 2 to OU 1 path + try: + ou_moved = self.update_node(obj=new_ou, field_name='path', + field_value=ou_1['path'], api_class=OrganisationalUnitResource, + is_superuser=False) + + except HTTPForbidden: + ou_moved = ou_2 + + # 7- Check if the storage has been moved + self.assertEqual(ou_moved['path'], ou_2['path']) + + # 8 - Move printer to the OU path like admin + ou_moved = self.update_node(obj=new_ou, field_name='path', + field_value=ou_1['path'], api_class=OrganisationalUnitResource, + is_superuser=True) + + # 9- Check if the storage has been moved + self.assertNotEqual(ou_moved['path'], ou_2['path']) + + self.assertNoErrorJobs() + + @mock.patch('gecoscc.api.chef_status.Node') + @mock.patch('gecoscc.forms.create_chef_admin_user') + @mock.patch('gecoscc.forms._') + @mock.patch('gecoscc.utils.isinstance') + @mock.patch('chef.Node') + @mock.patch('gecoscc.utils.ChefNode') + @mock.patch('gecoscc.tasks.get_cookbook') + @mock.patch('gecoscc.utils.get_cookbook') + def test_07_OUs_movements_domain(self, get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, + isinstance_method, gettext, create_chef_admin_user_method, ChefNodeStatusClass): + ''' + Test 07: + 1. Check the ous movements work + ''' + self.apply_mocks(get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, isinstance_method, gettext_mock, create_chef_admin_user_method, ChefNodeStatusClass) + + # 1 - Create domain + data = {'name': 'Flag', + 'type': 'ou', + 'path': 'root', + 'source': 'gecos'} + + request_post = self.get_dummy_json_post_request(data, OrganisationalUnitResource.schema_detail) + ou_api = OrganisationalUnitResource(request_post) + flag_new = ou_api.collection_post() + + data, domain = self.create_domain('Domain 2', flag_new) + + # 2 - Register a workstation + db = self.get_db() + ou_1 = db.nodes.find_one({'name': 'OU 1'}) + self.register_computer(ou_name=ou_1['name']) + + # 3 - Move OU 1 to Domain path like admin + try: + ou_moved = self.update_node(obj=ou_1, field_name='path', + field_value=domain['path'], api_class=OrganisationalUnitResource, + is_superuser=True) + except HTTPForbidden: + ou_moved = ou_1 + + # 9- Check if the storage has been moved + self.assertEqual(ou_moved['path'], ou_1['path']) + + self.assertNoErrorJobs() + + @mock.patch('gecoscc.api.chef_status.Node') + @mock.patch('gecoscc.forms.create_chef_admin_user') + @mock.patch('gecoscc.forms._') + @mock.patch('gecoscc.utils.isinstance') + @mock.patch('chef.Node') + @mock.patch('gecoscc.utils.ChefNode') + @mock.patch('gecoscc.tasks.get_cookbook') + @mock.patch('gecoscc.utils.get_cookbook') + def test_08_complete_policy(self, get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, + isinstance_method, gettext, create_chef_admin_user_method, ChefNodeStatusClass): + ''' + Test 08: + 1. Check the ous movements work + ''' + self.apply_mocks(get_cookbook_method, get_cookbook_method_tasks, NodeClass, ChefNodeClass, isinstance_method, gettext_mock, create_chef_admin_user_method, ChefNodeStatusClass) + chef_node_id = CHEF_NODE_ID + + # 1 - Create OU 1 + data, ou_1 = self.create_ou('OU 1') + + # 2 - Create OU 2 + data, ou_2 = self.create_ou('OU 2') + + # 3 - Create OU 3 + data, ou_3 = self.create_ou('OU 3', 'OU 1') + + # 4 - Create user, workstation, storage and 5 - Assign user to computer + admin_username = 'superuser' + self.add_admin_user(admin_username) + + username = 'testuser' + data, user = self.create_user(username, 'OU 3') + self.assertEqualsObjects(data, user) + + db = self.get_db() + chef_node_id = CHEF_NODE_ID + self.register_computer(ou_name=ou_3['name']) + + self.assign_user_to_node(gcc_superusername=admin_username, chef_node_id=chef_node_id, username=username) + + data, storage = self.create_storage('shared folder', ou_3['name']) + data, storage_ou_1 = self.create_storage('shared folder_ou_1', ou_1['name']) + + user = db.nodes.find_one({'name': username}) + request = self.dummy_get_request(user, UserResource.schema_detail) + user_api = UserResource(request) + user = user_api.get() + + id_computer = user['computers'] + user['computers'] = [ObjectId(id_computer[0])] + + storage_policy = db.policies.find_one({'slug': 'storage_can_view'}) + + user['policies'] = {unicode(storage_policy['_id']): {'object_related_list': [storage['_id']]}} + storage_policy_path = storage_policy['path'] + '.' + username + '.gtkbookmarks' + node_policy = self.add_and_get_policy(node=user, chef_node_id=chef_node_id, api_class=UserResource, policy_path=storage_policy_path) + + ou_1 = db.nodes.find_one({'name': 'OU 1'}) + ou_1['policies'] = {unicode(storage_policy['_id']): {'object_related_list': [storage_ou_1['_id']]}} + node_policy = self.add_and_get_policy(node=ou_1, chef_node_id=chef_node_id, api_class=OrganisationalUnitResource, policy_path=storage_policy_path) + + # 7 - add package policy to OU_1, OU_3 and ws + package_res_policy = self.get_default_ws_policy() + policy_path = package_res_policy['path'] + '.package_list' + ou_1['policies'] = {unicode(package_res_policy['_id']): {'package_list': ['gimp'], 'pkgs_to_remove': []}} + package_res_node_policy = self.add_and_get_policy(node=ou_1, chef_node_id=chef_node_id, api_class=OrganisationalUnitResource, policy_path=policy_path) + + apply_package = [{'node': 'testing', 'api_type': ComputerResource, 'package': 'sublime'}, + {'node': 'OU 1', 'api_type': OrganisationalUnitResource, 'package': 'gimp'}, + {'node': 'OU 3', 'api_type': OrganisationalUnitResource, 'package': 'kate'}] + + package_res_policy = self.get_default_ws_policy() + policy_path = package_res_policy['path'] + '.package_list' + + for node in apply_package: + node_to_apply = db.nodes.find_one({'name': node['node']}) + node_to_apply['policies'] = {unicode(package_res_policy['_id']): {'package_list': [node['package']], 'pkgs_to_remove': []}} + package_res_node_policy = self.add_and_get_policy(node=node_to_apply, chef_node_id=chef_node_id, api_class=node['api_type'], policy_path=policy_path) + + self.assertItemsEqual(package_res_node_policy, [u'kate', u'sublime', u'gimp']) + self.assertEmitterObjects(node_policy, [storage_ou_1, storage], fields=('name', + 'uri')) + + # 8 - Move OU 3 to OU 1 path + ou_3 = db.nodes.find_one({'name': 'OU 3'}) + self.update_node(obj=ou_3, field_name='path', + field_value=ou_1['path'], api_class=OrganisationalUnitResource, + is_superuser=True) + + # 9 - Check if the policies has been updated in chef node + node = NodeMock(chef_node_id, None) + node_storage_policy = node.attributes.get_dotted(storage_policy_path) + node_package_policy = node.attributes.get_dotted(policy_path) + + self.assertEmitterObjects(node_storage_policy, [storage], fields=('name', + 'uri')) + self.assertItemsEqual(node_package_policy, [u'kate', u'sublime']) + + self.assertNoErrorJobs() diff --git a/gecoscc/utils.py b/gecoscc/utils.py index 3133fbbb..05f3fdb4 100644 --- a/gecoscc/utils.py +++ b/gecoscc/utils.py @@ -19,7 +19,7 @@ import re from bson import ObjectId, json_util -from copy import deepcopy +from copy import deepcopy, copy from chef import ChefAPI, Client from chef import Node as ChefNode @@ -36,6 +36,21 @@ USE_NODE = 'use_node' +def get_policy_emiter_id(collection, obj): + ''' + Get the id from a emitter policy + ''' + return collection.policies.find_one({'slug': emiter_police_slug(obj['type'])})['_id'] + + +def get_object_related_list(collection, obj): + ''' + Get the objects related list to an object + ''' + policy_id = unicode(get_policy_emiter_id(collection, obj)) + return collection.nodes.find({"policies.%s.object_related_list" % policy_id: {'$in': [unicode(obj['_id'])]}}) + + def merge_lists(collection, obj, old_obj, attribute, remote_attribute, keyname='_id'): """ Merge a list of relations in a two ways relation model. @@ -194,7 +209,10 @@ def delete_chef_admin_user(api, settings, usrname): return False -def remove_chef_computer_data(computer, api): +def remove_chef_computer_data(computer, api, policies=None): + ''' + Remove computer policies in chef node + ''' node_chef_id = computer.get('node_chef_id', None) if node_chef_id: node = reserve_node_or_raise(node_chef_id, api, 'gcc-remove-computer-data-%s' % random.random()) @@ -202,14 +220,26 @@ def remove_chef_computer_data(computer, api): settings = get_current_registry().settings cookbook_name = settings.get('chef.cookbook_name') cookbook = node.normal.get(cookbook_name) - for mgmt in cookbook.keys(): - if mgmt == USER_MGMT: - continue - cookbook.pop(mgmt) + if policies: + for policy in policies: + policy_path = policy[1] + policy_field = policy[2] + try: + cookbook[policy_path].pop(policy_field) + except KeyError: + continue + else: + for mgmt in cookbook.keys(): + if mgmt == USER_MGMT: + continue + cookbook.pop(mgmt) save_node_and_free(node) -def remove_chef_user_data(user, computers, api): +def remove_chef_user_data(user, computers, api, policy_fields=None): + ''' + Remove computer policies in chef node + ''' settings = get_current_registry().settings cookbook_name = settings.get('chef.cookbook_name') for computer in computers: @@ -217,19 +247,31 @@ def remove_chef_user_data(user, computers, api): if node_chef_id: node = reserve_node_or_raise(node_chef_id, api, 'gcc-remove-user-data-%s' % random.random()) if node: - try: - user_mgmt = node.normal.get_dotted('%s.%s' % (cookbook_name, USER_MGMT)) - for policy in user_mgmt: + if policy_fields: + for policy in policy_fields: try: - users = user_mgmt.get(policy).get('users') + user_mgmt = node.normal.get_dotted('%s.%s' % (cookbook_name + '.' + USER_MGMT, policy)) + users = user_mgmt.get('users') if not users: continue users.pop(user['name']) + save_node_and_free(node) except KeyError: - continue - save_node_and_free(node) - except KeyError: - save_node_and_free(node) + save_node_and_free(node) + else: + try: + user_mgmt = node.normal.get_dotted('%s.%s' % (cookbook_name, USER_MGMT)) + for policy in user_mgmt: + try: + users = user_mgmt.get(policy).get('users') + if not users: + continue + users.pop(user['name']) + except KeyError: + continue + save_node_and_free(node) + except KeyError: + save_node_and_free(node) def reserve_node_or_raise(node_id, api, controller_requestor='gcc', attempts=1): @@ -407,11 +449,7 @@ def visibility_object_related(db, obj): '_id': ObjectId(object_related_id) }) else: - is_visible = db.nodes.find_one( - {'_id': ObjectId(object_related_id), - 'path': get_filter_nodes_parents_ou(db, - ou_id, - obj_id)}) + is_visible = is_object_visible(db.nodes, object_related_id, ou_id, obj_id) if is_visible: object_related_visible.append(object_related_id) if object_related_list != object_related_visible: @@ -421,8 +459,7 @@ def visibility_object_related(db, obj): del policies[unicode(emitter_policy_id)] have_updated = True if have_updated: - db.nodes.update({'_id': obj_id}, {'$set': {'policies': policies}}) - obj = db.nodes.find_one({'_id': obj_id}) + obj = update_collection_and_get_obj(db.nodes, obj_id, policies) return obj @@ -460,7 +497,22 @@ def recalc_node_policies(nodes_collection, jobs_collection, computer, auth_user, return (True, 'success') -def apply_policies_to_computer(nodes_collection, computer, auth_user, api=None, initialize=False, use_celery=True): +def is_object_visible(nodes_collection, object_related_id, ou_id, obj_id): + return nodes_collection.find_one({'_id': ObjectId(object_related_id), + 'path': get_filter_nodes_parents_ou(nodes_collection.database, + ou_id, + obj_id)}) + + +def update_collection_and_get_obj(nodes_collection, obj_id, policies_value): + ''' + Updates the node policy and return the obj + ''' + nodes_collection.update({'_id': obj_id}, {'$set': {'policies': policies_value}}) + return nodes_collection.find_one({'_id': obj_id}) + + +def apply_policies_to_computer(nodes_collection, computer, auth_user, api=None, initialize=False, use_celery=True, policies_collection=None): from gecoscc.tasks import object_changed, object_created if use_celery: object_created = object_created.delay @@ -484,7 +536,7 @@ def apply_policies_to_computer(nodes_collection, computer, auth_user, api=None, object_created(auth_user, 'computer', computer, computers=[computer]) -def apply_policies_to_user(nodes_collection, user, auth_user, api=None, initialize=False, use_celery=True): +def apply_policies_to_user(nodes_collection, user, auth_user, api=None, initialize=False, use_celery=True, policies_collection=None): from gecoscc.tasks import object_changed, object_created if use_celery: object_created = object_created.delay @@ -513,6 +565,184 @@ def apply_policies_to_user(nodes_collection, user, auth_user, api=None, initiali object_created(auth_user, 'user', user, computers=computers) +def apply_policies_to_emitter_object(nodes_collection, obj, auth_user, slug, api=None, initialize=False, use_celery=True, policies_collection=None): + ''' + Checks if a emitter object is within the scope of the objects that is related and then update policies + ''' + from gecoscc.tasks import object_changed, object_created + policy = policies_collection.find_one({'slug': slug}) + policy_id = unicode(policy.get('_id')) + + if use_celery: + object_created = object_created.delay + object_changed = object_changed.delay + + nodes_related_with_obj = nodes_collection.find({"policies.%s.object_related_list" % policy_id: {'$in': [unicode(obj['_id'])]}}) + + if nodes_related_with_obj.count() == 0: + return + + for node in nodes_related_with_obj: + is_visible = is_object_visible(nodes_collection, object_related_id=obj['_id'], + ou_id=node['path'].split(',')[-1], obj_id=node['_id']) + + if not is_visible: + object_related_list = node['policies'][policy_id].get('object_related_list', []) + object_related_list.remove(unicode(obj['_id'])) + + if not object_related_list: + del node['policies'][policy_id] + else: + node['policies'][policy_id]['object_related_list'] = object_related_list + obj_related = update_collection_and_get_obj(nodes_collection, node['_id'], node['policies']) + if obj_related['type'] in RESOURCES_RECEPTOR_TYPES: + try: + func = globals()['update_data_%s' % obj_related['type']] + except KeyError: + raise NotImplementedError + func(nodes_collection, obj_related, policy, api, auth_user) + if obj_related['type'] == 'user': + apply_policies_to_user(nodes_collection, obj_related, auth_user, api) + if obj_related['type'] == 'computer': + apply_policies_to_computer(nodes_collection, obj_related, auth_user, api) + + object_created(auth_user, obj['type'], obj) + + +def apply_policies_to_group(nodes_collection, group, auth_user, api=None, initialize=False, use_celery=True, policies_collection=None): + ''' + Checks if a group is within the scope of the objects that is related and then update policies + ''' + from gecoscc.tasks import object_changed, object_created + if use_celery: + object_created = object_created.delay + object_changed = object_changed.delay + policies = group['policies'].keys() + members_group = copy(group['members']) + if not members_group: + return + for member_id in members_group: + member = nodes_collection.find_one({'_id': member_id}) + is_visible = is_visible_group(nodes_collection.database, group['_id'], member) + + if not is_visible: + + member['memberof'].remove(group['_id']) + user_member_of_groups = member['memberof'] + group['members'].remove(member['_id']) + groups_members = group['members'] + nodes_collection.update({'_id': member_id, }, {'$set': {'memberof': user_member_of_groups}}) + nodes_collection.update({'_id': group['_id']}, {'$set': {'members': groups_members}}) + + if member['type'] == 'user': + update_data_user(nodes_collection, member, policies, api, auth_user) + apply_policies_to_user(nodes_collection, member, auth_user, api) + elif member['type'] == 'computer': + update_data_computer(nodes_collection, member, policies, api, auth_user) + + object_created(auth_user, group['type'], group) + + +def apply_policies_to_ou(nodes_collection, ou, auth_user, api=None, initialize=False, use_celery=True, policies_collection=None): + ''' + Checks if a group is within the scope of the objects that is related and then update policies + ''' + from gecoscc.tasks import object_changed, object_created, object_moved + if use_celery: + object_created = object_created.delay + object_changed = object_changed.delay + children_path = ou['path'] + ',' + unicode(ou['_id']) + ou_children = nodes_collection.find({'path': {'$regex': '.*' + unicode(ou['_id']) + '.*'}}) + + visibility_object_related(nodes_collection.database, ou) + + if ou_children.count() == 0: + return + + for child in ou_children: + child_old = nodes_collection.find_one({'_id': child['_id']}) + child['path'] = children_path + object_moved(auth_user, child['type'], child, child_old) + + object_created(auth_user, 'ou', ou) + + +def update_data_ou(nodes_collection, obj, policy, api, auth_user): + members_path = obj['path'] + ',' + unicode(obj['_id']) + members = nodes_collection.find({'path': members_path}) + + for member in members: + if member['type'] in RESOURCES_RECEPTOR_TYPES: + try: + func = globals()['update_data_%s' % member['type']] + except KeyError: + raise NotImplementedError + func(nodes_collection, member, policy, api, auth_user) + if member['type'] == 'user': + apply_policies_to_user(nodes_collection, member, auth_user, api) + if member['type'] == 'computer': + apply_policies_to_computer(nodes_collection, member, auth_user, api) + + +def update_data_group(nodes_collection, obj, policy, api, auth_user): + for member_id in obj['members']: + member = nodes_collection.find_one({'_id': member_id}) + if member['type'] == 'user': + update_data_user(nodes_collection, member, policy, api, auth_user) + elif member['type'] == 'computer': + update_data_computer(nodes_collection, member, policy, api) + + +def update_data_user(nodes_collection, obj, policy, api, auth_user): + from gecoscc.tasks import object_changed, object_created + computers = get_computer_of_user(nodes_collection, obj) + if isinstance(policy, list): + policy_field_name = [] + for policy_id in policy: + policy = nodes_collection.database.policies.find_one({'_id': ObjectId(policy_id)}) + policy_field_name.append(policy['path'].split('.')[2]) + else: + policy_field_name = [policy['path'].split('.')[2]] + remove_chef_user_data(obj, computers, api, policy_field_name) + object_created(auth_user, 'user', obj, computers=computers) + object_changed(auth_user, 'user', obj, {}, computers=computers) + + +def update_data_computer(nodes_collection, obj, policy, api, auth_user): + from gecoscc.tasks import object_created + if policy and policy['slug'] != 'storage_can_view': + if isinstance(policy, list): + policy_field_name = [] + for policy_id in policy: + policy = nodes_collection.database.policies.find_one({'_id': ObjectId(policy_id)}) + policy_field_name.append(policy['path'].split('.')[:3]) + else: + policy_field_name = [policy['path'].split('.')[:3]] + remove_chef_computer_data(obj, api, policy_field_name) + object_created(auth_user, 'computer', obj, computers=[obj]) + + +def apply_policies_to_printer(nodes_collection, printer, auth_user, api=None, initialize=False, use_celery=True, policies_collection=None): + ''' + Checks if a printer is within the scope of the objects that is related and then update policies + ''' + apply_policies_to_emitter_object(nodes_collection, printer, auth_user, 'printer_can_view', api, initialize, use_celery, policies_collection) + + +def apply_policies_to_repository(nodes_collection, repository, auth_user, api=None, initialize=False, use_celery=True, policies_collection=None): + ''' + Checks if a repository is within the scope of the objects that is related and then update policies + ''' + apply_policies_to_emitter_object(nodes_collection, repository, auth_user, 'repository_can_view', api, initialize, use_celery, policies_collection) + + +def apply_policies_to_storage(nodes_collection, storage, auth_user, api=None, initialize=False, use_celery=True, policies_collection=None): + ''' + Checks if a storage is within the scope of the objects that is related and then update policies + ''' + apply_policies_to_emitter_object(nodes_collection, storage, auth_user, 'storage_can_view', api, initialize, use_celery, policies_collection) + + def remove_policies_of_computer(user, computer, auth_user): from gecoscc.tasks import object_deleted computer['user'] = user