Tinebase_Export - update script to import to vfs
[tine20] / tine20 / Tinebase / Setup / Update / Release10.php
1 <?php
2 /**
3  * Tine 2.0
4  *
5  * @package     Tinebase
6  * @subpackage  Setup
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL3
8  * @copyright   Copyright (c) 2016-2017 Metaways Infosystems GmbH (http://www.metaways.de)
9  * @author      Philipp Schüle <p.schuele@metaways.de>
10  */
11 class Tinebase_Setup_Update_Release10 extends Setup_Update_Abstract
12 {
13     /**
14      * update to 10.1
15      *
16      * @see 0012162: create new MailFiler application
17      */
18     public function update_0()
19     {
20         $release9 = new Tinebase_Setup_Update_Release9($this->_backend);
21         $release9->update_9();
22         $this->setApplicationVersion('Tinebase', '10.1');
23     }
24
25     /**
26      * update to 10.2
27      *
28      * @see 0012300: add container owner column
29      */
30     public function update_1()
31     {
32         $release9 = new Tinebase_Setup_Update_Release9($this->_backend);
33         try {
34             $release9->update_4();
35         } catch (Zend_Db_Exception $zde) {
36             Tinebase_Exception::log($zde);
37         }
38         $this->setApplicationVersion('Tinebase', '10.2');
39     }
40
41     /**
42      * update to 10.3
43      *
44      * change length of groups.description column from varchar(255) to text
45      */
46     public function update_2()
47     {
48         $release9 = new Tinebase_Setup_Update_Release9($this->_backend);
49         $release9->update_5();
50         $this->setApplicationVersion('Tinebase', '10.3');
51     }
52
53     /**
54      * update to 10.4
55      *
56      * dd numberables
57      */
58     public function update_3()
59     {
60         $release9 = new Tinebase_Setup_Update_Release9($this->_backend);
61         $release9->update_10();
62         $this->setApplicationVersion('Tinebase', '10.4');
63     }
64
65     /**
66      * needs to be done again to make sure we have the column!
67      *
68      * @see 0012300: add container owner column
69      */
70     public function update_4()
71     {
72         $release9 = new Tinebase_Setup_Update_Release9($this->_backend);
73         try {
74             $release9->update_4();
75         } catch (Zend_Db_Exception $zde) {
76             Tinebase_Exception::log($zde);
77         }
78         $this->setApplicationVersion('Tinebase', '10.5');
79     }
80
81     /**
82      * update to 10.6
83      *
84      * add account sync scheduler job
85      */
86     public function update_5()
87     {
88         $scheduler = Tinebase_Core::getScheduler();
89         Tinebase_Scheduler_Task::addAccountSyncTask($scheduler);
90
91         $this->setApplicationVersion('Tinebase', '10.6');
92     }
93
94     /**
95      * update to 10.7
96      *
97      * update timemachine_modlog table
98      */
99     public function update_6()
100     {
101         if (!$this->_backend->columnExists('instance_id', 'timemachine_modlog')) {
102
103             $this->_backend->renameTable('timemachine_modlog', 'timemachine_modlog_bkp');
104             $db = Tinebase_Core::getDb();
105             if ($db instanceof Zend_Db_Adapter_Pdo_Pgsql) {
106                 $db->exec('ALTER INDEX "' . SQL_TABLE_PREFIX . 'timemachine_modlog_pkey" RENAME TO ' . SQL_TABLE_PREFIX . 'timemachine_modlog_pkey_bkp');
107                 $db->exec('ALTER INDEX "' . SQL_TABLE_PREFIX . 'timemachine_modlog_seq" RENAME TO ' . SQL_TABLE_PREFIX . 'timemachine_modlog_seq_bkp');
108                 $db->exec('ALTER INDEX "' . SQL_TABLE_PREFIX . 'timemachine_modlog_unique-fields_key" RENAME TO "' . SQL_TABLE_PREFIX . 'timemachine_modlog_unique-fields_key_bkp"');
109             }
110
111             $this->_backend->createTable(new Setup_Backend_Schema_Table_Xml('<table>
112                 <name>timemachine_modlog</name>
113                 <version>5</version>
114                 <declaration>
115                     <field>
116                         <name>id</name>
117                         <type>text</type>
118                         <length>40</length>
119                         <notnull>true</notnull>
120                     </field>
121                     <field>
122                         <name>instance_id</name>
123                         <type>text</type>
124                         <length>40</length>
125                         <notnull>false</notnull>
126                     </field>
127                     <field>
128                         <name>instance_seq</name>
129                         <type>integer</type>
130                         <notnull>true</notnull>
131                         <autoincrement>true</autoincrement>
132                     </field>
133                     <field>
134                         <name>change_type</name>
135                         <type>text</type>
136                         <length>40</length>
137                         <notnull>false</notnull>
138                     </field>
139                     <field>
140                         <name>application_id</name>
141                         <type>text</type>
142                         <length>40</length>
143                         <notnull>true</notnull>
144                     </field>
145                     <field>
146                         <name>record_id</name>
147                         <type>text</type>
148                         <length>40</length>
149                         <notnull>false</notnull>
150                     </field>
151                     <field>
152                         <name>record_type</name>
153                         <type>text</type>
154                         <length>64</length>
155                         <notnull>false</notnull>
156                     </field>
157                     <field>
158                         <name>record_backend</name>
159                         <type>text</type>
160                         <length>64</length>
161                         <notnull>false</notnull>
162                     </field>
163                     <field>
164                         <name>modification_time</name>
165                         <type>datetime</type>
166                         <notnull>true</notnull>
167                     </field>
168                     <field>
169                         <name>modification_account</name>
170                         <type>text</type>
171                         <length>40</length>
172                         <notnull>true</notnull>
173                     </field>
174                     <field>
175                         <name>modified_attribute</name>
176                         <type>text</type>
177                         <length>64</length>
178                         <notnull>false</notnull>
179                     </field>
180                     <field>
181                         <name>old_value</name>
182                         <type>clob</type>
183                     </field>
184                     <field>
185                         <name>new_value</name>
186                         <type>clob</type>
187                     </field>
188                     <field>
189                         <name>seq</name>
190                         <type>integer</type>
191                         <length>64</length>
192                     </field>
193                     <field>
194                         <name>client</name>
195                         <type>text</type>
196                         <length>255</length>
197                         <notnull>true</notnull>
198                     </field>
199                     <index>
200                         <name>id</name>
201                         <primary>true</primary>
202                         <field>
203                             <name>id</name>
204                         </field>
205                     </index>
206                     <index>
207                         <name>instance_id</name>
208                         <field>
209                             <name>instance_id</name>
210                         </field>
211                     </index>
212                     <index>
213                         <name>instance_seq</name>
214                         <unique>true</unique>
215                         <field>
216                             <name>instance_seq</name>
217                         </field>
218                     </index>
219                     <index>
220                         <name>seq</name>
221                         <field>
222                             <name>seq</name>
223                         </field>
224                     </index>
225                     <index>
226                         <name>unique-fields</name>
227                         <unique>true</unique>
228                         <field>
229                             <name>application_id</name>
230                         </field>
231                         <field>
232                             <name>record_id</name>
233                         </field>
234                         <field>
235                             <name>record_type</name>
236                         </field>
237                         <field>
238                             <name>modification_time</name>
239                         </field>
240                         <field>
241                             <name>modification_account</name>
242                         </field>
243                         <field>
244                             <name>modified_attribute</name>
245                         </field>
246                         <field>
247                             <name>seq</name>
248                         </field>
249                     </index>
250                 </declaration>
251             </table>'));
252
253
254
255             $appIds[] = Tinebase_Application::getInstance()->getApplicationByName('Addressbook')->getId();
256             if (Tinebase_Application::getInstance()->isInstalled('Calendar')) {
257                 $appIds[] = Tinebase_Application::getInstance()->getApplicationByName('Calendar')->getId();
258             }
259
260             $select = $db->select()->from(SQL_TABLE_PREFIX . 'timemachine_modlog_bkp')->order('modification_time ASC')
261                 ->where($db->quoteInto($db->quoteIdentifier('application_id') . ' IN (?)', $appIds))
262                 ->where($db->quoteInto($db->quoteIdentifier('record_type') . ' IN (?)', array('Addressbook_Model_Contact', 'Calendar_Model_Resource')))
263                 ->where($db->quoteInto($db->quoteIdentifier('modified_attribute') . ' IN (?)', array('email', 'email_home')));
264
265             $stmt = $db->query($select);
266             $resultArray = $stmt->fetchAll(Zend_Db::FETCH_ASSOC);
267
268             if (count($resultArray) > 0) {
269                 foreach($resultArray as $row) {
270                     $row['client'] = 'update script';
271                     $db->insert(SQL_TABLE_PREFIX . 'timemachine_modlog', $row);
272                 }
273             }
274
275             $this->setTableVersion('timemachine_modlog', '5');
276         }
277
278         $this->setApplicationVersion('Tinebase', '10.7');
279     }
280
281     /**
282      * update to 10.8
283      *
284      * update roles and application table
285      */
286     public function update_7()
287     {
288         if (!$this->_backend->columnExists('is_deleted', 'roles')) {
289             $query = $this->_backend->addAddCol(null, 'roles',
290                 new Setup_Backend_Schema_Field_Xml('<field>
291                     <name>is_deleted</name>
292                     <type>boolean</type>
293                     <default>false</default>
294                 </field>'), 'last_modified_time'
295             );
296             $query = $this->_backend->addAddCol($query, 'roles',
297                 new Setup_Backend_Schema_Field_Xml('<field>
298                     <name>deleted_by</name>
299                     <type>text</type>
300                     <length>40</length>
301                 </field>'), 'is_deleted'
302             );
303             $query = $this->_backend->addAddCol($query, 'roles',
304                 new Setup_Backend_Schema_Field_Xml('<field>
305                     <name>deleted_time</name>
306                     <type>datetime</type>
307                 </field>'), 'deleted_by'
308             );
309             $query = $this->_backend->addAddCol($query, 'roles',
310                 new Setup_Backend_Schema_Field_Xml('<field>
311                     <name>seq</name>
312                     <type>integer</type>
313                     <notnull>true</notnull>
314                     <default>0</default>
315                 </field>'), 'deleted_time'
316             );
317             $this->_backend->execQueryVoid($query);
318             $this->setTableVersion('roles', '2');
319         }
320
321         if (!$this->_backend->columnExists('state', 'applications')) {
322
323             $this->_backend->addCol('applications',
324                 new Setup_Backend_Schema_Field_Xml('<field>
325                     <name>state</name>
326                     <type>text</type>
327                     <length>65535</length>
328                     <notnull>false</notnull>
329                 </field>')
330             );
331
332             $this->setTableVersion('applications', '4');
333         }
334
335         $this->setApplicationVersion('Tinebase', '10.8');
336     }
337
338     /**
339      * update to 10.9
340      *
341      * add client row to timemachine_modlog
342      *
343      * @see 0012830: add client user agent to modlog
344      */
345     public function update_8()
346     {
347         if (! $this->_backend->columnExists('client', 'timemachine_modlog')) {
348             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
349                     <name>client</name>
350                     <type>text</type>
351                     <length>255</length>
352                     <notnull>true</notnull>
353                 </field>');
354             $this->_backend->addCol('timemachine_modlog', $declaration);
355
356             $this->setTableVersion('timemachine_modlog', '5');
357         }
358
359         $this->setApplicationVersion('Tinebase', '10.9');
360     }
361
362     /**
363      * update to 10.10
364      *
365      * adding path filter feature switch & structure update
366      */
367     public function update_9()
368     {
369         $this->dropTable('path');
370
371         $declaration = new Setup_Backend_Schema_Table_Xml('<table>
372             <name>path</name>
373             <version>2</version>
374             <requirements>
375                 <required>mysql >= 5.6.4</required>
376             </requirements>
377             <declaration>
378                 <field>
379                     <name>id</name>
380                     <type>text</type>
381                     <length>40</length>
382                     <notnull>true</notnull>
383                 </field>
384                 <field>
385                     <name>path</name>
386                     <type>text</type>
387                     <length>65535</length>
388                     <notnull>true</notnull>
389                 </field>
390                 <field>
391                     <name>shadow_path</name>
392                     <type>text</type>
393                     <length>65535</length>
394                     <notnull>true</notnull>
395                 </field>
396                 <field>
397                     <name>creation_time</name>
398                     <type>datetime</type>
399                 </field>
400                 <index>
401                     <name>id</name>
402                     <primary>true</primary>
403                     <field>
404                         <name>id</name>
405                     </field>
406                 </index>
407                 <index>
408                 <name>path</name>
409                     <fulltext>true</fulltext>
410                     <field>
411                         <name>path</name>
412                     </field>
413                 </index>
414                 <index>
415                     <name>shadow_path</name>
416                     <fulltext>true</fulltext>
417                     <field>
418                         <name>shadow_path</name>
419                     </field>
420                 </index>
421             </declaration>
422         </table>');
423
424         $this->createTable('path', $declaration, 'Tinebase', 2);
425
426         try {
427             $setupUser = Setup_Update_Abstract::getSetupFromConfigOrCreateOnTheFly();
428             if ($setupUser) {
429                 Tinebase_Core::set(Tinebase_Core::USER, $setupUser);
430                 Tinebase_Controller::getInstance()->rebuildPaths();
431             } else {
432                 if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) {
433                     Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__
434                         . ' Could not find valid setupuser. Skipping rebuildPaths: you might need to run this manually.');
435                 }
436             }
437         } catch (Exception $e) {
438             Tinebase_Exception::log($e);
439             Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__
440                 . ' Skipping rebuildPaths: you might need to run this manually.');
441         }
442
443         $this->setApplicationVersion('Tinebase', '10.10');
444     }
445
446     /**
447      * update to 10.11
448      *
449      * create external_fulltext table
450      */
451     public function update_10()
452     {
453         $this->_backend->createTable(new Setup_Backend_Schema_Table_Xml('<table>
454             <name>external_fulltext</name>
455             <version>1</version>
456             <declaration>
457                 <field>
458                     <name>id</name>
459                     <type>text</type>
460                     <length>40</length>
461                     <notnull>true</notnull>
462                 </field>
463                 <field>
464                     <name>text_data</name>
465                     <type>text</type>
466                     <length>2147483647</length>
467                     <notnull>true</notnull>
468                 </field>
469                 <index>
470                     <name>id</name>
471                     <primary>true</primary>
472                     <field>
473                         <name>id</name>
474                     </field>
475                 </index>
476                 <index>
477                     <name>text_data</name>
478                     <fulltext>true</fulltext>
479                     <field>
480                         <name>text_data</name>
481                     </field>
482                 </index>
483             </declaration>
484         </table>'), 'Tinebase', 'external_fulltext');
485
486         $this->setApplicationVersion('Tinebase', '10.11');
487     }
488
489     /**
490      * update to 10.12
491      *
492      * add revision_size to tree_fileobjects
493      */
494     public function update_11()
495     {
496
497         if (!$this->_backend->columnExists('total_size', 'tree_fileobjects')) {
498             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
499                     <name>revision_size</name>
500                     <type>integer</type>
501                     <notnull>true</notnull>
502                     <default>0</default>
503                 </field>');
504
505             $query = $this->_backend->addAddCol('', 'tree_fileobjects', $declaration);
506
507             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
508                     <name>indexed_hash</name>
509                     <type>text</type>
510                     <length>40</length>
511                 </field>');
512
513             $query = $this->_backend->addAddCol($query, 'tree_fileobjects', $declaration);
514
515             $this->_backend->execQueryVoid($query);
516
517             $this->setTableVersion('tree_fileobjects', '4');
518         }
519
520         $this->setApplicationVersion('Tinebase', '10.12');
521     }
522
523     /**
524      * add tree_node_acl
525      */
526     public function update_12()
527     {
528         if (! $this->_backend->columnExists('acl_node', 'tree_nodes')) {
529             $declaration = new Setup_Backend_Schema_Field_Xml(
530                 '<field>
531                     <name>acl_node</name>
532                     <type>text</type>
533                     <length>40</length>
534                 </field>
535             ');
536             $query = $this->_backend->addAddCol('', 'tree_nodes', $declaration);
537             $declaration = new Setup_Backend_Schema_Field_Xml(
538                 '<field>
539                     <name>revisionProps</name>
540                     <type>text</type>
541                     <length>65535</length>
542                 </field>');
543             $query = $this->_backend->addAddCol($query, 'tree_nodes', $declaration);
544             $this->_backend->execQueryVoid($query);
545
546             $this->setTableVersion('tree_nodes', 2);
547
548             $declaration = new Setup_Backend_Schema_Table_Xml('<table>
549             <name>tree_node_acl</name>
550             <version>1</version>
551             <declaration>
552                 <field>
553                     <name>id</name>
554                     <type>text</type>
555                     <length>40</length>
556                     <notnull>true</notnull>
557                 </field>
558                 <field>
559                     <name>record_id</name>
560                     <type>text</type>
561                     <length>40</length>
562                     <notnull>true</notnull>
563                 </field>
564                 <field>
565                     <name>account_type</name>
566                     <type>text</type>
567                     <length>32</length>
568                     <default>user</default>
569                     <notnull>true</notnull>
570                 </field>
571                 <field>
572                     <name>account_id</name>
573                     <type>text</type>
574                     <length>40</length>
575                     <notnull>true</notnull>
576                 </field>
577                 <field>
578                     <name>account_grant</name>
579                     <type>text</type>
580                     <length>40</length>
581                     <notnull>true</notnull>
582                 </field>
583
584                 <index>
585                     <name>record_id-account-type-account_id-account_grant</name>
586                     <primary>true</primary>
587                     <field>
588                         <name>id</name>
589                     </field>
590                     <field>
591                         <name>record_id</name>
592                     </field>
593                     <field>
594                         <name>account_type</name>
595                     </field>
596                     <field>
597                         <name>account_id</name>
598                     </field>
599                     <field>
600                         <name>account_grant</name>
601                     </field>
602                 </index>
603                 <index>
604                     <name>id-account_type-account_id</name>
605                     <field>
606                         <name>record_id</name>
607                     </field>
608                     <field>
609                         <name>account_type</name>
610                     </field>
611                     <field>
612                         <name>account_id</name>
613                     </field>
614                 </index>
615                 <index>
616                     <name>tree_node_acl::record_id--tree_nodes::id</name>
617                     <field>
618                         <name>record_id</name>
619                     </field>
620                     <foreign>true</foreign>
621                     <reference>
622                         <table>tree_nodes</table>
623                         <field>id</field>
624                         <ondelete>cascade</ondelete>
625                     </reference>
626                 </index>
627             </declaration>
628         </table>');
629             $this->createTable('tree_node_acl', $declaration);
630         }
631
632         $this->setApplicationVersion('Tinebase', '10.13');
633     }
634
635     /**
636      * update to 10.14
637      *
638      * add file revision cleanup task to scheduler
639      */
640     public function update_13()
641     {
642         $scheduler = Tinebase_Core::getScheduler();
643         Tinebase_Scheduler_Task::addFileRevisionCleanupTask($scheduler);
644
645         $this->setApplicationVersion('Tinebase', '10.14');
646     }
647
648     /**
649      * update to 10.15
650      *
651      * update record_observer
652      */
653     public function update_14()
654     {
655         $this->dropTable('record_observer', 'Tinebase');
656
657         $this->createTable('record_observer', new Setup_Backend_Schema_Table_Xml('<table>
658             <name>record_observer</name>
659             <version>4</version>
660             <declaration>
661                 <field>
662                     <name>id</name>
663                     <type>integer</type>
664                     <autoincrement>true</autoincrement>
665                 </field>
666                 <field>
667                     <name>observable_model</name>
668                     <type>text</type>
669                     <length>100</length>
670                     <notnull>true</notnull>
671                 </field>
672                 <field>
673                     <name>observable_identifier</name>
674                     <type>text</type>
675                     <length>40</length>
676                     <notnull>true</notnull>
677                 </field>
678                 <field>
679                     <name>observer_model</name>
680                     <type>text</type>
681                     <length>100</length>
682                     <notnull>true</notnull>
683                 </field>
684                 <field>
685                     <name>observer_identifier</name>
686                     <type>text</type>
687                     <length>40</length>
688                     <notnull>true</notnull>
689                 </field>
690                 <field>
691                     <name>observed_event</name>
692                     <type>text</type>
693                     <length>100</length>
694                     <notnull>true</notnull>
695                 </field>
696                 <field>
697                     <name>created_by</name>
698                     <type>text</type>
699                     <length>40</length>
700                 </field>
701                 <field>
702                     <name>creation_time</name>
703                     <type>datetime</type>
704                     <notnull>true</notnull>
705                 </field>
706                 <index>
707                     <name>id</name>
708                     <primary>true</primary>
709                     <field>
710                         <name>id</name>
711                     </field>
712                 </index>
713                 <index>
714                     <name>observable-observer-event</name>
715                     <unique>true</unique>
716                     <field>
717                         <name>observable_model</name>
718                     </field>
719                     <field>
720                         <name>observable_identifier</name>
721                     </field>
722                     <field>
723                         <name>observer_model</name>
724                     </field>
725                     <field>
726                         <name>observer_identifier</name>
727                     </field>
728                     <field>
729                         <name>observed_event</name>
730                     </field>
731                 </index>
732                 <index>
733                     <name>observer</name>
734                     <field>
735                         <name>observer_model</name>
736                     </field>
737                     <field>
738                         <name>observer_identifier</name>
739                     </field>
740                 </index>
741             </declaration>
742         </table>'), 'Tinebase', 3);
743
744         $this->setApplicationVersion('Tinebase', '10.15');
745     }
746
747     /**
748      * update to 10.16
749      *
750      * add container xprops column
751      */
752     public function update_15()
753     {
754         if (! $this->_backend->columnExists('xprops', 'container')) {
755             $declaration = new Setup_Backend_Schema_Field_Xml(
756                 '<field>
757                     <name>xprops</name>
758                     <type>text</type>
759                     <notnull>false</notnull>
760                     <default>NULL</default>
761                 </field>
762             ');
763             $this->_backend->addCol('container', $declaration);
764             $this->setTableVersion('container', 12);
765         }
766
767         $this->setApplicationVersion('Tinebase', '10.16');
768     }
769
770     /**
771      * update node acl: find all nodes that have containers, copy acl to node and remove container
772      *
773      * TODO allow to call from cli?
774      */
775     public function update_16()
776     {
777         // this is needed for filesystem operations
778         $this->_addRevisionPreviewCountCol();
779
780         $applications = Tinebase_Application::getInstance()->getApplications();
781         $setupUser = Setup_Update_Abstract::getSetupFromConfigOrCreateOnTheFly();
782         if ($setupUser) {
783             Tinebase_Core::set(Tinebase_Core::USER, $setupUser);
784         }
785         foreach ($applications as $application) {
786             if ($setupUser && ! $setupUser->hasRight($application, Tinebase_Acl_Rights::RUN)) {
787                 if (Tinebase_Core::isLogLevel(Zend_Log::ERR)) {
788                     Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__
789                         . ' Skipping ' . $application->name . ' because setupuser has no RUN right');
790                 }
791                 continue;
792             }
793
794             $this->_migrateAclForApplication($application, Tinebase_FileSystem::FOLDER_TYPE_PERSONAL);
795             $this->_migrateAclForApplication($application, Tinebase_FileSystem::FOLDER_TYPE_SHARED);
796         }
797
798         $this->setApplicationVersion('Tinebase', '10.17');
799     }
800
801     /**
802      * @param $application
803      * @param $type
804      */
805     protected function _migrateAclForApplication($application, $type)
806     {
807         $path = Tinebase_FileSystem::getInstance()->getApplicationBasePath(
808             $application->name,
809             $type
810         );
811         try {
812             $parentNode = Tinebase_FileSystem::getInstance()->stat($path);
813         } catch (Tinebase_Exception_NotFound $tenf) {
814             return;
815         }
816
817         $childNodes = Tinebase_FileSystem::getInstance()->getTreeNodeChildren($parentNode);
818
819         if (count($childNodes) === 0) {
820             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
821                 . " No container nodes found for application " . $application->name);
822             return;
823         }
824
825         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
826             . ' ' . count($childNodes) . " nodes found for application " . $application->name);
827
828         if ($type === Tinebase_FileSystem::FOLDER_TYPE_PERSONAL) {
829             foreach ($childNodes as $accountNode) {
830                 $personalNodes = Tinebase_FileSystem::getInstance()->getTreeNodeChildren($accountNode);
831                 $this->_moveAclFromContainersToNodes($personalNodes);
832             }
833         } else {
834             // shared
835             $this->_moveAclFromContainersToNodes($childNodes);
836         }
837     }
838
839     /**
840      * @param Tinebase_Record_RecordSet $nodes
841      *
842      * TODO move to TFS?
843      */
844     protected function _moveAclFromContainersToNodes(Tinebase_Record_RecordSet $nodes)
845     {
846         foreach ($nodes as $node) {
847             try {
848                 $container = Tinebase_Container::getInstance()->getContainerById($node->name);
849             } catch (Tinebase_Exception_NotFound $tenf) {
850                 // already converted
851                 continue;
852             } catch (Tinebase_Exception_InvalidArgument $teia) {
853                 // already converted
854                 continue;
855             }
856             //print_r($container->toArray());
857             if ($container->model === 'HumanResources_Model_Employee') {
858                 // fix broken HR template container to prevent problems when removing data
859                 $container->model = 'Tinebase_Model_Tree_Node';
860                 Tinebase_Container::getInstance()->update($container);
861             }
862
863             // set container acl in node
864             $grants = Tinebase_Container::getInstance()->getGrantsOfContainer($container, /* ignore acl */ true);
865             Tinebase_FileSystem::getInstance()->setGrantsForNode($node, $grants);
866
867             // set container name in node
868             $node->name = $container->name;
869             // check if node exists and if yes: attach uid
870             $parentNode = Tinebase_FileSystem::getInstance()->get($node->parent_id);
871             $parentPath = Tinebase_FileSystem::getInstance()->getPathOfNode($parentNode, true);
872             if (Tinebase_FileSystem::getInstance()->fileExists($parentPath . '/' . $node->name)) {
873                 $node->name .= ' ' . Tinebase_Record_Abstract::generateUID(8);
874             }
875
876             $node->acl_node = $node->getId();
877             Tinebase_FileSystem::getInstance()->update($node);
878             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
879                 . ' Updated node acl for ' . $node->name .' (container id: ' . $container->getId() . ')');
880
881             // remove old acl container
882             Tinebase_Container::getInstance()->deleteContainer($container, /* ignore acl */ true);
883             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
884                 . ' Removed old container ' . $container->name);
885         }
886     }
887
888     /**
889      * update to 10.18
890      *
891      * Add fulltext index for description field
892      */
893     public function update_17()
894     {
895         $declaration = new Setup_Backend_Schema_Index_Xml('
896             <index>
897                 <name>description</name>
898                 <fulltext>true</fulltext>
899                 <field>
900                     <name>description</name>
901                 </field>
902             </index>
903         ');
904
905         $this->_backend->addIndex('tree_fileobjects', $declaration);
906
907         $this->setTableVersion('tree_fileobjects', '5');
908         $this->setApplicationVersion('Tinebase', '10.18');
909     }
910
911     /**
912      * update to 10.19
913      *
914      * Add fulltext search index for tags description
915      */
916     public function update_18()
917     {
918         $declaration = new Setup_Backend_Schema_Index_Xml('
919             <index>
920                 <name>description</name>
921                 <fulltext>true</fulltext>
922                 <field>
923                     <name>description</name>
924                 </field>
925             </index>
926         ');
927
928         try {
929             $this->_backend->dropIndex('tags', 'description');
930         } catch (Exception $e) {
931             // Ignore, if there is no index, we can just go on and create one.
932         }
933
934         $this->_backend->addIndex('tags', $declaration);
935
936         $this->setTableVersion('tags', 8);
937         $this->setApplicationVersion('Tinebase', '10.19');
938     }
939
940     /**
941      * update to 10.20
942      *
943      * Make tags description a longtext field
944      */
945     public function update_19()
946     {
947         $declaration = new Setup_Backend_Schema_Field_Xml('
948             <field>
949                 <name>description</name>
950                 <!--Long text!-->
951                 <length>2147483647</length>
952                 <type>text</type>
953                 <default>NULL</default>
954             </field>
955         ');
956
957         $this->_backend->alterCol('tags', $declaration);
958
959         $this->setTableVersion('tags', 9);
960         $this->setApplicationVersion('Tinebase', '10.20');
961     }
962
963     /**
964      * update to 10.21
965      *
966      * add new file system tasks to scheduler
967      */
968     public function update_20()
969     {
970         $scheduler = Tinebase_Core::getScheduler();
971         Tinebase_Scheduler_Task::addFileSystemSizeRecalculation($scheduler);
972         Tinebase_Scheduler_Task::addFileSystemCheckIndexTask($scheduler);
973
974         $this->setApplicationVersion('Tinebase', '10.21');
975     }
976
977     /**
978      * update to 10.22
979      *
980      * add favorite column to importexport_definition
981      */
982     public function update_21()
983     {
984         if (! $this->_backend->columnExists('favorite', 'importexport_definition')) {
985             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
986                     <name>icon_class</name>
987                     <type>text</type>
988                     <length>255</length>
989                 </field>');
990             $this->_backend->addCol('importexport_definition', $declaration);
991
992             $declaration = new Setup_Backend_Schema_Field_Xml('
993                 <field>
994                     <name>favorite</name>
995                     <type>boolean</type>
996                 </field>');
997             $this->_backend->addCol('importexport_definition', $declaration);
998
999             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
1000                     <name>order</name>
1001                     <type>integer</type>
1002                     <notnull>true</notnull>
1003                     <default>0</default>
1004                 </field>');
1005             $this->_backend->addCol('importexport_definition', $declaration);
1006
1007             $this->setTableVersion('importexport_definition', 9);
1008         }
1009
1010         $this->setApplicationVersion('Tinebase', '10.22');
1011     }
1012
1013     /**
1014      * update to 10.23
1015      *
1016      * add preview_count column to tree_filerevisions
1017      */
1018     public function update_22()
1019     {
1020         $this->_addRevisionPreviewCountCol();
1021         $this->setApplicationVersion('Tinebase', '10.23');
1022     }
1023
1024     protected function _addRevisionPreviewCountCol()
1025     {
1026         if (! $this->_backend->columnExists('preview_count', 'tree_filerevisions')) {
1027             $declaration = new Setup_Backend_Schema_Field_Xml(
1028                 '<field>
1029                     <name>preview_count</name>
1030                     <type>integer</type>
1031                     <length>64</length>
1032                     <notnull>true</notnull>
1033                     <default>0</default>
1034                 </field>');
1035             $this->_backend->addCol('tree_filerevisions', $declaration);
1036             $this->setTableVersion('tree_filerevisions', 2);
1037         }
1038     }
1039
1040     /**
1041      * update to 10.24
1042      *
1043      * 0013032: add GRANT_DOWNLOAD
1044      * 0013034: add GRANT_PUBLISH
1045      */
1046     public function update_23()
1047     {
1048         $this->_addNotificationProps();
1049         
1050         // get all folder nodes with own acl
1051         $searchFilter = new Tinebase_Model_Tree_Node_Filter(array(
1052             array(
1053                 'field'     => 'type',
1054                 'operator'  => 'equals',
1055                 'value'     => Tinebase_Model_Tree_FileObject::TYPE_FOLDER
1056             )
1057         ), Tinebase_Model_Filter_FilterGroup::CONDITION_AND, array('ignoreAcl' => true));
1058         $folders = Tinebase_FileSystem::getInstance()->searchNodes($searchFilter);
1059         $updateCount = 0;
1060         foreach ($folders as $folder) {
1061             if ($folder->acl_node === $folder->getId()) {
1062                 $grants = Tinebase_FileSystem::getInstance()->getGrantsOfContainer($folder, /* ignoreAcl */ true);
1063                 foreach ($grants as $grant) {
1064                     // add download & publish for admins and only download for the rest
1065                     if ($grant->{Tinebase_Model_Grants::GRANT_ADMIN}) {
1066                         $grant->{Tinebase_Model_Grants::GRANT_DOWNLOAD} = true;
1067                         $grant->{Tinebase_Model_Grants::GRANT_PUBLISH} = true;
1068                     } else {
1069                         $grant->{Tinebase_Model_Grants::GRANT_DOWNLOAD} = true;
1070                     }
1071                 }
1072                 Tinebase_FileSystem::getInstance()->setGrantsForNode($folder, $grants);
1073                 $updateCount++;
1074             }
1075         }
1076
1077         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
1078             . ' Added DOWNLOAD & PUBLISH grants to ' . $updateCount . ' folder nodes');
1079
1080         $this->setApplicationVersion('Tinebase', '10.24');
1081     }
1082
1083     /**
1084      * update to 10.25
1085      *
1086      * add notification props
1087      */
1088     public function update_24()
1089     {
1090         $this->_addNotificationProps();
1091         $this->setApplicationVersion('Tinebase', '10.25');
1092     }
1093
1094     protected function _addNotificationProps()
1095     {
1096         if (! $this->_backend->columnExists('notificationProps', 'tree_nodes')) {
1097             $declaration = new Setup_Backend_Schema_Field_Xml(
1098                 '<field>
1099                     <name>notificationProps</name>
1100                     <type>text</type>
1101                     <length>65535</length>
1102                 </field>
1103             ');
1104             $this->_backend->addCol('tree_nodes', $declaration);
1105             $this->setTableVersion('tree_nodes', 3);
1106         }
1107     }
1108
1109     /**
1110      * update to 10.26
1111      *
1112      * add scope column to importexport_definition
1113      */
1114     public function update_25()
1115     {
1116         if (! $this->_backend->columnExists('scope', 'importexport_definition')) {
1117             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
1118                     <name>scope</name>
1119                     <type>text</type>
1120                     <length>255</length>
1121                 </field>');
1122             $this->_backend->addCol('importexport_definition', $declaration);
1123
1124             $this->setTableVersion('importexport_definition', 10);
1125         }
1126
1127         $this->setApplicationVersion('Tinebase', '10.26');
1128     }
1129
1130     /**
1131      * update to 10.27
1132      *
1133      * change role_accounts id to uuid
1134      */
1135     public function update_26()
1136     {
1137         $declaration = new Setup_Backend_Schema_Field_Xml('<field>
1138                     <name>id</name>
1139                     <type>text</type>
1140                     <length>40</length>
1141                 </field>');
1142         $this->_backend->alterCol('role_accounts', $declaration);
1143
1144         $this->setTableVersion('role_accounts', 4);
1145         $this->setApplicationVersion('Tinebase', '10.27');
1146     }
1147
1148     /**
1149      * update to 10.28
1150      *
1151      * add scope column to importexport_definition
1152      */
1153     public function update_27()
1154     {
1155         if (! $this->_backend->columnExists('format', 'importexport_definition')) {
1156             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
1157                     <name>format</name>
1158                     <type>text</type>
1159                     <length>255</length>
1160                 </field>');
1161             $this->_backend->addCol('importexport_definition', $declaration);
1162
1163             $this->setTableVersion('importexport_definition', 11);
1164         }
1165
1166         $this->setApplicationVersion('Tinebase', '10.28');
1167     }
1168
1169     /**
1170      * update to 10.29
1171      *
1172      * add scope column to importexport_definition
1173      */
1174     public function update_28()
1175     {
1176         foreach (Tinebase_Application::getInstance()->getApplications() as $application) {
1177             Setup_Controller::getInstance()->createImportExportDefinitions($application);
1178         }
1179
1180         $this->setApplicationVersion('Tinebase', '10.29');
1181     }
1182 }