From fe2ec65900c1b7f4b394d56170e7b02a381bc5b5 Mon Sep 17 00:00:00 2001
From: nagem <meganhenning@flywheel.io>
Date: Sun, 10 Apr 2016 19:38:14 -0500
Subject: [PATCH] Propagate group tag changes down heirarchy

---
 api/api.py                  | 10 ++++----
 api/handlers/listhandler.py | 51 +++++++++++++++++++++++++++++++++++++
 api/schemas/input/tag.json  |  2 +-
 3 files changed, 57 insertions(+), 6 deletions(-)

diff --git a/api/api.py b/api/api.py
index 097315e9..882669a3 100644
--- a/api/api.py
+++ b/api/api.py
@@ -61,7 +61,7 @@ routing_regexes = {
     # tag regex
     # length between 3 and 24 characters
     # any character allowed except '/''
-    'tag_re': '[^/]{3,24}',
+    'tag_re': '[^/]{1,32}',
     # filename regex
     # any character allowed except '/'
     'filename_re': '[^/]+',
@@ -127,11 +127,11 @@ routes = [
     webapp2.Route(_format(r'/api/<cont_name:groups>/<cid:{group_id_re}>/<list_name:roles>/<site:{site_id_re}>/<_id:{user_id_re}>'),    listhandler.ListHandler, name='group_roles', methods=['GET', 'PUT', 'DELETE']),
 
 
-    webapp2.Route(_format(r'/api/<cont_name:groups>/<cid:{group_id_re}>/<list_name:tags>'),                                      listhandler.ListHandler, methods=['POST'], name='tags_post'),
-    webapp2.Route(_format(r'/api/<cont_name:groups>/<cid:{group_id_re}>/<list_name:tags>/<value:{tag_re}>'),                     listhandler.ListHandler, name='tags'),
+    webapp2.Route(_format(r'/api/<cont_name:groups>/<cid:{group_id_re}>/<list_name:tags>'),                                      listhandler.TagsListHandler, methods=['POST'], name='tags_post'),
+    webapp2.Route(_format(r'/api/<cont_name:groups>/<cid:{group_id_re}>/<list_name:tags>/<value:{tag_re}>'),                     listhandler.TagsListHandler, name='tags'),
 
-    webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:tags>'),                                      listhandler.ListHandler, methods=['POST'], name='tags_post'),
-    webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:tags>/<value:{tag_re}>'),                     listhandler.ListHandler, name='tags'),
+    webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:tags>'),                                      listhandler.TagsListHandler, methods=['POST'], name='tags_post'),
+    webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:tags>/<value:{tag_re}>'),                     listhandler.TagsListHandler, name='tags'),
 
     webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/packfile'),                                     listhandler.FileListHandler, name='packfile', handler_method='packfile', methods=['POST']),
     webapp2.Route(_format(r'/api/<cont_name:{cont_name_re}>/<cid:{cid_re}>/<list_name:files>'),                                     listhandler.FileListHandler, name='files_post', methods=['POST']),
diff --git a/api/handlers/listhandler.py b/api/handlers/listhandler.py
index ac119a2e..2c646d54 100644
--- a/api/handlers/listhandler.py
+++ b/api/handlers/listhandler.py
@@ -212,6 +212,7 @@ class PermissionsListHandler(ListHandler):
 
     def put(self, cont_name, list_name, **kwargs):
         _id = kwargs.get('cid')
+
         result = super(PermissionsListHandler, self).put(cont_name, list_name, **kwargs)
         if cont_name == 'projects':
             self._propagate_project_permissions(_id)
@@ -282,6 +283,56 @@ class NotesListHandler(ListHandler):
             return {'modified':result.modified_count}
 
 
+class TagsListHandler(ListHandler):
+    """
+    TagsListHandler overrides put, delete methods of ListHandler to propagate changes to group tags
+    If a tag is renamed or deleted at the group level, project, session and acquisition tags will also be renamed/deleted
+    """
+
+    def put(self, cont_name, list_name, **kwargs):
+        _id = kwargs.get('cid')
+        result = super(TagsListHandler, self).put(cont_name, list_name, **kwargs)
+        if cont_name == 'groups':
+            payload = self.request.json_body
+            current_value = kwargs.get('value')
+            new_value = payload.get('value')
+            query = {'$and':[{'tags': current_value}, {'tags': {'$ne': new_value}}]}
+            update = {'$set': {'tags.$': new_value}}
+            self._propagate_group_tags(_id, query, update)
+        return result
+
+    def delete(self, cont_name, list_name, **kwargs):
+        _id = kwargs.get('cid')
+        result = super(TagsListHandler, self).delete(cont_name, list_name, **kwargs)
+        if cont_name == 'groups':
+            payload = self.request.json_body
+            deleted_tag = payload.get('value')
+            query = {}
+            update = {'$pull': {'tags': deleted_tag}}
+            self._propagate_group_tags(_id, query, update)
+
+    def _propagate_group_tags(self, _id, query, update):
+        """
+        method to propagate tag changes from a group to its projects, sessions and acquisitions
+        """
+        try:
+            project_ids = [p['_id'] for p in config.db.projects.find({'group': _id}, [])]
+            session_ids = [s['_id'] for s in config.db.sessions.find({'project': {'$in': project_ids}}, [])]
+
+            project_q = query.copy()
+            project_q['_id'] = {'$in': project_ids}
+            session_q = query.copy()
+            session_q['_id'] = {'$in': session_ids}
+            acquisition_q = query.copy()
+            acquisition_q['session'] = {'$in': session_ids}
+
+            config.db.projects.update_many(project_q, update)
+            config.db.sessions.update_many(session_q, update)
+            config.db.acquisitions.update_many(acquisition_q, update)
+        except:
+            log.debug(e)
+            self.abort(500, 'tag change not propagated down heirarchy from group {}'.format(_id))
+
 
 class FileListHandler(ListHandler):
     """
diff --git a/api/schemas/input/tag.json b/api/schemas/input/tag.json
index 1475459e..5621558e 100644
--- a/api/schemas/input/tag.json
+++ b/api/schemas/input/tag.json
@@ -2,7 +2,7 @@
   "$schema": "http://json-schema.org/draft-04/schema#",
   "type": "object",
   "properties": {
-    "value":             {"type": "string"}
+    "value":             {"type": "string", "minLength": 1, "maxLength": 32}
   },
   "required": ["value"],
   "additionalProperties": false
-- 
GitLab