a0bdb5a41335f2c76a647fcd71b928cfebe501c2
[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
1326         if (version_compare($this->getApplicationVersion('Tinebase'), '10.32') < 0 ) {
1327             if ($this->getTableVersion('container') < 13) {
1328                 $this->_backend->alterCol('container', new Setup_Backend_Schema_Field_Xml('<field>
1329                             <name>id</name>
1330                             <type>text</type>
1331                             <length>40</length>
1332                             <notnull>true</notnull>
1333                         </field>'));
1334                 $this->setTableVersion('container', 13);
1335             }
1336
1337             if ($this->getTableVersion('container_acl') < 4) {
1338                 $this->_backend->alterCol('container_acl', new Setup_Backend_Schema_Field_Xml('<field>
1339                             <name>container_id</name>
1340                             <type>text</type>
1341                             <length>40</length>
1342                             <notnull>true</notnull>
1343                         </field>'));
1344                 $this->setTableVersion('container_acl', 4);
1345             }
1346
1347             if ($this->getTableVersion('container_content') < 3) {
1348                 $this->_backend->alterCol('container_content', new Setup_Backend_Schema_Field_Xml('<field>
1349                             <name>container_id</name>
1350                             <type>text</type>
1351                             <length>40</length>
1352                             <notnull>true</notnull>
1353                         </field>'));
1354                 $this->setTableVersion('container_content', 3);
1355             }
1356         }
1357
1358         if (version_compare($this->getApplicationVersion('Addressbook'), '10.6') < 0 ) {
1359             if ($this->getTableVersion('addressbook') < 25) {
1360                 $this->_backend->alterCol('addressbook', new Setup_Backend_Schema_Field_Xml('<field>
1361                     <name>container_id</name>
1362                     <type>text</type>
1363                     <length>40</length>
1364                     <notnull>false</notnull>
1365                 </field>'));
1366                 $this->setTableVersion('addressbook', 25);
1367             }
1368
1369             if ($this->getTableVersion('addressbook_lists') < 6) {
1370                 $this->_backend->alterCol('addressbook_lists', new Setup_Backend_Schema_Field_Xml('<field>
1371                     <name>container_id</name>
1372                     <type>text</type>
1373                     <length>40</length>
1374                     <notnull>false</notnull>
1375                 </field>'));
1376                 $this->setTableVersion('addressbook_lists', 25);
1377             }
1378
1379             $this->setApplicationVersion('Addressbook', '10.6');
1380         }
1381
1382         if (Tinebase_Application::getInstance()->isInstalled('Calendar') &&
1383                 version_compare($this->getApplicationVersion('Calendar'), '10.8') < 0 ) {
1384             if ($this->getTableVersion('cal_events') < 14) {
1385                 $this->_backend->alterCol('cal_events', new Setup_Backend_Schema_Field_Xml('<field>
1386                     <name>container_id</name>
1387                     <type>text</type>
1388                     <length>40</length>
1389                     <notnull>false</notnull>
1390                 </field>'));
1391                 $this->setTableVersion('cal_events', 14);
1392             }
1393
1394             if ($this->getTableVersion('cal_attendee') < 6) {
1395                 $this->_backend->alterCol('cal_attendee', new Setup_Backend_Schema_Field_Xml('<field>
1396                     <name>displaycontainer_id</name>
1397                     <type>text</type>
1398                     <length>40</length>
1399                     <notnull>false</notnull>
1400                 </field>'));
1401                 $this->setTableVersion('cal_attendee', 6);
1402             }
1403
1404             if ($this->getTableVersion('cal_resources') < 6) {
1405                 $this->_backend->alterCol('cal_resources', new Setup_Backend_Schema_Field_Xml('<field>
1406                     <name>container_id</name>
1407                     <type>text</type>
1408                     <length>40</length>
1409                     <notnull>false</notnull>
1410                 </field>'));
1411                 $this->setTableVersion('cal_resources', 6);
1412             }
1413
1414             $this->setApplicationVersion('Calendar', '10.8');
1415         }
1416
1417         if (Tinebase_Application::getInstance()->isInstalled('Crm') &&
1418             version_compare($this->getApplicationVersion('Crm'), '10.2') < 0 ) {
1419             if ($this->getTableVersion('metacrm_lead') < 10) {
1420                 $this->_backend->alterCol('metacrm_lead', new Setup_Backend_Schema_Field_Xml('<field>
1421                     <name>container_id</name>
1422                     <type>text</type>
1423                     <length>40</length>
1424                     <notnull>false</notnull>
1425                 </field>'));
1426                 $this->setTableVersion('metacrm_lead', 10);
1427             }
1428             $this->setApplicationVersion('Crm', '10.2');
1429         }
1430
1431         if (Tinebase_Application::getInstance()->isInstalled('Events') &&
1432             version_compare($this->getApplicationVersion('Events'), '10.2') < 0 ) {
1433             if ($this->getTableVersion('events_event') < 3) {
1434                 $this->_backend->alterCol('events_event', new Setup_Backend_Schema_Field_Xml('<field>
1435                     <name>container_id</name>
1436                     <type>text</type>
1437                     <length>40</length>
1438                     <notnull>false</notnull>
1439                 </field>'));
1440                 $this->setTableVersion('events_event', 3);
1441             }
1442             $this->setApplicationVersion('Events', '10.2');
1443         }
1444
1445         if (Tinebase_Application::getInstance()->isInstalled('Projects') &&
1446             version_compare($this->getApplicationVersion('Projects'), '10.2') < 0 ) {
1447             if ($this->getTableVersion('projects_project') < 4) {
1448                 $this->_backend->alterCol('projects_project', new Setup_Backend_Schema_Field_Xml('<field>
1449                     <name>container_id</name>
1450                     <type>text</type>
1451                     <length>40</length>
1452                     <notnull>false</notnull>
1453                 </field>'));
1454                 $this->setTableVersion('projects_project', 4);
1455             }
1456             $this->setApplicationVersion('Projects', '10.2');
1457         }
1458
1459         if (Tinebase_Application::getInstance()->isInstalled('Sales') &&
1460             version_compare($this->getApplicationVersion('Sales'), '10.9') < 0 ) {
1461             if ($this->getTableVersion('sales_contracts') < 10) {
1462                 $this->_backend->alterCol('sales_contracts', new Setup_Backend_Schema_Field_Xml('<field>
1463                     <name>container_id</name>
1464                     <type>text</type>
1465                     <length>40</length>
1466                     <notnull>true</notnull>
1467                 </field>'));
1468                 $this->setTableVersion('sales_contracts', 10);
1469             }
1470             $this->setApplicationVersion('Sales', '10.9');
1471         }
1472
1473         if (Tinebase_Application::getInstance()->isInstalled('SimpleFAQ') &&
1474             version_compare($this->getApplicationVersion('SimpleFAQ'), '10.1') < 0 ) {
1475             if ($this->getTableVersion('simple_faq') < 3) {
1476                 $this->_backend->alterCol('simple_faq', new Setup_Backend_Schema_Field_Xml('<field>
1477                     <name>container_id</name>
1478                     <type>text</type>
1479                     <length>40</length>
1480                     <notnull>false</notnull>
1481                 </field>'));
1482                 $this->setTableVersion('simple_faq', 3);
1483             }
1484             $this->setApplicationVersion('SimpleFAQ', '10.1');
1485         }
1486
1487         if (Tinebase_Application::getInstance()->isInstalled('Tasks') &&
1488             version_compare($this->getApplicationVersion('Tasks'), '10.2') < 0 ) {
1489             if ($this->getTableVersion('tasks') < 10) {
1490                 $this->_backend->alterCol('tasks', new Setup_Backend_Schema_Field_Xml('<field>
1491                     <name>container_id</name>
1492                     <type>text</type>
1493                     <length>40</length>
1494                     <notnull>false</notnull>
1495                 </field>'));
1496                 $this->setTableVersion('tasks', 10);
1497             }
1498             $this->setApplicationVersion('Tasks', '10.2');
1499         }
1500
1501         if (Tinebase_Application::getInstance()->isInstalled('Timetracker') &&
1502             version_compare($this->getApplicationVersion('Timetracker'), '10.3') < 0 ) {
1503             if ($this->getTableVersion('timetracker_timeaccount') < 12) {
1504                 $this->_backend->alterCol('timetracker_timeaccount', new Setup_Backend_Schema_Field_Xml('<field>
1505                     <name>container_id</name>
1506                     <type>text</type>
1507                     <length>40</length>
1508                     <notnull>false</notnull>
1509                 </field>'));
1510                 $this->setTableVersion('timetracker_timeaccount', 12);
1511             }
1512             $this->setApplicationVersion('Timetracker', '10.3');
1513         }
1514
1515         $this->_backend->addForeignKey('container_content', new Setup_Backend_Schema_Index_Xml('<index>
1516                     <name>container_content::container_id--container::id</name>
1517                     <field>
1518                         <name>container_id</name>
1519                     </field>
1520                     <foreign>true</foreign>
1521                     <reference>
1522                         <table>container</table>
1523                         <field>id</field>
1524                         <ondelete>cascade</ondelete>
1525                     </reference>
1526                 </index>'));
1527
1528         $this->_backend->addForeignKey('container_acl', new Setup_Backend_Schema_Index_Xml('<index>
1529                     <name>container_acl::container_id--container::id</name>
1530                     <field>
1531                         <name>container_id</name>
1532                     </field>
1533                     <foreign>true</foreign>
1534                     <reference>
1535                         <table>container</table>
1536                         <field>id</field>
1537                         <ondelete>cascade</ondelete>
1538                         <!-- add onupdate? -->
1539                     </reference>
1540                 </index>'));
1541
1542         if ($this->_backend->tableExists('timeaccount')) {
1543             $this->_backend->addForeignKey('timeaccount', new Setup_Backend_Schema_Index_Xml('<index>
1544                     <name>timeaccount::container_id--container::id</name>
1545                     <field>
1546                         <name>container_id</name>
1547                     </field>
1548                     <foreign>true</foreign>
1549                     <reference>
1550                         <table>container</table>
1551                         <field>id</field>
1552                     </reference>
1553                 </index>'));
1554         }
1555
1556         if ($this->_backend->tableExists('sales_contracts')) {
1557             $this->_backend->addForeignKey('sales_contracts', new Setup_Backend_Schema_Index_Xml('<index>
1558                     <name>sales_contracts::container_id--container::id</name>
1559                     <field>
1560                         <name>container_id</name>
1561                     </field>
1562                     <foreign>true</foreign>
1563                     <reference>
1564                         <table>container</table>
1565                         <field>id</field>
1566                     </reference>
1567                 </index>'));
1568         }
1569
1570         if ($this->_backend->tableExists('metacrm_lead')) {
1571             $this->_backend->addForeignKey('metacrm_lead', new Setup_Backend_Schema_Index_Xml('<index>
1572                     <name>metacrm_lead::container_id--container::id</name>
1573                     <field>
1574                         <name>container_id</name>
1575                     </field>
1576                     <foreign>true</foreign>
1577                     <reference>
1578                         <table>container</table>
1579                         <field>id</field>
1580                     </reference>
1581                 </index>'));
1582         }
1583
1584         if ($this->_backend->tableExists('cal_resources')) {
1585             $this->_backend->addForeignKey('cal_resources', new Setup_Backend_Schema_Index_Xml('<index>
1586                     <name>cal_resources::container_id--container::id</name>
1587                     <field>
1588                         <name>container_id</name>
1589                     </field>
1590                     <foreign>true</foreign>
1591                     <reference>
1592                         <table>container</table>
1593                         <field>id</field>
1594                     </reference>
1595                 </index>'));
1596         }
1597
1598         if ($this->_backend->tableExists('cal_events')) {
1599             $this->_backend->addForeignKey('cal_events', new Setup_Backend_Schema_Index_Xml('<index>
1600                     <name>cal_events::container_id--container::id</name>
1601                     <field>
1602                         <name>container_id</name>
1603                     </field>
1604                     <foreign>true</foreign>
1605                     <reference>
1606                         <table>container</table>
1607                         <field>id</field>
1608                     </reference>
1609                 </index>'));
1610         }
1611
1612         if ($this->_backend->tableExists('cal_attendee')) {
1613             $this->_backend->addForeignKey('cal_attendee', new Setup_Backend_Schema_Index_Xml('<index>
1614                     <name>cal_attendee::displaycontainer_id--container::id</name>
1615                     <field>
1616                         <name>displaycontainer_id</name>
1617                     </field>
1618                     <foreign>true</foreign>
1619                     <reference>
1620                         <table>container</table>
1621                         <field>id</field>
1622                     </reference>
1623                 </index>'));
1624         }
1625
1626         if ($this->_backend->tableExists('addressbook')) {
1627             $this->_backend->addForeignKey('addressbook', new Setup_Backend_Schema_Index_Xml('<index>
1628                     <name>addressbook::container_id--container::id</name>
1629                     <field>
1630                         <name>container_id</name>
1631                     </field>
1632                     <foreign>true</foreign>
1633                     <reference>
1634                         <table>container</table>
1635                         <field>id</field>
1636                     </reference>
1637                 </index>'));
1638         }
1639
1640         $this->setApplicationVersion('Tinebase', '10.32');
1641     }
1642
1643     /**
1644      * update to 10.33
1645      *
1646      * change role id from int to uuid
1647      */
1648     public function update_32()
1649     {
1650         try {
1651             $this->_backend->dropForeignKey('role_rights', 'role_rights::role_id--roles::id');
1652         } catch (Exception $e) {}
1653         try {
1654             $this->_backend->dropForeignKey('role_accounts', 'role_accounts::role_id--roles::id');
1655         } catch (Exception $e) {}
1656
1657         if ($this->getTableVersion('roles') < 3) {
1658             $this->_backend->alterCol('roles', new Setup_Backend_Schema_Field_Xml('<field>
1659                             <name>id</name>
1660                             <type>text</type>
1661                             <length>40</length>
1662                             <notnull>true</notnull>
1663                         </field>'));
1664             $this->setTableVersion('roles', 3);
1665         }
1666
1667         if ($this->getTableVersion('role_rights') < 3) {
1668             $this->_backend->alterCol('role_rights', new Setup_Backend_Schema_Field_Xml('<field>
1669                             <name>id</name>
1670                             <type>text</type>
1671                             <length>40</length>
1672                             <notnull>true</notnull>
1673                         </field>'));
1674
1675             $this->_backend->alterCol('role_rights', new Setup_Backend_Schema_Field_Xml('<field>
1676                             <name>role_id</name>
1677                             <type>text</type>
1678                             <length>40</length>
1679                             <notnull>true</notnull>
1680                         </field>'));
1681             $this->setTableVersion('role_rights', 3);
1682         }
1683
1684         if ($this->getTableVersion('role_accounts') < 5) {
1685             $this->_backend->alterCol('role_accounts', new Setup_Backend_Schema_Field_Xml('<field>
1686                             <name>role_id</name>
1687                             <type>text</type>
1688                             <length>40</length>
1689                             <notnull>true</notnull>
1690                         </field>'));
1691             $this->setTableVersion('role_accounts', 5);
1692         }
1693
1694         if ($this->_backend->tableExists('role_rights')) {
1695             $this->_backend->addForeignKey('role_rights', new Setup_Backend_Schema_Index_Xml('<index>
1696                     <name>role_rights::role_id--roles::id</name>
1697                     <field>
1698                         <name>role_id</name>
1699                     </field>
1700                     <foreign>true</foreign>
1701                     <reference>
1702                         <table>roles</table>
1703                         <field>id</field>
1704                         <ondelete>cascade</ondelete>
1705                     </reference>
1706                 </index>'));
1707         }
1708
1709         if ($this->_backend->tableExists('role_accounts')) {
1710             $this->_backend->addForeignKey('role_accounts', new Setup_Backend_Schema_Index_Xml('<index>
1711                     <name>role_accounts::role_id--roles::id</name>
1712                     <field>
1713                         <name>role_id</name>
1714                     </field>
1715                     <foreign>true</foreign>
1716                     <reference>
1717                         <table>roles</table>
1718                         <field>id</field>
1719                         <ondelete>cascade</ondelete>
1720                     </reference>
1721                 </index>'));
1722         }
1723
1724         $this->setApplicationVersion('Tinebase', '10.33');
1725     }
1726
1727     /**
1728      * update to 10.34
1729      *
1730      * add pin column to accounts
1731      */
1732     public function update_33()
1733     {
1734         if (! $this->_backend->columnExists('pin', 'accounts')) {
1735             $declaration = new Setup_Backend_Schema_Field_Xml('<field>
1736                     <name>pin</name>
1737                     <type>text</type>
1738                     <length>100</length>
1739                     <notnull>false</notnull>
1740                 </field>');
1741             $this->_backend->addCol('accounts', $declaration);
1742
1743             $this->setTableVersion('accounts', 12);
1744         }
1745
1746         $this->setApplicationVersion('Tinebase', '10.34');
1747     }
1748
1749     /**
1750      * update to 10.35
1751      *
1752      * add configuration column to accounts
1753      */
1754     public function update_34()
1755     {
1756         if (! $this->_backend->columnExists('configuration', 'accounts')) {
1757             $this->_backend->addCol('accounts', new Setup_Backend_Schema_Field_Xml('<field>
1758                     <name>configuration</name>
1759                     <type>text</type>
1760                     <length>65535</length>
1761                 </field>'));
1762             $this->setTableVersion('accounts', 13);
1763         }
1764         $this->setApplicationVersion('Tinebase', '10.35');
1765     }
1766
1767     /**
1768      * update to 10.36
1769      *
1770      * add quota column to tree_nodes
1771      */
1772     public function update_35()
1773     {
1774         if (! $this->_backend->columnExists('quota', 'tree_nodes')) {
1775             $this->_backend->addCol('tree_nodes', new Setup_Backend_Schema_Field_Xml('<field>
1776                     <name>quota</name>
1777                     <type>integer</type>
1778                     <length>64</length>
1779                     <notnull>false</notnull>
1780                 </field>'));
1781             $this->setTableVersion('tree_nodes', 5);
1782         }
1783
1784         if ($this->getTableVersion('tree_fileobjects') < 6) {
1785             $this->_backend->alterCol('tree_fileobjects', new Setup_Backend_Schema_Field_Xml('<field>
1786                     <name>revision_size</name>
1787                     <type>integer</type>
1788                     <length>64</length>
1789                     <notnull>true</notnull>
1790                     <default>0</default>
1791                 </field>'));
1792             $this->setTableVersion('tree_fileobjects', 6);
1793         }
1794
1795         $this->setApplicationVersion('Tinebase', '10.36');
1796     }
1797
1798     /**
1799      * update to 10.37
1800      *
1801      * fix tree_node_acl and container_acl tables re primary / unique keys
1802      */
1803     public function update_36()
1804     {
1805         $result = $this->_db->select()->from(SQL_TABLE_PREFIX . 'container_acl')->query(Zend_Db::FETCH_ASSOC);
1806         $quotedId = $this->_db->quoteIdentifier('id');
1807         $quotedContainerId = $this->_db->quoteIdentifier('container_id');
1808         $quotedAccountType = $this->_db->quoteIdentifier('account_type');
1809         $quotedAccountId = $this->_db->quoteIdentifier('account_id');
1810         $quotedAccountGrant = $this->_db->quoteIdentifier('account_grant');
1811         foreach ($result->fetchAll() as $row) {
1812             $this->_db->update(SQL_TABLE_PREFIX . 'container_acl',
1813                 array('id' => Tinebase_Record_Abstract::generateUID()),
1814                 $quotedId           . ' = ' . $this->_db->quote($row['id'])           . ' AND ' .
1815                 $quotedContainerId  . ' = ' . $this->_db->quote($row['container_id']) . ' AND ' .
1816                 $quotedAccountType  . ' = ' . $this->_db->quote($row['account_type']) . ' AND ' .
1817                 $quotedAccountId    . ' = ' . $this->_db->quote($row['account_id'])   . ' AND ' .
1818                 $quotedAccountGrant . ' = ' . $this->_db->quote($row['account_grant'])
1819             );
1820         }
1821
1822         $result = $this->_db->select()->from(SQL_TABLE_PREFIX . 'tree_node_acl')->query(Zend_Db::FETCH_ASSOC);
1823         $quotedRecordId = $this->_db->quoteIdentifier('record_id');
1824         foreach ($result->fetchAll() as $row) {
1825             $this->_db->update(SQL_TABLE_PREFIX . 'tree_node_acl',
1826                 array('id' => Tinebase_Record_Abstract::generateUID()),
1827                 $quotedId           . ' = ' . $this->_db->quote($row['id'])           . ' AND ' .
1828                 $quotedRecordId     . ' = ' . $this->_db->quote($row['record_id'])    . ' AND ' .
1829                 $quotedAccountType  . ' = ' . $this->_db->quote($row['account_type']) . ' AND ' .
1830                 $quotedAccountId    . ' = ' . $this->_db->quote($row['account_id'])   . ' AND ' .
1831                 $quotedAccountGrant . ' = ' . $this->_db->quote($row['account_grant'])
1832             );
1833         }
1834
1835         /** @var Tinebase_Backend_Sql_Command_Interface $command */
1836         $command = Tinebase_Backend_Sql_Command::factory($this->_db);
1837         $quotedC = $this->_db->quoteIdentifier('c');
1838         $stmt = $this->_db->select()->from(SQL_TABLE_PREFIX . 'container_acl', array($command->getAggregate('id'),
1839             new Zend_Db_Expr('count(*) AS ' . $quotedC)))
1840             ->group(array('container_id', 'account_type', 'account_id', 'account_grant'));
1841         if ($this->_db instanceof Zend_Db_Adapter_Pdo_Pgsql) {
1842             $stmt->having('count(*) > 1');
1843         } else {
1844             $stmt->having('c > 1');
1845         }
1846         $result = $stmt->query(Zend_Db::FETCH_NUM);
1847         foreach ($result->fetchAll() as $row) {
1848             $ids = explode(',', ltrim(rtrim($row[0], '}'), '{'));
1849             array_pop($ids);
1850             $this->_db->delete(SQL_TABLE_PREFIX . 'container_acl', $this->_db->quoteInto($quotedId . ' in (?)', $ids));
1851         }
1852
1853         $stmt = $this->_db->select()->from(SQL_TABLE_PREFIX . 'tree_node_acl', array($command->getAggregate('id'),
1854             new Zend_Db_Expr('count(*) AS '. $quotedC)))
1855             ->group(array('record_id', 'account_type', 'account_id', 'account_grant'));
1856         if ($this->_db instanceof Zend_Db_Adapter_Pdo_Pgsql) {
1857             $stmt->having('count(*) > 1');
1858         } else {
1859             $stmt->having('c > 1');
1860         }
1861         $result = $stmt->query(Zend_Db::FETCH_NUM);
1862         foreach ($result->fetchAll() as $row) {
1863             $ids = explode(',', ltrim(rtrim($row[0], '}'), '{'));
1864             array_pop($ids);
1865             $this->_db->delete(SQL_TABLE_PREFIX . 'tree_node_acl', $this->_db->quoteInto($quotedId . ' in (?)', $ids));
1866         }
1867
1868         if ($this->getTableVersion('container_acl') < 5) {
1869             $this->_backend->dropPrimaryKey('container_acl');
1870             $this->_backend->addIndex('container_acl', new Setup_Backend_Schema_Index_Xml('<index>
1871                     <name>id</name>
1872                     <primary>true</primary>
1873                     <field>
1874                         <name>id</name>
1875                     </field>
1876                 </index>
1877             '));
1878             $this->_backend->addIndex('container_acl', new Setup_Backend_Schema_Index_Xml('<index>
1879                     <name>container_id-account_type-account_id-acount_grant</name>
1880                     <unique>true</unique>
1881                     <field>
1882                         <name>container_id</name>
1883                     </field>
1884                     <field>
1885                         <name>account_type</name>
1886                     </field>
1887                     <field>
1888                         <name>account_id</name>
1889                     </field>
1890                     <field>
1891                         <name>account_grant</name>
1892                     </field>
1893                 </index>
1894             '));
1895             try {
1896                 $this->_backend->dropIndex('container_acl', 'id-account_type-account_id');
1897             } catch(Exception $e) {}
1898             $this->setTableVersion('container_acl', 5);
1899         }
1900
1901         if ($this->getTableVersion('tree_node_acl') < 2) {
1902             $this->_backend->dropPrimaryKey('tree_node_acl');
1903             $this->_backend->addIndex('tree_node_acl', new Setup_Backend_Schema_Index_Xml('<index>
1904                     <name>id</name>
1905                     <primary>true</primary>
1906                     <field>
1907                         <name>id</name>
1908                     </field>
1909                 </index>
1910             '));
1911             $this->_backend->addIndex('tree_node_acl', new Setup_Backend_Schema_Index_Xml('<index>
1912                     <name>record_id-account-type-account_id-account_grant</name>
1913                     <unique>true</unique>
1914                     <field>
1915                         <name>record_id</name>
1916                     </field>
1917                     <field>
1918                         <name>account_type</name>
1919                     </field>
1920                     <field>
1921                         <name>account_id</name>
1922                     </field>
1923                     <field>
1924                         <name>account_grant</name>
1925                     </field>
1926                 </index>
1927             '));
1928             try {
1929                 $this->_backend->dropIndex('tree_node_acl', 'id-account_type-account_id');
1930             } catch(Exception $e) {}
1931             $this->setTableVersion('tree_node_acl', 2);
1932         }
1933         $this->setApplicationVersion('Tinebase', '10.37');
1934     }
1935
1936     /**
1937      * update to 10.38
1938      *
1939      * set shared folders acl not if not set
1940      */
1941     public function update_37()
1942     {
1943         $this->_addIsDeletedToTreeNodes();
1944         $fileSystem = Tinebase_FileSystem::getInstance();
1945         $inheritPropertyMethod = $this->_getProtectedMethod($fileSystem, '_recursiveInheritPropertyUpdate');
1946         if (Tinebase_Application::getInstance()->isInstalled('Filemanager')) {
1947             try {
1948                 $node = $fileSystem->stat('/Filemanager/folders/shared');
1949                 if (null === $node->acl_node) {
1950                     $fileSystem->setGrantsForNode($node, Tinebase_Model_Grants::getDefaultGrants(array(
1951                         Tinebase_Model_Grants::GRANT_DOWNLOAD => true
1952                     ), array(
1953                         Tinebase_Model_Grants::GRANT_PUBLISH => true
1954                     )));
1955                     $inheritPropertyMethod->invoke($fileSystem, $node, 'acl_node', $node->acl_node, null);
1956                 }
1957             } catch(Tinebase_Exception_NotFound $tenf) {}
1958         }
1959         if (Tinebase_Application::getInstance()->isInstalled('MailFiler')) {
1960             try {
1961                 $node = $fileSystem->stat('/MailFiler/folders/shared');
1962                 if (null === $node->acl_node) {
1963                     $fileSystem->setGrantsForNode($node, Tinebase_Model_Grants::getDefaultGrants(array(
1964                         Tinebase_Model_Grants::GRANT_DOWNLOAD => true
1965                     ), array(
1966                         Tinebase_Model_Grants::GRANT_PUBLISH => true
1967                     )));
1968                     $inheritPropertyMethod->invoke($fileSystem, $node, 'acl_node', $node->acl_node, null);
1969                 }
1970             } catch(Tinebase_Exception_NotFound $tenf) {}
1971         }
1972
1973         $this->setApplicationVersion('Tinebase', '10.38');
1974     }
1975
1976     /**
1977      * GetProtectedMethod constructor.
1978      * @param $object
1979      * @param $method
1980      * @return ReflectionMethod
1981      */
1982     protected function _getProtectedMethod($object, $method)
1983     {
1984         $class = new ReflectionClass($object);
1985         $method = $class->getMethod($method);
1986         $method->setAccessible(true);
1987
1988         return $method;
1989     }
1990
1991     /**
1992      * update to 10.39
1993      *
1994      * tree_nodes add pin_protected
1995      */
1996     public function update_38()
1997     {
1998         if ($this->getTableVersion('tree_nodes') < 6) {
1999             $this->_addIsDeletedToTreeNodes();
2000             $this->setTableVersion('tree_nodes', 6);
2001         }
2002         $this->setApplicationVersion('Tinebase', '10.39');
2003     }
2004
2005     /**
2006      * update to 10.40
2007      *
2008      * tree_nodes make name column case sensitive
2009      */
2010     public function update_39()
2011     {
2012         if ($this->getTableVersion('tree_nodes') < 7) {
2013             if (Tinebase_Core::getDb() instanceof Zend_Db_Adapter_Pdo_Mysql) {
2014                 $this->_backend->alterCol('tree_nodes', new Setup_Backend_Schema_Field_Xml('<field>
2015                         <name>name</name>
2016                         <type>text</type>
2017                         <length>255</length>
2018                         <notnull>true</notnull>
2019                         <collation>utf8_bin</collation>
2020                     </field>'));
2021             }
2022             $this->setTableVersion('tree_nodes', 7);
2023         }
2024         $this->setApplicationVersion('Tinebase', '10.40');
2025     }
2026
2027     /**
2028      * update to 10.41
2029      *
2030      * pgsql - fix bigint issue
2031      */
2032     public function update_40()
2033     {
2034         $applications = Tinebase_Application::getInstance()->getApplications();
2035         /** @var Tinebase_Model_Application $application */
2036         foreach ($applications as $application) {
2037             $setupXml = Setup_Controller::getInstance()->getSetupXml($application->name);
2038             foreach ($setupXml->tables->table as $key => $table) {
2039                 /** @var SimpleXMLElement $field */
2040                 foreach ($table->declaration->field as $field) {
2041                     if ($field->type == 'integer' && !empty($field->length) && $field->length > 19) {
2042                         $this->_backend->alterCol($table->name, new Setup_Backend_Schema_Field_Xml(
2043                             $field->asXML()
2044                         ));
2045                     }
2046                 }
2047             }
2048         }
2049
2050         $this->setApplicationVersion('Tinebase', '10.41');
2051     }
2052 }