Tinebase_Setup10 - handle outdated table structure of uninstalled apps
[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         $this->_addIsDeletedToTreeNodes();
21
22         $release9 = new Tinebase_Setup_Update_Release9($this->_backend);
23         $release9->update_9();
24         $this->setApplicationVersion('Tinebase', '10.1');
25     }
26
27     /**
28      * update to 10.2
29      *
30      * @see 0012300: add container owner column
31      */
32     public function update_1()
33     {
34         $release9 = new Tinebase_Setup_Update_Release9($this->_backend);
35         try {
36             $release9->update_4();
37         } catch (Zend_Db_Exception $zde) {
38             Tinebase_Exception::log($zde);
39         }
40         $this->setApplicationVersion('Tinebase', '10.2');
41     }
42
43     /**
44      * update to 10.3
45      *
46      * change length of groups.description column from varchar(255) to text
47      */
48     public function update_2()
49     {
50         $release9 = new Tinebase_Setup_Update_Release9($this->_backend);
51         $release9->update_5();
52         $this->setApplicationVersion('Tinebase', '10.3');
53     }
54
55     /**
56      * update to 10.4
57      *
58      * dd numberables
59      */
60     public function update_3()
61     {
62         $release9 = new Tinebase_Setup_Update_Release9($this->_backend);
63         $release9->update_10();
64         $this->setApplicationVersion('Tinebase', '10.4');
65     }
66
67     /**
68      * needs to be done again to make sure we have the column!
69      *
70      * @see 0012300: add container owner column
71      */
72     public function update_4()
73     {
74         $release9 = new Tinebase_Setup_Update_Release9($this->_backend);
75         try {
76             $release9->update_4();
77         } catch (Zend_Db_Exception $zde) {
78             Tinebase_Exception::log($zde);
79         }
80         $this->setApplicationVersion('Tinebase', '10.5');
81     }
82
83     /**
84      * update to 10.6
85      *
86      * add account sync scheduler job
87      */
88     public function update_5()
89     {
90         $scheduler = Tinebase_Core::getScheduler();
91         Tinebase_Scheduler_Task::addAccountSyncTask($scheduler);
92
93         $this->setApplicationVersion('Tinebase', '10.6');
94     }
95
96     /**
97      * update to 10.7
98      *
99      * update timemachine_modlog table
100      */
101     public function update_6()
102     {
103         if (!$this->_backend->columnExists('instance_id', 'timemachine_modlog')) {
104
105             $this->_backend->renameTable('timemachine_modlog', 'timemachine_modlog_bkp');
106             $db = Tinebase_Core::getDb();
107             if ($db instanceof Zend_Db_Adapter_Pdo_Pgsql) {
108                 $db->exec('ALTER INDEX "' . SQL_TABLE_PREFIX . 'timemachine_modlog_pkey" RENAME TO ' . SQL_TABLE_PREFIX . 'timemachine_modlog_pkey_bkp');
109                 $db->exec('ALTER INDEX "' . SQL_TABLE_PREFIX . 'timemachine_modlog_seq" RENAME TO ' . SQL_TABLE_PREFIX . 'timemachine_modlog_seq_bkp');
110                 $db->exec('ALTER INDEX "' . SQL_TABLE_PREFIX . 'timemachine_modlog_unique-fields_key" RENAME TO "' . SQL_TABLE_PREFIX . 'timemachine_modlog_unique-fields_key_bkp"');
111             }
112
113             $this->_backend->createTable(new Setup_Backend_Schema_Table_Xml('<table>
114                 <name>timemachine_modlog</name>
115                 <version>5</version>
116                 <declaration>
117                     <field>
118                         <name>id</name>
119                         <type>text</type>
120                         <length>40</length>
121                         <notnull>true</notnull>
122                     </field>
123                     <field>
124                         <name>instance_id</name>
125                         <type>text</type>
126                         <length>40</length>
127                         <notnull>false</notnull>
128                     </field>
129                     <field>
130                         <name>instance_seq</name>
131                         <type>integer</type>
132                         <notnull>true</notnull>
133                         <autoincrement>true</autoincrement>
134                     </field>
135                     <field>
136                         <name>change_type</name>
137                         <type>text</type>
138                         <length>40</length>
139                         <notnull>false</notnull>
140                     </field>
141                     <field>
142                         <name>application_id</name>
143                         <type>text</type>
144                         <length>40</length>
145                         <notnull>true</notnull>
146                     </field>
147                     <field>
148                         <name>record_id</name>
149                         <type>text</type>
150                         <length>40</length>
151                         <notnull>false</notnull>
152                     </field>
153                     <field>
154                         <name>record_type</name>
155                         <type>text</type>
156                         <length>64</length>
157                         <notnull>false</notnull>
158                     </field>
159                     <field>
160                         <name>record_backend</name>
161                         <type>text</type>
162                         <length>64</length>
163                         <notnull>false</notnull>
164                     </field>
165                     <field>
166                         <name>modification_time</name>
167                         <type>datetime</type>
168                         <notnull>true</notnull>
169                     </field>
170                     <field>
171                         <name>modification_account</name>
172                         <type>text</type>
173                         <length>40</length>
174                         <notnull>true</notnull>
175                     </field>
176                     <field>
177                         <name>modified_attribute</name>
178                         <type>text</type>
179                         <length>64</length>
180                         <notnull>false</notnull>
181                     </field>
182                     <field>
183                         <name>old_value</name>
184                         <type>clob</type>
185                     </field>
186                     <field>
187                         <name>new_value</name>
188                         <type>clob</type>
189                     </field>
190                     <field>
191                         <name>seq</name>
192                         <type>integer</type>
193                         <length>64</length>
194                     </field>
195                     <field>
196                         <name>client</name>
197                         <type>text</type>
198                         <length>255</length>
199                         <notnull>true</notnull>
200                     </field>
201                     <index>
202                         <name>id</name>
203                         <primary>true</primary>
204                         <field>
205                             <name>id</name>
206                         </field>
207                     </index>
208                     <index>
209                         <name>instance_id</name>
210                         <field>
211                             <name>instance_id</name>
212                         </field>
213                     </index>
214                     <index>
215                         <name>instance_seq</name>
216                         <unique>true</unique>
217                         <field>
218                             <name>instance_seq</name>
219                         </field>
220                     </index>
221                     <index>
222                         <name>seq</name>
223                         <field>
224                             <name>seq</name>
225                         </field>
226                     </index>
227                     <index>
228                         <name>unique-fields</name>
229                         <unique>true</unique>
230                         <field>
231                             <name>application_id</name>
232                         </field>
233                         <field>
234                             <name>record_id</name>
235                         </field>
236                         <field>
237                             <name>record_type</name>
238                         </field>
239                         <field>
240                             <name>modification_time</name>
241                         </field>
242                         <field>
243                             <name>modification_account</name>
244                         </field>
245                         <field>
246                             <name>modified_attribute</name>
247                         </field>
248                         <field>
249                             <name>seq</name>
250                         </field>
251                     </index>
252                 </declaration>
253             </table>'));
254
255
256
257             $appIds[] = Tinebase_Application::getInstance()->getApplicationByName('Addressbook')->getId();
258             if (Tinebase_Application::getInstance()->isInstalled('Calendar')) {
259                 $appIds[] = Tinebase_Application::getInstance()->getApplicationByName('Calendar')->getId();
260             }
261
262             $select = $db->select()->from(SQL_TABLE_PREFIX . 'timemachine_modlog_bkp')->order('modification_time ASC')
263                 ->where($db->quoteInto($db->quoteIdentifier('application_id') . ' IN (?)', $appIds))
264                 ->where($db->quoteInto($db->quoteIdentifier('record_type') . ' IN (?)', array('Addressbook_Model_Contact', 'Calendar_Model_Resource')))
265                 ->where($db->quoteInto($db->quoteIdentifier('modified_attribute') . ' IN (?)', array('email', 'email_home')));
266
267             $stmt = $db->query($select);
268             $resultArray = $stmt->fetchAll(Zend_Db::FETCH_ASSOC);
269
270             if (count($resultArray) > 0) {
271                 foreach($resultArray as $row) {
272                     $row['client'] = 'update script';
273                     $db->insert(SQL_TABLE_PREFIX . 'timemachine_modlog', $row);
274                 }
275             }
276
277             $this->setTableVersion('timemachine_modlog', '5');
278         }
279
280         $this->setApplicationVersion('Tinebase', '10.7');
281     }
282
283     /**
284      * update to 10.8
285      *
286      * update roles and application table
287      */
288     public function update_7()
289     {
290         if (!$this->_backend->columnExists('is_deleted', 'roles')) {
291             $query = $this->_backend->addAddCol(null, 'roles',
292                 new Setup_Backend_Schema_Field_Xml('<field>
293                     <name>is_deleted</name>
294                     <type>boolean</type>
295                     <default>false</default>
296                 </field>'), 'last_modified_time'
297             );
298             $query = $this->_backend->addAddCol($query, 'roles',
299                 new Setup_Backend_Schema_Field_Xml('<field>
300                     <name>deleted_by</name>
301                     <type>text</type>
302                     <length>40</length>
303                 </field>'), 'is_deleted'
304             );
305             $query = $this->_backend->addAddCol($query, 'roles',
306                 new Setup_Backend_Schema_Field_Xml('<field>
307                     <name>deleted_time</name>
308                     <type>datetime</type>
309                 </field>'), 'deleted_by'
310             );
311             $query = $this->_backend->addAddCol($query, 'roles',
312                 new Setup_Backend_Schema_Field_Xml('<field>
313                     <name>seq</name>
314                     <type>integer</type>
315                     <notnull>true</notnull>
316                     <default>0</default>
317                 </field>'), 'deleted_time'
318             );
319             $this->_backend->execQueryVoid($query);
320             $this->setTableVersion('roles', '2');
321         }
322
323         if (!$this->_backend->columnExists('state', 'applications')) {
324
325             $this->_backend->addCol('applications',
326                 new Setup_Backend_Schema_Field_Xml('<field>
327                     <name>state</name>
328                     <type>text</type>
329                     <length>65535</length>
330                     <notnull>false</notnull>
331                 </field>')
332             );
333
334             $this->setTableVersion('applications', '4');
335         }
336
337         $this->setApplicationVersion('Tinebase', '10.8');
338     }
339
340     /**
341      * update to 10.9
342      *
343      * add client row to timemachine_modlog
344      *
345      * @see 0012830: add client user agent to modlog
346      */
347     public function update_8()
348     {
349         if (! $this->_backend->columnExists('client', 'timemachine_modlog')) {
350             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
351                     <name>client</name>
352                     <type>text</type>
353                     <length>255</length>
354                     <notnull>true</notnull>
355                 </field>');
356             $this->_backend->addCol('timemachine_modlog', $declaration);
357
358             $this->setTableVersion('timemachine_modlog', '5');
359         }
360
361         $this->setApplicationVersion('Tinebase', '10.9');
362     }
363
364     /**
365      * update to 10.10
366      *
367      * adding path filter feature switch & structure update
368      */
369     public function update_9()
370     {
371         $this->_addIsDeletedToTreeNodes();
372
373         $this->dropTable('path');
374
375         $declaration = new Setup_Backend_Schema_Table_Xml('<table>
376             <name>path</name>
377             <version>2</version>
378             <requirements>
379                 <required>mysql >= 5.6.4</required>
380             </requirements>
381             <declaration>
382                 <field>
383                     <name>id</name>
384                     <type>text</type>
385                     <length>40</length>
386                     <notnull>true</notnull>
387                 </field>
388                 <field>
389                     <name>path</name>
390                     <type>text</type>
391                     <length>65535</length>
392                     <notnull>true</notnull>
393                 </field>
394                 <field>
395                     <name>shadow_path</name>
396                     <type>text</type>
397                     <length>65535</length>
398                     <notnull>true</notnull>
399                 </field>
400                 <field>
401                     <name>creation_time</name>
402                     <type>datetime</type>
403                 </field>
404                 <index>
405                     <name>id</name>
406                     <primary>true</primary>
407                     <field>
408                         <name>id</name>
409                     </field>
410                 </index>
411                 <index>
412                 <name>path</name>
413                     <fulltext>true</fulltext>
414                     <field>
415                         <name>path</name>
416                     </field>
417                 </index>
418                 <index>
419                     <name>shadow_path</name>
420                     <fulltext>true</fulltext>
421                     <field>
422                         <name>shadow_path</name>
423                     </field>
424                 </index>
425             </declaration>
426         </table>');
427
428         $this->createTable('path', $declaration, 'Tinebase', 2);
429
430         try {
431             $setupUser = Setup_Update_Abstract::getSetupFromConfigOrCreateOnTheFly();
432             if ($setupUser) {
433                 Tinebase_Core::set(Tinebase_Core::USER, $setupUser);
434                 Tinebase_Controller::getInstance()->rebuildPaths();
435             } else {
436                 if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) {
437                     Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__
438                         . ' Could not find valid setupuser. Skipping rebuildPaths: you might need to run this manually.');
439                 }
440             }
441         } catch (Exception $e) {
442             Tinebase_Exception::log($e);
443             Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__
444                 . ' Skipping rebuildPaths: you might need to run this manually.');
445         }
446
447         $this->setApplicationVersion('Tinebase', '10.10');
448     }
449
450     /**
451      * update to 10.11
452      *
453      * create external_fulltext table
454      */
455     public function update_10()
456     {
457         $this->_backend->createTable(new Setup_Backend_Schema_Table_Xml('<table>
458             <name>external_fulltext</name>
459             <version>1</version>
460             <declaration>
461                 <field>
462                     <name>id</name>
463                     <type>text</type>
464                     <length>40</length>
465                     <notnull>true</notnull>
466                 </field>
467                 <field>
468                     <name>text_data</name>
469                     <type>text</type>
470                     <length>2147483647</length>
471                     <notnull>true</notnull>
472                 </field>
473                 <index>
474                     <name>id</name>
475                     <primary>true</primary>
476                     <field>
477                         <name>id</name>
478                     </field>
479                 </index>
480                 <index>
481                     <name>text_data</name>
482                     <fulltext>true</fulltext>
483                     <field>
484                         <name>text_data</name>
485                     </field>
486                 </index>
487             </declaration>
488         </table>'), 'Tinebase', 'external_fulltext');
489
490         $this->setApplicationVersion('Tinebase', '10.11');
491     }
492
493     /**
494      * update to 10.12
495      *
496      * add revision_size to tree_fileobjects
497      */
498     public function update_11()
499     {
500
501         if (!$this->_backend->columnExists('total_size', 'tree_fileobjects')) {
502             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
503                     <name>revision_size</name>
504                     <type>integer</type>
505                     <notnull>true</notnull>
506                     <default>0</default>
507                 </field>');
508
509             $query = $this->_backend->addAddCol('', 'tree_fileobjects', $declaration);
510
511             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
512                     <name>indexed_hash</name>
513                     <type>text</type>
514                     <length>40</length>
515                 </field>');
516
517             $query = $this->_backend->addAddCol($query, 'tree_fileobjects', $declaration);
518
519             $this->_backend->execQueryVoid($query);
520
521             $this->setTableVersion('tree_fileobjects', '4');
522         }
523
524         $this->setApplicationVersion('Tinebase', '10.12');
525     }
526
527     /**
528      * add tree_node_acl
529      */
530     public function update_12()
531     {
532         if (! $this->_backend->columnExists('acl_node', 'tree_nodes')) {
533             $declaration = new Setup_Backend_Schema_Field_Xml(
534                 '<field>
535                     <name>acl_node</name>
536                     <type>text</type>
537                     <length>40</length>
538                 </field>
539             ');
540             $query = $this->_backend->addAddCol('', 'tree_nodes', $declaration);
541             $declaration = new Setup_Backend_Schema_Field_Xml(
542                 '<field>
543                     <name>revisionProps</name>
544                     <type>text</type>
545                     <length>65535</length>
546                 </field>');
547             $query = $this->_backend->addAddCol($query, 'tree_nodes', $declaration);
548             $this->_backend->execQueryVoid($query);
549
550             $this->setTableVersion('tree_nodes', 2);
551
552             $declaration = new Setup_Backend_Schema_Table_Xml('<table>
553             <name>tree_node_acl</name>
554             <version>1</version>
555             <declaration>
556                 <field>
557                     <name>id</name>
558                     <type>text</type>
559                     <length>40</length>
560                     <notnull>true</notnull>
561                 </field>
562                 <field>
563                     <name>record_id</name>
564                     <type>text</type>
565                     <length>40</length>
566                     <notnull>true</notnull>
567                 </field>
568                 <field>
569                     <name>account_type</name>
570                     <type>text</type>
571                     <length>32</length>
572                     <default>user</default>
573                     <notnull>true</notnull>
574                 </field>
575                 <field>
576                     <name>account_id</name>
577                     <type>text</type>
578                     <length>40</length>
579                     <notnull>true</notnull>
580                 </field>
581                 <field>
582                     <name>account_grant</name>
583                     <type>text</type>
584                     <length>40</length>
585                     <notnull>true</notnull>
586                 </field>
587
588                 <index>
589                     <name>record_id-account-type-account_id-account_grant</name>
590                     <primary>true</primary>
591                     <field>
592                         <name>id</name>
593                     </field>
594                     <field>
595                         <name>record_id</name>
596                     </field>
597                     <field>
598                         <name>account_type</name>
599                     </field>
600                     <field>
601                         <name>account_id</name>
602                     </field>
603                     <field>
604                         <name>account_grant</name>
605                     </field>
606                 </index>
607                 <index>
608                     <name>id-account_type-account_id</name>
609                     <field>
610                         <name>record_id</name>
611                     </field>
612                     <field>
613                         <name>account_type</name>
614                     </field>
615                     <field>
616                         <name>account_id</name>
617                     </field>
618                 </index>
619                 <index>
620                     <name>tree_node_acl::record_id--tree_nodes::id</name>
621                     <field>
622                         <name>record_id</name>
623                     </field>
624                     <foreign>true</foreign>
625                     <reference>
626                         <table>tree_nodes</table>
627                         <field>id</field>
628                         <ondelete>cascade</ondelete>
629                     </reference>
630                 </index>
631             </declaration>
632         </table>');
633             $this->createTable('tree_node_acl', $declaration);
634         }
635
636         $this->setApplicationVersion('Tinebase', '10.13');
637     }
638
639     /**
640      * update to 10.14
641      *
642      * add file revision cleanup task to scheduler
643      */
644     public function update_13()
645     {
646         $scheduler = Tinebase_Core::getScheduler();
647         Tinebase_Scheduler_Task::addFileRevisionCleanupTask($scheduler);
648
649         $this->setApplicationVersion('Tinebase', '10.14');
650     }
651
652     /**
653      * update to 10.15
654      *
655      * update record_observer
656      */
657     public function update_14()
658     {
659         $this->dropTable('record_observer', 'Tinebase');
660
661         $this->createTable('record_observer', new Setup_Backend_Schema_Table_Xml('<table>
662             <name>record_observer</name>
663             <version>4</version>
664             <declaration>
665                 <field>
666                     <name>id</name>
667                     <type>integer</type>
668                     <autoincrement>true</autoincrement>
669                 </field>
670                 <field>
671                     <name>observable_model</name>
672                     <type>text</type>
673                     <length>100</length>
674                     <notnull>true</notnull>
675                 </field>
676                 <field>
677                     <name>observable_identifier</name>
678                     <type>text</type>
679                     <length>40</length>
680                     <notnull>true</notnull>
681                 </field>
682                 <field>
683                     <name>observer_model</name>
684                     <type>text</type>
685                     <length>100</length>
686                     <notnull>true</notnull>
687                 </field>
688                 <field>
689                     <name>observer_identifier</name>
690                     <type>text</type>
691                     <length>40</length>
692                     <notnull>true</notnull>
693                 </field>
694                 <field>
695                     <name>observed_event</name>
696                     <type>text</type>
697                     <length>100</length>
698                     <notnull>true</notnull>
699                 </field>
700                 <field>
701                     <name>created_by</name>
702                     <type>text</type>
703                     <length>40</length>
704                 </field>
705                 <field>
706                     <name>creation_time</name>
707                     <type>datetime</type>
708                     <notnull>true</notnull>
709                 </field>
710                 <index>
711                     <name>id</name>
712                     <primary>true</primary>
713                     <field>
714                         <name>id</name>
715                     </field>
716                 </index>
717                 <index>
718                     <name>observable-observer-event</name>
719                     <unique>true</unique>
720                     <field>
721                         <name>observable_model</name>
722                     </field>
723                     <field>
724                         <name>observable_identifier</name>
725                     </field>
726                     <field>
727                         <name>observer_model</name>
728                     </field>
729                     <field>
730                         <name>observer_identifier</name>
731                     </field>
732                     <field>
733                         <name>observed_event</name>
734                     </field>
735                 </index>
736                 <index>
737                     <name>observer</name>
738                     <field>
739                         <name>observer_model</name>
740                     </field>
741                     <field>
742                         <name>observer_identifier</name>
743                     </field>
744                 </index>
745             </declaration>
746         </table>'), 'Tinebase', 3);
747
748         $this->setApplicationVersion('Tinebase', '10.15');
749     }
750
751     /**
752      * update to 10.16
753      *
754      * add container xprops column
755      */
756     public function update_15()
757     {
758         if (! $this->_backend->columnExists('xprops', 'container')) {
759             $declaration = new Setup_Backend_Schema_Field_Xml(
760                 '<field>
761                     <name>xprops</name>
762                     <type>text</type>
763                     <notnull>false</notnull>
764                     <default>NULL</default>
765                 </field>
766             ');
767             $this->_backend->addCol('container', $declaration);
768             $this->setTableVersion('container', 12);
769         }
770
771         $this->setApplicationVersion('Tinebase', '10.16');
772     }
773
774     /**
775      * update node acl: find all nodes that have containers, copy acl to node and remove container
776      *
777      * TODO allow to call from cli?
778      */
779     public function update_16()
780     {
781         $this->_addIsDeletedToTreeNodes();
782
783         // this is needed for filesystem operations
784         $this->_addRevisionPreviewCountCol();
785
786         $applications = Tinebase_Application::getInstance()->getApplications();
787         $setupUser = Setup_Update_Abstract::getSetupFromConfigOrCreateOnTheFly();
788         if ($setupUser) {
789             Tinebase_Core::set(Tinebase_Core::USER, $setupUser);
790         }
791         foreach ($applications as $application) {
792             if ($setupUser && ! $setupUser->hasRight($application, Tinebase_Acl_Rights::RUN)) {
793                 if (Tinebase_Core::isLogLevel(Zend_Log::ERR)) {
794                     Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__
795                         . ' Skipping ' . $application->name . ' because setupuser has no RUN right');
796                 }
797                 continue;
798             }
799
800             $this->_migrateAclForApplication($application, Tinebase_FileSystem::FOLDER_TYPE_PERSONAL);
801             $this->_migrateAclForApplication($application, Tinebase_FileSystem::FOLDER_TYPE_SHARED);
802         }
803
804         $this->setApplicationVersion('Tinebase', '10.17');
805     }
806
807     /**
808      * @param $application
809      * @param $type
810      */
811     protected function _migrateAclForApplication($application, $type)
812     {
813         $path = Tinebase_FileSystem::getInstance()->getApplicationBasePath(
814             $application->name,
815             $type
816         );
817         try {
818             $parentNode = Tinebase_FileSystem::getInstance()->stat($path);
819         } catch (Tinebase_Exception_NotFound $tenf) {
820             return;
821         }
822
823         $childNodes = Tinebase_FileSystem::getInstance()->getTreeNodeChildren($parentNode);
824
825         if (count($childNodes) === 0) {
826             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
827                 . " No container nodes found for application " . $application->name);
828             return;
829         }
830
831         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
832             . ' ' . count($childNodes) . " nodes found for application " . $application->name);
833
834         if ($type === Tinebase_FileSystem::FOLDER_TYPE_PERSONAL) {
835             foreach ($childNodes as $accountNode) {
836                 $personalNodes = Tinebase_FileSystem::getInstance()->getTreeNodeChildren($accountNode);
837                 $this->_moveAclFromContainersToNodes($personalNodes);
838             }
839         } else {
840             // shared
841             $this->_moveAclFromContainersToNodes($childNodes);
842         }
843     }
844
845     /**
846      * @param Tinebase_Record_RecordSet $nodes
847      *
848      * TODO move to TFS?
849      */
850     protected function _moveAclFromContainersToNodes(Tinebase_Record_RecordSet $nodes)
851     {
852         foreach ($nodes as $node) {
853             try {
854                 $container = Tinebase_Container::getInstance()->getContainerById($node->name);
855             } catch (Tinebase_Exception_NotFound $tenf) {
856                 // already converted
857                 continue;
858             } catch (Tinebase_Exception_InvalidArgument $teia) {
859                 // already converted
860                 continue;
861             }
862             //print_r($container->toArray());
863             if ($container->model === 'HumanResources_Model_Employee') {
864                 // fix broken HR template container to prevent problems when removing data
865                 $container->model = 'Tinebase_Model_Tree_Node';
866                 Tinebase_Container::getInstance()->update($container);
867             }
868
869             // set container acl in node
870             $grants = Tinebase_Container::getInstance()->getGrantsOfContainer($container, /* ignore acl */ true);
871             Tinebase_FileSystem::getInstance()->setGrantsForNode($node, $grants);
872
873             // set container name in node
874             $node->name = $container->name;
875             // check if node exists and if yes: attach uid
876             $parentNode = Tinebase_FileSystem::getInstance()->get($node->parent_id);
877             $parentPath = Tinebase_FileSystem::getInstance()->getPathOfNode($parentNode, true);
878             if (Tinebase_FileSystem::getInstance()->fileExists($parentPath . '/' . $node->name)) {
879                 $node->name .= ' ' . Tinebase_Record_Abstract::generateUID(8);
880             }
881
882             $node->acl_node = $node->getId();
883             Tinebase_FileSystem::getInstance()->update($node);
884             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
885                 . ' Updated node acl for ' . $node->name .' (container id: ' . $container->getId() . ')');
886
887             // remove old acl container
888             Tinebase_Container::getInstance()->deleteContainer($container, /* ignore acl */ true);
889             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
890                 . ' Removed old container ' . $container->name);
891         }
892     }
893
894     /**
895      * update to 10.18
896      *
897      * Add fulltext index for description field
898      */
899     public function update_17()
900     {
901         $declaration = new Setup_Backend_Schema_Index_Xml('
902             <index>
903                 <name>description</name>
904                 <fulltext>true</fulltext>
905                 <field>
906                     <name>description</name>
907                 </field>
908             </index>
909         ');
910
911         $this->_backend->addIndex('tree_fileobjects', $declaration);
912
913         $this->setTableVersion('tree_fileobjects', '5');
914         $this->setApplicationVersion('Tinebase', '10.18');
915     }
916
917     /**
918      * update to 10.19
919      *
920      * Add fulltext search index for tags description
921      */
922     public function update_18()
923     {
924         $declaration = new Setup_Backend_Schema_Index_Xml('
925             <index>
926                 <name>description</name>
927                 <fulltext>true</fulltext>
928                 <field>
929                     <name>description</name>
930                 </field>
931             </index>
932         ');
933
934         try {
935             $this->_backend->dropIndex('tags', 'description');
936         } catch (Exception $e) {
937             // Ignore, if there is no index, we can just go on and create one.
938         }
939
940         $this->_backend->addIndex('tags', $declaration);
941
942         $this->setTableVersion('tags', 8);
943         $this->setApplicationVersion('Tinebase', '10.19');
944     }
945
946     /**
947      * update to 10.20
948      *
949      * Make tags description a longtext field
950      */
951     public function update_19()
952     {
953         $declaration = new Setup_Backend_Schema_Field_Xml('
954             <field>
955                 <name>description</name>
956                 <!--Long text!-->
957                 <length>2147483647</length>
958                 <type>text</type>
959                 <default>NULL</default>
960             </field>
961         ');
962
963         $this->_backend->alterCol('tags', $declaration);
964
965         $this->setTableVersion('tags', 9);
966         $this->setApplicationVersion('Tinebase', '10.20');
967     }
968
969     /**
970      * update to 10.21
971      *
972      * add new file system tasks to scheduler
973      */
974     public function update_20()
975     {
976         $scheduler = Tinebase_Core::getScheduler();
977         Tinebase_Scheduler_Task::addFileSystemSizeRecalculation($scheduler);
978         Tinebase_Scheduler_Task::addFileSystemCheckIndexTask($scheduler);
979
980         $this->setApplicationVersion('Tinebase', '10.21');
981     }
982
983     /**
984      * update to 10.22
985      *
986      * add favorite column to importexport_definition
987      */
988     public function update_21()
989     {
990         if (! $this->_backend->columnExists('favorite', 'importexport_definition')) {
991             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
992                     <name>icon_class</name>
993                     <type>text</type>
994                     <length>255</length>
995                 </field>');
996             $this->_backend->addCol('importexport_definition', $declaration);
997
998             $declaration = new Setup_Backend_Schema_Field_Xml('
999                 <field>
1000                     <name>favorite</name>
1001                     <type>boolean</type>
1002                 </field>');
1003             $this->_backend->addCol('importexport_definition', $declaration);
1004
1005             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
1006                     <name>order</name>
1007                     <type>integer</type>
1008                     <notnull>true</notnull>
1009                     <default>0</default>
1010                 </field>');
1011             $this->_backend->addCol('importexport_definition', $declaration);
1012
1013             $this->setTableVersion('importexport_definition', 9);
1014         }
1015
1016         $this->setApplicationVersion('Tinebase', '10.22');
1017     }
1018
1019     /**
1020      * update to 10.23
1021      *
1022      * add preview_count column to tree_filerevisions
1023      */
1024     public function update_22()
1025     {
1026         $this->_addRevisionPreviewCountCol();
1027         $this->setApplicationVersion('Tinebase', '10.23');
1028     }
1029
1030     protected function _addRevisionPreviewCountCol()
1031     {
1032         if (! $this->_backend->columnExists('preview_count', 'tree_filerevisions')) {
1033             $declaration = new Setup_Backend_Schema_Field_Xml(
1034                 '<field>
1035                     <name>preview_count</name>
1036                     <type>integer</type>
1037                     <length>64</length>
1038                     <notnull>true</notnull>
1039                     <default>0</default>
1040                 </field>');
1041             $this->_backend->addCol('tree_filerevisions', $declaration);
1042             $this->setTableVersion('tree_filerevisions', 2);
1043         }
1044     }
1045
1046     /**
1047      * update to 10.24
1048      *
1049      * 0013032: add GRANT_DOWNLOAD
1050      * 0013034: add GRANT_PUBLISH
1051      */
1052     public function update_23()
1053     {
1054         $this->_addNotificationProps();
1055         $this->_addIsDeletedToTreeNodes();
1056
1057         // get all folder nodes with own acl
1058         $searchFilter = new Tinebase_Model_Tree_Node_Filter(array(
1059             array(
1060                 'field'     => 'type',
1061                 'operator'  => 'equals',
1062                 'value'     => Tinebase_Model_Tree_FileObject::TYPE_FOLDER
1063             )
1064         ), Tinebase_Model_Filter_FilterGroup::CONDITION_AND, array('ignoreAcl' => true));
1065         $folders = Tinebase_FileSystem::getInstance()->searchNodes($searchFilter);
1066         $updateCount = 0;
1067         foreach ($folders as $folder) {
1068             if ($folder->acl_node === $folder->getId()) {
1069                 $grants = Tinebase_FileSystem::getInstance()->getGrantsOfContainer($folder, /* ignoreAcl */ true);
1070                 foreach ($grants as $grant) {
1071                     // add download & publish for admins and only download for the rest
1072                     if ($grant->{Tinebase_Model_Grants::GRANT_ADMIN}) {
1073                         $grant->{Tinebase_Model_Grants::GRANT_DOWNLOAD} = true;
1074                         $grant->{Tinebase_Model_Grants::GRANT_PUBLISH} = true;
1075                     } else {
1076                         $grant->{Tinebase_Model_Grants::GRANT_DOWNLOAD} = true;
1077                     }
1078                 }
1079                 Tinebase_FileSystem::getInstance()->setGrantsForNode($folder, $grants);
1080                 $updateCount++;
1081             }
1082         }
1083
1084         if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
1085             . ' Added DOWNLOAD & PUBLISH grants to ' . $updateCount . ' folder nodes');
1086
1087         $this->setApplicationVersion('Tinebase', '10.24');
1088     }
1089
1090     /**
1091      * update to 10.25
1092      *
1093      * add notification props
1094      */
1095     public function update_24()
1096     {
1097         $this->_addNotificationProps();
1098         $this->setApplicationVersion('Tinebase', '10.25');
1099     }
1100
1101     protected function _addNotificationProps()
1102     {
1103         if (! $this->_backend->columnExists('notificationProps', 'tree_nodes')) {
1104             $declaration = new Setup_Backend_Schema_Field_Xml(
1105                 '<field>
1106                     <name>notificationProps</name>
1107                     <type>text</type>
1108                     <length>65535</length>
1109                 </field>
1110             ');
1111             $this->_backend->addCol('tree_nodes', $declaration);
1112             $this->setTableVersion('tree_nodes', 3);
1113         }
1114     }
1115
1116     /**
1117      * update to 10.26
1118      *
1119      * add scope column to importexport_definition
1120      */
1121     public function update_25()
1122     {
1123         if (! $this->_backend->columnExists('scope', 'importexport_definition')) {
1124             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
1125                     <name>scope</name>
1126                     <type>text</type>
1127                     <length>255</length>
1128                 </field>');
1129             $this->_backend->addCol('importexport_definition', $declaration);
1130
1131             $this->setTableVersion('importexport_definition', 10);
1132         }
1133
1134         $this->setApplicationVersion('Tinebase', '10.26');
1135     }
1136
1137     /**
1138      * update to 10.27
1139      *
1140      * change role_accounts id to uuid
1141      */
1142     public function update_26()
1143     {
1144         $declaration = new Setup_Backend_Schema_Field_Xml('<field>
1145                     <name>id</name>
1146                     <type>text</type>
1147                     <length>40</length>
1148                 </field>');
1149         $this->_backend->alterCol('role_accounts', $declaration);
1150
1151         $this->setTableVersion('role_accounts', 4);
1152         $this->setApplicationVersion('Tinebase', '10.27');
1153     }
1154
1155     /**
1156      * update to 10.28
1157      *
1158      * add scope column to importexport_definition
1159      */
1160     public function update_27()
1161     {
1162         if (! $this->_backend->columnExists('format', 'importexport_definition')) {
1163             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
1164                     <name>format</name>
1165                     <type>text</type>
1166                     <length>255</length>
1167                 </field>');
1168             $this->_backend->addCol('importexport_definition', $declaration);
1169
1170             $this->setTableVersion('importexport_definition', 11);
1171         }
1172
1173         $this->setApplicationVersion('Tinebase', '10.28');
1174     }
1175
1176     /**
1177      * update to 10.29
1178      *
1179      * add scope column to importexport_definition
1180      */
1181     public function update_28()
1182     {
1183         $this->_addIsDeletedToTreeNodes();
1184
1185         foreach (Tinebase_Application::getInstance()->getApplications() as $application) {
1186             Setup_Controller::getInstance()->createImportExportDefinitions($application);
1187         }
1188
1189         $this->setApplicationVersion('Tinebase', '10.29');
1190     }
1191
1192     /**
1193      * update to 10.30
1194      *
1195      * add scope column to importexport_definition
1196      */
1197     public function update_29()
1198     {
1199         $this->_backend->dropIndex('record_observer', 'observable-observer-event');
1200
1201         $this->_backend->alterCol('record_observer', new Setup_Backend_Schema_Field_Xml('<field>
1202                     <name>observable_identifier</name>
1203                     <type>text</type>
1204                     <length>40</length>
1205                     <notnull>false</notnull>
1206                 </field>'));
1207
1208         $this->_backend->addIndex('record_observer', new Setup_Backend_Schema_Index_Xml('<index>
1209                     <name>observable-observer-event</name>
1210                     <unique>true</unique>
1211                     <field>
1212                         <name>observable_model</name>
1213                     </field>
1214                     <field>
1215                         <name>observed_event</name>
1216                     </field>
1217                     <field>
1218                         <name>observable_identifier</name>
1219                     </field>
1220                     <field>
1221                         <name>observer_model</name>
1222                     </field>
1223                     <field>
1224                         <name>observer_identifier</name>
1225                     </field>
1226                 </index>'));
1227
1228         $this->setTableVersion('record_observer', 5);
1229
1230         $this->setApplicationVersion('Tinebase', '10.30');
1231     }
1232
1233     /**
1234      * update to 10.31
1235      *
1236      * add is_deleted column to tree nodes
1237      */
1238     public function update_30()
1239     {
1240         $this->_addIsDeletedToTreeNodes();
1241
1242         $this->setApplicationVersion('Tinebase', '10.31');
1243     }
1244
1245     protected function _addIsDeletedToTreeNodes()
1246     {
1247         if (! $this->_backend->columnExists('is_deleted', 'tree_nodes')) {
1248             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
1249                     <name>is_deleted</name>
1250                     <type>boolean</type>
1251                     <default>false</default>
1252                     <notnull>true</notnull>
1253                 </field>');
1254             $this->_backend->addCol('tree_nodes', $declaration);
1255
1256             $this->setTableVersion('tree_nodes', 4);
1257         }
1258
1259         if (! $this->_backend->columnExists('pin_protected', 'tree_nodes')) {
1260             $this->_backend->addCol('tree_nodes', new Setup_Backend_Schema_Field_Xml('<field>
1261                     <name>pin_protected</name>
1262                     <type>boolean</type>
1263                     <default>false</default>
1264                     <notnull>true</notnull>
1265                 </field>'));
1266         }
1267     }
1268
1269     /**
1270      * update to 10.32
1271      *
1272      * change container id from int to uuid
1273      */
1274     public function update_31()
1275     {
1276         //ATTENTION foreign constraints
1277
1278         try {
1279             $this->_backend->dropForeignKey('container_acl', 'container_acl::container_id--container::id');
1280         } catch (Exception $e) {}
1281         try {
1282             $this->_backend->dropForeignKey('container_content', 'container_content::container_id--container::id');
1283         } catch (Exception $e) {}
1284
1285         if ($this->_backend->tableExists('addressbook')) {
1286             try {
1287                 $this->_backend->dropForeignKey('addressbook', 'addressbook::container_id--container::id');
1288             } catch (Exception $e) {}
1289         }
1290         if ($this->_backend->tableExists('cal_events')) {
1291             try {
1292                 $this->_backend->dropForeignKey('cal_events', 'cal_events::container_id--container::id');
1293             } catch (Exception $e) {}
1294         }
1295         if ($this->_backend->tableExists('cal_resources')) {
1296             try {
1297                 $this->_backend->dropForeignKey('cal_resources', 'cal_resources::container_id--container::id');
1298             } catch (Exception $e) {}
1299         }
1300         if ($this->_backend->tableExists('cal_attendee')) {
1301             try {
1302                 $this->_backend->dropForeignKey('cal_attendee', 'cal_attendee::displaycontainer_id--container::id');
1303             } catch (Exception $e) {}
1304         }
1305         if ($this->_backend->tableExists('metacrm_lead')) {
1306             try {
1307                 $this->_backend->dropForeignKey('metacrm_lead', 'metacrm_lead::container_id--container::id');
1308             } catch (Exception $e) {}
1309         }
1310         if ($this->_backend->tableExists('sales_contracts')) {
1311             try {
1312                 $this->_backend->dropForeignKey('sales_contracts', 'sales_contracts::container_id--container::id');
1313             } catch (Exception $e) {}
1314         }
1315         if ($this->_backend->tableExists('sales_contracts')) {
1316             try {
1317                 $this->_backend->dropForeignKey('sales_contracts', 'tine20_erp_contracts::container_id--container::id');
1318             } catch (Exception $e) {}
1319         }
1320         if ($this->_backend->tableExists('timetracker_timeaccount')) {
1321             try {
1322                 $this->_backend->dropForeignKey('timetracker_timeaccount', 'timeaccount::container_id--container::id');
1323             } catch (Exception $e) {}
1324         }
1325         if ($this->_backend->tableExists('humanresources_contract')) {
1326             try {
1327                 $this->_backend->dropForeignKey('humanresources_contract', 'tine20_contract::feast_calendar_id--container::id');
1328             } catch (Exception $e) {}
1329         }
1330
1331
1332         if (version_compare($this->getApplicationVersion('Tinebase'), '10.32') < 0 ) {
1333             if ($this->getTableVersion('container') < 13) {
1334                 $this->_backend->alterCol('container', new Setup_Backend_Schema_Field_Xml('<field>
1335                             <name>id</name>
1336                             <type>text</type>
1337                             <length>40</length>
1338                             <notnull>true</notnull>
1339                         </field>'));
1340                 $this->setTableVersion('container', 13);
1341             }
1342
1343             if ($this->getTableVersion('container_acl') < 4) {
1344                 $this->_backend->alterCol('container_acl', new Setup_Backend_Schema_Field_Xml('<field>
1345                             <name>container_id</name>
1346                             <type>text</type>
1347                             <length>40</length>
1348                             <notnull>true</notnull>
1349                         </field>'));
1350                 $this->setTableVersion('container_acl', 4);
1351             }
1352
1353             if ($this->getTableVersion('container_content') < 3) {
1354                 $this->_backend->alterCol('container_content', new Setup_Backend_Schema_Field_Xml('<field>
1355                             <name>container_id</name>
1356                             <type>text</type>
1357                             <length>40</length>
1358                             <notnull>true</notnull>
1359                         </field>'));
1360                 $this->setTableVersion('container_content', 3);
1361             }
1362         }
1363
1364         if (version_compare($this->getApplicationVersion('Addressbook'), '10.6') < 0 ) {
1365             if ($this->getTableVersion('addressbook') < 25) {
1366                 $this->_backend->alterCol('addressbook', new Setup_Backend_Schema_Field_Xml('<field>
1367                     <name>container_id</name>
1368                     <type>text</type>
1369                     <length>40</length>
1370                     <notnull>false</notnull>
1371                 </field>'));
1372                 $this->setTableVersion('addressbook', 25);
1373             }
1374
1375             if ($this->getTableVersion('addressbook_lists') < 6) {
1376                 $this->_backend->alterCol('addressbook_lists', new Setup_Backend_Schema_Field_Xml('<field>
1377                     <name>container_id</name>
1378                     <type>text</type>
1379                     <length>40</length>
1380                     <notnull>false</notnull>
1381                 </field>'));
1382                 $this->setTableVersion('addressbook_lists', 25);
1383             }
1384
1385             $this->setApplicationVersion('Addressbook', '10.6');
1386         }
1387
1388         if (Tinebase_Application::getInstance()->isInstalled('Calendar') &&
1389                 version_compare($this->getApplicationVersion('Calendar'), '10.8') < 0 ) {
1390             if ($this->getTableVersion('cal_events') < 14) {
1391                 $this->_backend->alterCol('cal_events', new Setup_Backend_Schema_Field_Xml('<field>
1392                     <name>container_id</name>
1393                     <type>text</type>
1394                     <length>40</length>
1395                     <notnull>false</notnull>
1396                 </field>'));
1397                 $this->setTableVersion('cal_events', 14);
1398             }
1399
1400             if ($this->getTableVersion('cal_attendee') < 6) {
1401                 $this->_backend->alterCol('cal_attendee', new Setup_Backend_Schema_Field_Xml('<field>
1402                     <name>displaycontainer_id</name>
1403                     <type>text</type>
1404                     <length>40</length>
1405                     <notnull>false</notnull>
1406                 </field>'));
1407                 $this->setTableVersion('cal_attendee', 6);
1408             }
1409
1410             if ($this->getTableVersion('cal_resources') < 6) {
1411                 $this->_backend->alterCol('cal_resources', new Setup_Backend_Schema_Field_Xml('<field>
1412                     <name>container_id</name>
1413                     <type>text</type>
1414                     <length>40</length>
1415                     <notnull>false</notnull>
1416                 </field>'));
1417                 $this->setTableVersion('cal_resources', 6);
1418             }
1419
1420             $this->setApplicationVersion('Calendar', '10.8');
1421         }
1422
1423         if (Tinebase_Application::getInstance()->isInstalled('Crm') &&
1424             version_compare($this->getApplicationVersion('Crm'), '10.2') < 0 ) {
1425             if ($this->getTableVersion('metacrm_lead') < 10) {
1426                 $this->_backend->alterCol('metacrm_lead', new Setup_Backend_Schema_Field_Xml('<field>
1427                     <name>container_id</name>
1428                     <type>text</type>
1429                     <length>40</length>
1430                     <notnull>false</notnull>
1431                 </field>'));
1432                 $this->setTableVersion('metacrm_lead', 10);
1433             }
1434             $this->setApplicationVersion('Crm', '10.2');
1435         }
1436
1437         if (Tinebase_Application::getInstance()->isInstalled('Events') &&
1438             version_compare($this->getApplicationVersion('Events'), '10.2') < 0 ) {
1439             if ($this->getTableVersion('events_event') < 3) {
1440                 $this->_backend->alterCol('events_event', new Setup_Backend_Schema_Field_Xml('<field>
1441                     <name>container_id</name>
1442                     <type>text</type>
1443                     <length>40</length>
1444                     <notnull>false</notnull>
1445                 </field>'));
1446                 $this->setTableVersion('events_event', 3);
1447             }
1448             $this->setApplicationVersion('Events', '10.2');
1449         }
1450
1451         if (Tinebase_Application::getInstance()->isInstalled('Projects') &&
1452             version_compare($this->getApplicationVersion('Projects'), '10.2') < 0 ) {
1453             if ($this->getTableVersion('projects_project') < 4) {
1454                 $this->_backend->alterCol('projects_project', new Setup_Backend_Schema_Field_Xml('<field>
1455                     <name>container_id</name>
1456                     <type>text</type>
1457                     <length>40</length>
1458                     <notnull>false</notnull>
1459                 </field>'));
1460                 $this->setTableVersion('projects_project', 4);
1461             }
1462             $this->setApplicationVersion('Projects', '10.2');
1463         }
1464
1465         if (Tinebase_Application::getInstance()->isInstalled('Sales') &&
1466             version_compare($this->getApplicationVersion('Sales'), '10.9') < 0 ) {
1467             if ($this->getTableVersion('sales_contracts') < 10) {
1468                 $this->_backend->alterCol('sales_contracts', new Setup_Backend_Schema_Field_Xml('<field>
1469                     <name>container_id</name>
1470                     <type>text</type>
1471                     <length>40</length>
1472                     <notnull>true</notnull>
1473                 </field>'));
1474                 $this->setTableVersion('sales_contracts', 10);
1475             }
1476             $this->setApplicationVersion('Sales', '10.9');
1477         }
1478
1479         if (Tinebase_Application::getInstance()->isInstalled('SimpleFAQ') &&
1480             version_compare($this->getApplicationVersion('SimpleFAQ'), '10.1') < 0 ) {
1481             if ($this->getTableVersion('simple_faq') < 3) {
1482                 $this->_backend->alterCol('simple_faq', new Setup_Backend_Schema_Field_Xml('<field>
1483                     <name>container_id</name>
1484                     <type>text</type>
1485                     <length>40</length>
1486                     <notnull>false</notnull>
1487                 </field>'));
1488                 $this->setTableVersion('simple_faq', 3);
1489             }
1490             $this->setApplicationVersion('SimpleFAQ', '10.1');
1491         }
1492
1493         if (Tinebase_Application::getInstance()->isInstalled('Tasks') &&
1494             version_compare($this->getApplicationVersion('Tasks'), '10.2') < 0 ) {
1495             if ($this->getTableVersion('tasks') < 10) {
1496                 $this->_backend->alterCol('tasks', new Setup_Backend_Schema_Field_Xml('<field>
1497                     <name>container_id</name>
1498                     <type>text</type>
1499                     <length>40</length>
1500                     <notnull>false</notnull>
1501                 </field>'));
1502                 $this->setTableVersion('tasks', 10);
1503             }
1504             $this->setApplicationVersion('Tasks', '10.2');
1505         }
1506
1507         if (Tinebase_Application::getInstance()->isInstalled('Timetracker') &&
1508             version_compare($this->getApplicationVersion('Timetracker'), '10.3') < 0 ) {
1509             if ($this->getTableVersion('timetracker_timeaccount') < 12) {
1510                 $this->_backend->alterCol('timetracker_timeaccount', new Setup_Backend_Schema_Field_Xml('<field>
1511                     <name>container_id</name>
1512                     <type>text</type>
1513                     <length>40</length>
1514                     <notnull>false</notnull>
1515                 </field>'));
1516                 $this->setTableVersion('timetracker_timeaccount', 12);
1517             }
1518             $this->setApplicationVersion('Timetracker', '10.3');
1519         }
1520
1521         $this->_backend->addForeignKey('container_content', new Setup_Backend_Schema_Index_Xml('<index>
1522                     <name>container_content::container_id--container::id</name>
1523                     <field>
1524                         <name>container_id</name>
1525                     </field>
1526                     <foreign>true</foreign>
1527                     <reference>
1528                         <table>container</table>
1529                         <field>id</field>
1530                         <ondelete>cascade</ondelete>
1531                     </reference>
1532                 </index>'));
1533
1534         $this->_backend->addForeignKey('container_acl', new Setup_Backend_Schema_Index_Xml('<index>
1535                     <name>container_acl::container_id--container::id</name>
1536                     <field>
1537                         <name>container_id</name>
1538                     </field>
1539                     <foreign>true</foreign>
1540                     <reference>
1541                         <table>container</table>
1542                         <field>id</field>
1543                         <ondelete>cascade</ondelete>
1544                         <!-- add onupdate? -->
1545                     </reference>
1546                 </index>'));
1547
1548         if (Tinebase_Application::getInstance()->isInstalled('Timetracker') &&
1549                 $this->_backend->tableExists('timeaccount')) {
1550             $this->_backend->addForeignKey('timeaccount', new Setup_Backend_Schema_Index_Xml('<index>
1551                     <name>timeaccount::container_id--container::id</name>
1552                     <field>
1553                         <name>container_id</name>
1554                     </field>
1555                     <foreign>true</foreign>
1556                     <reference>
1557                         <table>container</table>
1558                         <field>id</field>
1559                     </reference>
1560                 </index>'));
1561         }
1562
1563         if (Tinebase_Application::getInstance()->isInstalled('Sales') &&
1564                 $this->_backend->tableExists('sales_contracts')) {
1565             $this->_backend->addForeignKey('sales_contracts', new Setup_Backend_Schema_Index_Xml('<index>
1566                     <name>sales_contracts::container_id--container::id</name>
1567                     <field>
1568                         <name>container_id</name>
1569                     </field>
1570                     <foreign>true</foreign>
1571                     <reference>
1572                         <table>container</table>
1573                         <field>id</field>
1574                     </reference>
1575                 </index>'));
1576         }
1577
1578         if (Tinebase_Application::getInstance()->isInstalled('Crm') &&
1579                 $this->_backend->tableExists('metacrm_lead')) {
1580             $this->_backend->addForeignKey('metacrm_lead', new Setup_Backend_Schema_Index_Xml('<index>
1581                     <name>metacrm_lead::container_id--container::id</name>
1582                     <field>
1583                         <name>container_id</name>
1584                     </field>
1585                     <foreign>true</foreign>
1586                     <reference>
1587                         <table>container</table>
1588                         <field>id</field>
1589                     </reference>
1590                 </index>'));
1591         }
1592
1593         if (Tinebase_Application::getInstance()->isInstalled('Calendar')) {
1594             if ($this->_backend->tableExists('cal_resources')) {
1595                 $this->_backend->addForeignKey('cal_resources', new Setup_Backend_Schema_Index_Xml('<index>
1596                         <name>cal_resources::container_id--container::id</name>
1597                         <field>
1598                             <name>container_id</name>
1599                         </field>
1600                         <foreign>true</foreign>
1601                         <reference>
1602                             <table>container</table>
1603                             <field>id</field>
1604                         </reference>
1605                     </index>'));
1606             }
1607
1608             if ($this->_backend->tableExists('cal_events')) {
1609                 $this->_backend->addForeignKey('cal_events', new Setup_Backend_Schema_Index_Xml('<index>
1610                         <name>cal_events::container_id--container::id</name>
1611                         <field>
1612                             <name>container_id</name>
1613                         </field>
1614                         <foreign>true</foreign>
1615                         <reference>
1616                             <table>container</table>
1617                             <field>id</field>
1618                         </reference>
1619                     </index>'));
1620             }
1621
1622             if ($this->_backend->tableExists('cal_attendee')) {
1623                 $this->_backend->addForeignKey('cal_attendee', new Setup_Backend_Schema_Index_Xml('<index>
1624                         <name>cal_attendee::displaycontainer_id--container::id</name>
1625                         <field>
1626                             <name>displaycontainer_id</name>
1627                         </field>
1628                         <foreign>true</foreign>
1629                         <reference>
1630                             <table>container</table>
1631                             <field>id</field>
1632                         </reference>
1633                     </index>'));
1634             }
1635         }
1636
1637         if ($this->_backend->tableExists('addressbook')) {
1638             $this->_backend->addForeignKey('addressbook', new Setup_Backend_Schema_Index_Xml('<index>
1639                     <name>addressbook::container_id--container::id</name>
1640                     <field>
1641                         <name>container_id</name>
1642                     </field>
1643                     <foreign>true</foreign>
1644                     <reference>
1645                         <table>container</table>
1646                         <field>id</field>
1647                     </reference>
1648                 </index>'));
1649         }
1650
1651         $this->setApplicationVersion('Tinebase', '10.32');
1652     }
1653
1654     /**
1655      * update to 10.33
1656      *
1657      * change role id from int to uuid
1658      */
1659     public function update_32()
1660     {
1661         try {
1662             $this->_backend->dropForeignKey('role_rights', 'role_rights::role_id--roles::id');
1663         } catch (Exception $e) {}
1664         try {
1665             $this->_backend->dropForeignKey('role_accounts', 'role_accounts::role_id--roles::id');
1666         } catch (Exception $e) {}
1667
1668         if ($this->getTableVersion('roles') < 3) {
1669             $this->_backend->alterCol('roles', new Setup_Backend_Schema_Field_Xml('<field>
1670                             <name>id</name>
1671                             <type>text</type>
1672                             <length>40</length>
1673                             <notnull>true</notnull>
1674                         </field>'));
1675             $this->setTableVersion('roles', 3);
1676         }
1677
1678         if ($this->getTableVersion('role_rights') < 3) {
1679             $this->_backend->alterCol('role_rights', new Setup_Backend_Schema_Field_Xml('<field>
1680                             <name>id</name>
1681                             <type>text</type>
1682                             <length>40</length>
1683                             <notnull>true</notnull>
1684                         </field>'));
1685
1686             $this->_backend->alterCol('role_rights', new Setup_Backend_Schema_Field_Xml('<field>
1687                             <name>role_id</name>
1688                             <type>text</type>
1689                             <length>40</length>
1690                             <notnull>true</notnull>
1691                         </field>'));
1692             $this->setTableVersion('role_rights', 3);
1693         }
1694
1695         if ($this->getTableVersion('role_accounts') < 5) {
1696             $this->_backend->alterCol('role_accounts', new Setup_Backend_Schema_Field_Xml('<field>
1697                             <name>role_id</name>
1698                             <type>text</type>
1699                             <length>40</length>
1700                             <notnull>true</notnull>
1701                         </field>'));
1702             $this->setTableVersion('role_accounts', 5);
1703         }
1704
1705         if ($this->_backend->tableExists('role_rights')) {
1706             $this->_backend->addForeignKey('role_rights', new Setup_Backend_Schema_Index_Xml('<index>
1707                     <name>role_rights::role_id--roles::id</name>
1708                     <field>
1709                         <name>role_id</name>
1710                     </field>
1711                     <foreign>true</foreign>
1712                     <reference>
1713                         <table>roles</table>
1714                         <field>id</field>
1715                         <ondelete>cascade</ondelete>
1716                     </reference>
1717                 </index>'));
1718         }
1719
1720         if ($this->_backend->tableExists('role_accounts')) {
1721             $this->_backend->addForeignKey('role_accounts', new Setup_Backend_Schema_Index_Xml('<index>
1722                     <name>role_accounts::role_id--roles::id</name>
1723                     <field>
1724                         <name>role_id</name>
1725                     </field>
1726                     <foreign>true</foreign>
1727                     <reference>
1728                         <table>roles</table>
1729                         <field>id</field>
1730                         <ondelete>cascade</ondelete>
1731                     </reference>
1732                 </index>'));
1733         }
1734
1735         $this->setApplicationVersion('Tinebase', '10.33');
1736     }
1737
1738     /**
1739      * update to 10.34
1740      *
1741      * add pin column to accounts
1742      */
1743     public function update_33()
1744     {
1745         if (! $this->_backend->columnExists('pin', 'accounts')) {
1746             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
1747                     <name>pin</name>
1748                     <type>text</type>
1749                     <length>100</length>
1750                     <notnull>false</notnull>
1751                 </field>');
1752             $this->_backend->addCol('accounts', $declaration);
1753
1754             $this->setTableVersion('accounts', 12);
1755         }
1756
1757         $this->setApplicationVersion('Tinebase', '10.34');
1758     }
1759
1760     /**
1761      * update to 10.35
1762      *
1763      * add configuration column to accounts
1764      */
1765     public function update_34()
1766     {
1767         if (! $this->_backend->columnExists('configuration', 'accounts')) {
1768             $this->_backend->addCol('accounts', new Setup_Backend_Schema_Field_Xml('<field>
1769                     <name>configuration</name>
1770                     <type>text</type>
1771                     <length>65535</length>
1772                 </field>'));
1773             $this->setTableVersion('accounts', 13);
1774         }
1775         $this->setApplicationVersion('Tinebase', '10.35');
1776     }
1777
1778     /**
1779      * update to 10.36
1780      *
1781      * add quota column to tree_nodes
1782      */
1783     public function update_35()
1784     {
1785         if (! $this->_backend->columnExists('quota', 'tree_nodes')) {
1786             $this->_backend->addCol('tree_nodes', new Setup_Backend_Schema_Field_Xml('<field>
1787                     <name>quota</name>
1788                     <type>integer</type>
1789                     <length>64</length>
1790                     <notnull>false</notnull>
1791                 </field>'));
1792             $this->setTableVersion('tree_nodes', 5);
1793         }
1794
1795         if ($this->getTableVersion('tree_fileobjects') < 6) {
1796             $this->_backend->alterCol('tree_fileobjects', new Setup_Backend_Schema_Field_Xml('<field>
1797                     <name>revision_size</name>
1798                     <type>integer</type>
1799                     <length>64</length>
1800                     <notnull>true</notnull>
1801                     <default>0</default>
1802                 </field>'));
1803             $this->setTableVersion('tree_fileobjects', 6);
1804         }
1805
1806         $this->setApplicationVersion('Tinebase', '10.36');
1807     }
1808
1809     /**
1810      * update to 10.37
1811      *
1812      * fix tree_node_acl and container_acl tables re primary / unique keys
1813      */
1814     public function update_36()
1815     {
1816         $result = $this->_db->select()->from(SQL_TABLE_PREFIX . 'container_acl')->query(Zend_Db::FETCH_ASSOC);
1817         $quotedId = $this->_db->quoteIdentifier('id');
1818         $quotedContainerId = $this->_db->quoteIdentifier('container_id');
1819         $quotedAccountType = $this->_db->quoteIdentifier('account_type');
1820         $quotedAccountId = $this->_db->quoteIdentifier('account_id');
1821         $quotedAccountGrant = $this->_db->quoteIdentifier('account_grant');
1822         foreach ($result->fetchAll() as $row) {
1823             $this->_db->update(SQL_TABLE_PREFIX . 'container_acl',
1824                 array('id' => Tinebase_Record_Abstract::generateUID()),
1825                 $quotedId           . ' = ' . $this->_db->quote($row['id'])           . ' AND ' .
1826                 $quotedContainerId  . ' = ' . $this->_db->quote($row['container_id']) . ' AND ' .
1827                 $quotedAccountType  . ' = ' . $this->_db->quote($row['account_type']) . ' AND ' .
1828                 $quotedAccountId    . ' = ' . $this->_db->quote($row['account_id'])   . ' AND ' .
1829                 $quotedAccountGrant . ' = ' . $this->_db->quote($row['account_grant'])
1830             );
1831         }
1832
1833         $result = $this->_db->select()->from(SQL_TABLE_PREFIX . 'tree_node_acl')->query(Zend_Db::FETCH_ASSOC);
1834         $quotedRecordId = $this->_db->quoteIdentifier('record_id');
1835         foreach ($result->fetchAll() as $row) {
1836             $this->_db->update(SQL_TABLE_PREFIX . 'tree_node_acl',
1837                 array('id' => Tinebase_Record_Abstract::generateUID()),
1838                 $quotedId           . ' = ' . $this->_db->quote($row['id'])           . ' AND ' .
1839                 $quotedRecordId     . ' = ' . $this->_db->quote($row['record_id'])    . ' AND ' .
1840                 $quotedAccountType  . ' = ' . $this->_db->quote($row['account_type']) . ' AND ' .
1841                 $quotedAccountId    . ' = ' . $this->_db->quote($row['account_id'])   . ' AND ' .
1842                 $quotedAccountGrant . ' = ' . $this->_db->quote($row['account_grant'])
1843             );
1844         }
1845
1846         /** @var Tinebase_Backend_Sql_Command_Interface $command */
1847         $command = Tinebase_Backend_Sql_Command::factory($this->_db);
1848         $quotedC = $this->_db->quoteIdentifier('c');
1849         $stmt = $this->_db->select()->from(SQL_TABLE_PREFIX . 'container_acl', array($command->getAggregate('id'),
1850             new Zend_Db_Expr('count(*) AS ' . $quotedC)))
1851             ->group(array('container_id', 'account_type', 'account_id', 'account_grant'));
1852         if ($this->_db instanceof Zend_Db_Adapter_Pdo_Pgsql) {
1853             $stmt->having('count(*) > 1');
1854         } else {
1855             $stmt->having('c > 1');
1856         }
1857         $result = $stmt->query(Zend_Db::FETCH_NUM);
1858         foreach ($result->fetchAll() as $row) {
1859             $ids = explode(',', ltrim(rtrim($row[0], '}'), '{'));
1860             array_pop($ids);
1861             $this->_db->delete(SQL_TABLE_PREFIX . 'container_acl', $this->_db->quoteInto($quotedId . ' in (?)', $ids));
1862         }
1863
1864         $stmt = $this->_db->select()->from(SQL_TABLE_PREFIX . 'tree_node_acl', array($command->getAggregate('id'),
1865             new Zend_Db_Expr('count(*) AS '. $quotedC)))
1866             ->group(array('record_id', 'account_type', 'account_id', 'account_grant'));
1867         if ($this->_db instanceof Zend_Db_Adapter_Pdo_Pgsql) {
1868             $stmt->having('count(*) > 1');
1869         } else {
1870             $stmt->having('c > 1');
1871         }
1872         $result = $stmt->query(Zend_Db::FETCH_NUM);
1873         foreach ($result->fetchAll() as $row) {
1874             $ids = explode(',', ltrim(rtrim($row[0], '}'), '{'));
1875             array_pop($ids);
1876             $this->_db->delete(SQL_TABLE_PREFIX . 'tree_node_acl', $this->_db->quoteInto($quotedId . ' in (?)', $ids));
1877         }
1878
1879         if ($this->getTableVersion('container_acl') < 5) {
1880             $this->_backend->dropPrimaryKey('container_acl');
1881             $this->_backend->addIndex('container_acl', new Setup_Backend_Schema_Index_Xml('<index>
1882                     <name>id</name>
1883                     <primary>true</primary>
1884                     <field>
1885                         <name>id</name>
1886                     </field>
1887                 </index>
1888             '));
1889             $this->_backend->addIndex('container_acl', new Setup_Backend_Schema_Index_Xml('<index>
1890                     <name>container_id-account_type-account_id-acount_grant</name>
1891                     <unique>true</unique>
1892                     <field>
1893                         <name>container_id</name>
1894                     </field>
1895                     <field>
1896                         <name>account_type</name>
1897                     </field>
1898                     <field>
1899                         <name>account_id</name>
1900                     </field>
1901                     <field>
1902                         <name>account_grant</name>
1903                     </field>
1904                 </index>
1905             '));
1906             try {
1907                 $this->_backend->dropIndex('container_acl', 'id-account_type-account_id');
1908             } catch(Exception $e) {}
1909             $this->setTableVersion('container_acl', 5);
1910         }
1911
1912         if ($this->getTableVersion('tree_node_acl') < 2) {
1913             $this->_backend->dropPrimaryKey('tree_node_acl');
1914             $this->_backend->addIndex('tree_node_acl', new Setup_Backend_Schema_Index_Xml('<index>
1915                     <name>id</name>
1916                     <primary>true</primary>
1917                     <field>
1918                         <name>id</name>
1919                     </field>
1920                 </index>
1921             '));
1922             $this->_backend->addIndex('tree_node_acl', new Setup_Backend_Schema_Index_Xml('<index>
1923                     <name>record_id-account-type-account_id-account_grant</name>
1924                     <unique>true</unique>
1925                     <field>
1926                         <name>record_id</name>
1927                     </field>
1928                     <field>
1929                         <name>account_type</name>
1930                     </field>
1931                     <field>
1932                         <name>account_id</name>
1933                     </field>
1934                     <field>
1935                         <name>account_grant</name>
1936                     </field>
1937                 </index>
1938             '));
1939             try {
1940                 $this->_backend->dropIndex('tree_node_acl', 'id-account_type-account_id');
1941             } catch(Exception $e) {}
1942             $this->setTableVersion('tree_node_acl', 2);
1943         }
1944         $this->setApplicationVersion('Tinebase', '10.37');
1945     }
1946
1947     /**
1948      * update to 10.38
1949      *
1950      * set shared folders acl not if not set
1951      */
1952     public function update_37()
1953     {
1954         $this->_addIsDeletedToTreeNodes();
1955         $fileSystem = Tinebase_FileSystem::getInstance();
1956         $inheritPropertyMethod = $this->_getProtectedMethod($fileSystem, '_recursiveInheritPropertyUpdate');
1957         if (Tinebase_Application::getInstance()->isInstalled('Filemanager')) {
1958             try {
1959                 $node = $fileSystem->stat('/Filemanager/folders/shared');
1960                 if (null === $node->acl_node) {
1961                     $fileSystem->setGrantsForNode($node, Tinebase_Model_Grants::getDefaultGrants(array(
1962                         Tinebase_Model_Grants::GRANT_DOWNLOAD => true
1963                     ), array(
1964                         Tinebase_Model_Grants::GRANT_PUBLISH => true
1965                     )));
1966                     $inheritPropertyMethod->invoke($fileSystem, $node, 'acl_node', $node->acl_node, null);
1967                 }
1968             } catch(Tinebase_Exception_NotFound $tenf) {}
1969         }
1970         if (Tinebase_Application::getInstance()->isInstalled('MailFiler')) {
1971             try {
1972                 $node = $fileSystem->stat('/MailFiler/folders/shared');
1973                 if (null === $node->acl_node) {
1974                     $fileSystem->setGrantsForNode($node, Tinebase_Model_Grants::getDefaultGrants(array(
1975                         Tinebase_Model_Grants::GRANT_DOWNLOAD => true
1976                     ), array(
1977                         Tinebase_Model_Grants::GRANT_PUBLISH => true
1978                     )));
1979                     $inheritPropertyMethod->invoke($fileSystem, $node, 'acl_node', $node->acl_node, null);
1980                 }
1981             } catch(Tinebase_Exception_NotFound $tenf) {}
1982         }
1983
1984         $this->setApplicationVersion('Tinebase', '10.38');
1985     }
1986
1987     /**
1988      * GetProtectedMethod constructor.
1989      * @param $object
1990      * @param $method
1991      * @return ReflectionMethod
1992      */
1993     protected function _getProtectedMethod($object, $method)
1994     {
1995         $class = new ReflectionClass($object);
1996         $method = $class->getMethod($method);
1997         $method->setAccessible(true);
1998
1999         return $method;
2000     }
2001
2002     /**
2003      * update to 10.39
2004      *
2005      * tree_nodes add pin_protected
2006      */
2007     public function update_38()
2008     {
2009         if ($this->getTableVersion('tree_nodes') < 6) {
2010             $this->_addIsDeletedToTreeNodes();
2011             $this->setTableVersion('tree_nodes', 6);
2012         }
2013         $this->setApplicationVersion('Tinebase', '10.39');
2014     }
2015
2016     /**
2017      * update to 10.40
2018      *
2019      * tree_nodes make name column case sensitive
2020      */
2021     public function update_39()
2022     {
2023         if ($this->getTableVersion('tree_nodes') < 7) {
2024             if (Tinebase_Core::getDb() instanceof Zend_Db_Adapter_Pdo_Mysql) {
2025                 $this->_backend->alterCol('tree_nodes', new Setup_Backend_Schema_Field_Xml('<field>
2026                         <name>name</name>
2027                         <type>text</type>
2028                         <length>255</length>
2029                         <notnull>true</notnull>
2030                         <collation>utf8_bin</collation>
2031                     </field>'));
2032             }
2033             $this->setTableVersion('tree_nodes', 7);
2034         }
2035         $this->setApplicationVersion('Tinebase', '10.40');
2036     }
2037
2038     /**
2039      * update to 10.41
2040      *
2041      * pgsql - fix bigint issue
2042      */
2043     public function update_40()
2044     {
2045         $applications = Tinebase_Application::getInstance()->getApplications();
2046         /** @var Tinebase_Model_Application $application */
2047         foreach ($applications as $application) {
2048             try {
2049                 $setupXml = Setup_Controller::getInstance()->getSetupXml($application->name);
2050             } catch (Setup_Exception_NotFound $senf) {
2051                 Tinebase_Exception::log($senf);
2052                 $setupXml = false;
2053             }
2054             if (!$setupXml || !$setupXml->tables || !$setupXml->tables->table) {
2055                 continue;
2056             }
2057             foreach ($setupXml->tables->table as $key => $table) {
2058                 /** @var SimpleXMLElement $field */
2059                 foreach ($table->declaration->field as $field) {
2060                     if ($field->type == 'integer' && !empty($field->length) && $field->length > 19) {
2061                         $this->_backend->alterCol($table->name, new Setup_Backend_Schema_Field_Xml(
2062                             $field->asXML()
2063                         ));
2064                     }
2065                 }
2066             }
2067         }
2068
2069         $this->setApplicationVersion('Tinebase', '10.41');
2070     }
2071
2072     /**
2073      * update to 10.42
2074      *
2075      * fix static scheduler issue
2076      */
2077     public function update_41()
2078     {
2079         $scheduler = Tinebase_Core::getScheduler();
2080         $scheduler->removeTask('Tinebase_User/Group::syncUsers/Groups');
2081         Tinebase_Scheduler_Task::addAccountSyncTask($scheduler);
2082         $this->setApplicationVersion('Tinebase', '10.42');
2083     }
2084 }