From cb0b8c5f7809db8c0136373339be89bf7b360062 Mon Sep 17 00:00:00 2001
From: gloas <gloas@afi-sa.fr>
Date: Tue, 13 Feb 2018 11:49:38 +0100
Subject: [PATCH] hotline #71124 : sql migration for circular user group
 categories

---
 VERSIONS_HOTLINE/71124                        |  1 +
 cosmogramme/sql/patch/patch_340.php           |  2 +
 .../Migration/CircularUserGroupCategories.php | 36 +++++++
 library/Class/UserGroupCategorie.php          |  4 +-
 tests/db/UpgradeDBTest.php                    | 11 +++
 .../CircularUserGroupCategoriestTest.php      | 93 +++++++++++++++++++
 6 files changed, 145 insertions(+), 2 deletions(-)
 create mode 100644 VERSIONS_HOTLINE/71124
 create mode 100644 cosmogramme/sql/patch/patch_340.php
 create mode 100644 library/Class/Migration/CircularUserGroupCategories.php
 create mode 100644 tests/library/Class/Migration/CircularUserGroupCategoriestTest.php

diff --git a/VERSIONS_HOTLINE/71124 b/VERSIONS_HOTLINE/71124
new file mode 100644
index 00000000000..0680386af94
--- /dev/null
+++ b/VERSIONS_HOTLINE/71124
@@ -0,0 +1 @@
+ - ticket #71124 : Administration : Groupes : Correction de références circulaires
\ No newline at end of file
diff --git a/cosmogramme/sql/patch/patch_340.php b/cosmogramme/sql/patch/patch_340.php
new file mode 100644
index 00000000000..73d65fa9d0b
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_340.php
@@ -0,0 +1,2 @@
+<?php
+(new Class_Migration_CircularUserGroupCategories())->run();
\ No newline at end of file
diff --git a/library/Class/Migration/CircularUserGroupCategories.php b/library/Class/Migration/CircularUserGroupCategories.php
new file mode 100644
index 00000000000..0955516c5fe
--- /dev/null
+++ b/library/Class/Migration/CircularUserGroupCategories.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class Class_Migration_CircularUserGroupCategories {
+  public function run() {
+    foreach(Class_UserGroupCategorie::findAll() as $category)
+      $this->_runOne($category);
+  }
+
+
+  protected function _runOne($category) {
+    if ($category->isParentCategoryNotCircular())
+      return;
+
+    $category->setParentId(0)->save();
+  }
+}
diff --git a/library/Class/UserGroupCategorie.php b/library/Class/UserGroupCategorie.php
index 09a140c4394..b1cccf99f0b 100644
--- a/library/Class/UserGroupCategorie.php
+++ b/library/Class/UserGroupCategorie.php
@@ -105,12 +105,12 @@ class Class_UserGroupCategorie extends Storm_Model_Abstract {
 
   public function validate() {
     $this->checkAttribute('parent_id',
-                          $this->_isParentCategoryNotCircular(),
+                          $this->isParentCategoryNotCircular(),
                           $this->_('Référence circulaire'));
   }
 
 
-  protected function _isParentCategoryNotCircular() {
+  public function isParentCategoryNotCircular() {
     $parent = Class_UserGroupCategorie::getLoader()->find($this->getParentId());
     while($parent) {
       if ($parent->getId() == $this->getId()) {
diff --git a/tests/db/UpgradeDBTest.php b/tests/db/UpgradeDBTest.php
index b0c1083ed09..081ca6e49f3 100644
--- a/tests/db/UpgradeDBTest.php
+++ b/tests/db/UpgradeDBTest.php
@@ -1853,3 +1853,14 @@ class UpgradeDB_339_Test extends UpgradeDBTestCase {
     $this->assertEquals(0, $datas['numberOf']);
   }
 }
+
+
+
+
+class UpgradeDB_340_Test extends UpgradeDBTestCase {
+  public function prepare() {}
+
+
+  /** @test */
+  public function placeholderForCircularUserGroupCategories() {}
+}
\ No newline at end of file
diff --git a/tests/library/Class/Migration/CircularUserGroupCategoriestTest.php b/tests/library/Class/Migration/CircularUserGroupCategoriestTest.php
new file mode 100644
index 00000000000..470bcd5af1b
--- /dev/null
+++ b/tests/library/Class/Migration/CircularUserGroupCategoriestTest.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class Class_Migration_CircularUserGroupCategoriesTest extends ModelTestCase {
+  protected $_storm_default_to_volatile=true;
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->fixture('Class_UserGroupCategorie',
+                   ['id' => 2,
+                    'parent_id' =>1 ]);
+
+    // skip model validation to reproduce production data corruption
+    // one level
+    Class_UserGroupCategorie::getLoader()
+      ->save(Class_UserGroupCategorie::newInstance(['id' => 3,
+                                                    'parent_id' => 3 ]));
+
+
+    // two levels
+    Class_UserGroupCategorie::getLoader()
+      ->save(Class_UserGroupCategorie::newInstance(['id' => 4,
+                                                    'parent_id' => 5 ]));
+
+    Class_UserGroupCategorie::getLoader()
+      ->save(Class_UserGroupCategorie::newInstance(['id' => 5,
+                                                    'parent_id' => 4 ]));
+
+
+    // three levels
+    Class_UserGroupCategorie::getLoader()
+      ->save(Class_UserGroupCategorie::newInstance(['id' => 10,
+                                                    'parent_id' => 11 ]));
+
+    Class_UserGroupCategorie::getLoader()
+      ->save(Class_UserGroupCategorie::newInstance(['id' => 11,
+                                                    'parent_id' => 12 ]));
+
+    Class_UserGroupCategorie::getLoader()
+      ->save(Class_UserGroupCategorie::newInstance(['id' => 12,
+                                                    'parent_id' => 10 ]));
+
+
+    (new Class_Migration_CircularUserGroupCategories())->run();
+  }
+
+
+  /** @test */
+  public function notCircularShouldNotBeUpdated() {
+    $this->assertEquals(1, Class_UserGroupCategorie::find(2)->getParentId());
+  }
+
+
+  /** @test */
+  public function circularOneLevelShouldMoveToRoot() {
+    $this->assertEquals(0, Class_UserGroupCategorie::find(3)->getParentId());
+  }
+
+
+  /** @test */
+  public function circularTwoLevelsShouldMoveToRoot() {
+    $this->assertEquals(0, Class_UserGroupCategorie::find(4)->getParentId());
+    $this->assertEquals(4, Class_UserGroupCategorie::find(5)->getParentId());
+  }
+
+
+  /** @test */
+  public function circularTreeLevelsShouldMoveToRoot() {
+    $this->assertEquals(0, Class_UserGroupCategorie::find(10)->getParentId());
+    $this->assertEquals(12, Class_UserGroupCategorie::find(11)->getParentId());
+    $this->assertEquals(10, Class_UserGroupCategorie::find(12)->getParentId());
+  }
+}
-- 
GitLab