0009634: add missing rule clauses on create/update
authorCornelius Weiß <mail@corneliusweiss.de>
Tue, 11 Feb 2014 11:15:22 +0000 (12:15 +0100)
committerPhilipp Schüle <p.schuele@metaways.de>
Tue, 11 Feb 2014 14:45:41 +0000 (15:45 +0100)
* normalize rrule on event inspection
* normalize all rrules via updatescript

Change-Id: Ic028f7fce139d29c3dc0142b3a821e7c2a48876c
Reviewed-on: https://gerrit.tine20.org/tine20/2791
Tested-by: jenkins user
Reviewed-by: Philipp Schüle <p.schuele@metaways.de>
tests/tine20/Calendar/Controller/RecurTest.php
tine20/Calendar/Controller/Event.php
tine20/Calendar/Model/Rrule.php
tine20/Calendar/Setup/Update/Release8.php
tine20/Calendar/Setup/setup.xml

index 05fa78c..9a83f0a 100644 (file)
@@ -47,6 +47,37 @@ class Calendar_Controller_RecurTest extends Calendar_TestCase
         $persistentEvent = $this->_controller->create($event);
     }
     
+    /**
+     * imcomplete rrule clauses should be filled in automatically
+     */
+    public function testIncompleteRrule()
+    {
+        $event = $this->_getRecurEvent();
+        
+        $event->rrule = 'FREQ=WEEKLY';
+        $persistentEvent = $this->_controller->create(clone $event);
+        $this->assertEquals(Calendar_Model_Rrule::getWeekStart(), $persistentEvent->rrule->wkst, 'wkst not normalized');
+        $this->assertEquals('TH', $persistentEvent->rrule->byday, 'byday not normalized');
+        
+        $rrule = Calendar_Model_Rrule::getRruleFromString('FREQ=MONTHLY');
+        $rrule->normalize($event);
+        $this->assertEquals(20, $rrule->bymonthday, 'bymonthday not normalized');
+        
+        $rrule = Calendar_Model_Rrule::getRruleFromString('FREQ=MONTHLY;BYDAY=1TH');
+        $rrule->normalize($event);
+        $this->assertEquals(NULL, $rrule->bymonthday, 'bymonthday must not be added');
+        
+        $rrule = Calendar_Model_Rrule::getRruleFromString('FREQ=YEARLY');
+        $rrule->normalize($event);
+        $this->assertEquals(5, $rrule->bymonth, 'bymonth not normalized');
+        $this->assertEquals(20, $rrule->bymonthday, 'bymonthday not normalized');
+        
+        $rrule = Calendar_Model_Rrule::getRruleFromString('FREQ=YEARLY;BYDAY=1TH');
+        $rrule->normalize($event);
+        $this->assertEquals(5, $rrule->bymonth, 'bymonth not normalized');
+        $this->assertEquals(NULL, $rrule->bymonthday, 'bymonthday must not be added');
+    }
+    
     public function testFirstInstanceException()
     {
         $from = new Tinebase_DateTime('2011-04-18 00:00:00');
index 0859d1e..3188013 100644 (file)
@@ -1407,6 +1407,10 @@ class Calendar_Controller_Event extends Tinebase_Controller_Record_Abstract impl
         }
         $_record->setRruleUntil();
         
+        if ($_record->rrule instanceof Calendar_Model_Rrule) {
+            $_record->rrule->normalize($_record);
+        }
+        
         if ($_record->isRecurException() && $_record->rrule !== NULL) {
             if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
                 . ' Removing invalid rrule from recur exception: ' . $_record->rrule);
index 0945a6a..ebeeed2 100644 (file)
@@ -268,6 +268,44 @@ class Calendar_Model_Rrule extends Tinebase_Record_Abstract
     }
     
     /**
+     * normalizes rrule by setting missing clauses. This is needed as some rrule computations
+     * need all clauses and have no access to the event itself.
+     * 
+     * @param Calendar_Model_Event $event
+     */
+    public function normalize(Calendar_Model_Event $event) {
+        switch ($this->freq) {
+            case self::FREQ_WEEKLY:
+                if (! $this->wkst ) {
+                    $this->wkst = self::getWeekStart();
+                }
+            
+                if (! $this->byday) {
+                    $this->byday = array_search($event->dtstart->format('w'), self::$WEEKDAY_DIGIT_MAP);
+                }
+                break;
+            
+            case self::FREQ_MONTHLY:
+                if (! $this->byday && ! $this->bymonthday) {
+                    $this->bymonthday = $event->dtstart->format('j');
+                }
+                break;
+                
+            case self::FREQ_YEARLY:
+                if (! $this->byday && ! $this->bymonthday) {
+                    $this->bymonthday = $event->dtstart->format('j');
+                }
+                if (! $this->bymonth) {
+                    $this->bymonth = $event->dtstart->format('n');
+                }
+                break;
+            default:
+                // do nothing
+                break;
+        }
+    }
+    
+    /**
      * get human readable version of this rrule
      * 
      * @param  Zend_Translate   $translation
@@ -622,8 +660,7 @@ class Calendar_Model_Rrule extends Tinebase_Record_Abstract
                 }
                 
                 if (! $rrule->wkst) {
-                    // @TODO if organizer has an account get its locales wkst
-                    $rrule->wkst = self::WDAY_MONDAY;
+                    $rrule->wkst = self::getWeekStart();
                 }
                 $weekDays = array_keys(self::$WEEKDAY_DIGIT_MAP);
                 array_splice($weekDays, 0, 0, array_splice($weekDays, array_search($rrule->wkst, $weekDays)));
@@ -1130,4 +1167,17 @@ class Calendar_Model_Rrule extends Tinebase_Record_Abstract
         $_dateInUTC->subHour($_dateInUTC->get('I') ? 1 : 0);
         $_dateInUTC->setTimezone('UTC');
     }
+    
+    /**
+     * returns weekstart in iCal day format
+     * 
+     * @param  string $locale
+     * @return string
+     */
+    public static function getWeekStart($locale = NULL) {
+        $locale = $locale ?: Tinebase_Core::getLocale();
+        
+        $weekInfo = Zend_Locale::getTranslationList('week', $locale);
+        return array_value($weekInfo['firstDay'], array_flip(self::$WEEKDAY_MAP));
+    }
 }
index 96aad32..e04d8bc 100644 (file)
@@ -59,4 +59,39 @@ class Calendar_Setup_Update_Release8 extends Setup_Update_Abstract
         $this->setTableVersion('cal_attendee', 5);
         $this->setApplicationVersion('Calendar', '8.1');
     }
+    
+    /**
+     * update to 8.2
+     * - normalize all rrules
+     */
+    public function update_1()
+    {
+        // find all events with rrule
+        $eventIds = $this->_db->query(
+                "SELECT " . $this->_db->quoteIdentifier('id') .
+                " FROM " . $this->_db->quoteIdentifier(SQL_TABLE_PREFIX . "cal_events") .
+                " WHERE " . $this->_db->quoteIdentifier("rrule") . " IS NOT NULL"
+        )->fetchAll(Zend_Db::FETCH_ASSOC);
+        
+        // NOTE: we need a generic sql BE to circumvent calendar specific acl issues
+        $eventBE = new Tinebase_Backend_Sql(array(
+                'modelName'    => 'Calendar_Model_Event',
+                'tableName'    => 'cal_events',
+                'modlogActive' => false
+        ));
+        
+        foreach ($eventIds as $eventId) {
+            $event = $eventBE->get($eventId['id']);
+            $oldRruleString = (string) $event->rrule;
+            $rrule = Calendar_Model_Rrule::getRruleFromString($oldRruleString);
+            $rrule->normalize($event);
+            
+            if ($oldRruleString != (string) $rrule) {
+                $event->rrule = (string) $rrule;
+                $eventBE->update($event);
+            }
+        }
+        
+        $this->setApplicationVersion('Calendar', '8.2');
+    }
 }
index 98545f1..462a9dd 100644 (file)
@@ -2,7 +2,7 @@
 <application>
     <name>Calendar</name>
     <!-- gettext('Calendar') -->   
-    <version>8.1</version>
+    <version>8.2</version>
     <order>15</order>
     <status>enabled</status>
     <tables>