From 64e1a5a830674e37c33e590a7750a761eae2fe78 Mon Sep 17 00:00:00 2001 From: nathangray Date: Tue, 18 Jun 2019 15:11:53 -0600 Subject: [PATCH] Calendar - create function for reset of participant status when event is moved - Still respecting preference for users - Always resetting non-user participants --- calendar/inc/class.calendar_boupdate.inc.php | 59 ++++ calendar/inc/class.calendar_uiforms.inc.php | 43 --- calendar/tests/ResetParticipantStatusTest.php | 283 ++++++++++++++++++ 3 files changed, 342 insertions(+), 43 deletions(-) create mode 100644 calendar/tests/ResetParticipantStatusTest.php diff --git a/calendar/inc/class.calendar_boupdate.inc.php b/calendar/inc/class.calendar_boupdate.inc.php index f8d761636c..6b840ea2e3 100644 --- a/calendar/inc/class.calendar_boupdate.inc.php +++ b/calendar/inc/class.calendar_boupdate.inc.php @@ -245,6 +245,9 @@ class calendar_boupdate extends calendar_bo return $conflicts; } + // See if we need to reset any participant statuses + $this->check_reset_stati($event, $old_event); + //echo "saving $event[id]="; _debug_array($event); $event2save = $event; @@ -2917,4 +2920,60 @@ class calendar_boupdate extends calendar_bo $this->so->purge(time() - 365*24*3600*(float)$age); } } + + /** + * Check to see if we need to reset the status of any of the participants + * - Current user is never reset + * - Other users we respect their preference + * - Non-users status is always reset + * + * @param Array $event New event + * @param Array $old_event Event before modification + * + * @return boolean true if any statuses were reset + */ + protected function check_reset_stati(&$event, $old_event) + { + if(!$old_event || !is_array($old_event)) + { + return false; + } + + $status_reset = false; + $sameday = (date('Ymd', $old_event['start']) == date('Ymd', $event['start'])); + foreach((array)$event['participants'] as $uid => $status) + { + $q = $r = null; + calendar_so::split_status($status,$q,$r); + if($uid == $this->user || $status == 'U') + { + continue; + } + + // Just user accounts + if (is_int($uid)) + { + $preferences = new Api\Preferences($uid); + $part_prefs = $preferences->read_repository(); + switch ($part_prefs['calendar']['reset_stati']) + { + case 'no': + break; + case 'startday': + if ($sameday) break; + default: + $status_reset = true; + $event['participants'][$uid] = calendar_so::combine_status('U',$q,$r); + } + } + // All other participant types + else + { + $status_reset = true; + $event['participants'][$uid] = calendar_so::combine_status('U',$q,$r); + } + } + return $status_reset; + + } } diff --git a/calendar/inc/class.calendar_uiforms.inc.php b/calendar/inc/class.calendar_uiforms.inc.php index 4268be3615..3b1500a254 100644 --- a/calendar/inc/class.calendar_uiforms.inc.php +++ b/calendar/inc/class.calendar_uiforms.inc.php @@ -852,28 +852,6 @@ class calendar_uiforms extends calendar_ui $old_event['end'] != $event['end'] || $event['whole_day'] != $old_event['whole_day']) { - $sameday = (date('Ymd', $old_event['start']) == date('Ymd', $event['start'])); - foreach((array)$event['participants'] as $uid => $status) - { - $q = $r = null; - calendar_so::split_status($status,$q,$r); - if ($uid[0] != 'c' && $uid[0] != 'e' && $uid != $this->bo->user && $status != 'U') - { - $preferences = new Api\Preferences($uid); - $part_prefs = $preferences->read_repository(); - switch ($part_prefs['calendar']['reset_stati']) - { - case 'no': - break; - case 'startday': - if ($sameday) break; - default: - $status_reset_to_unknown = true; - $event['participants'][$uid] = calendar_so::combine_status('U',$q,$r); - // todo: report reset status to user - } - } - } // check if we need to move the alarms, because they are relative $this->bo->check_move_alarms($event, $old_event); } @@ -3060,27 +3038,6 @@ class calendar_uiforms extends calendar_ui $status_reset_to_unknown = false; $sameday = (date('Ymd', $old_event['start']) == date('Ymd', $event['start'])); - foreach((array)$event['participants'] as $uid => $status) - { - $q = $r = null; - calendar_so::split_status($status,$q,$r); - if ($uid[0] != 'c' && $uid[0] != 'e' && $uid != $this->bo->user && $status != 'U') - { - $preferences = new Api\Preferences($uid); - $part_prefs = $preferences->read_repository(); - switch ($part_prefs['calendar']['reset_stati']) - { - case 'no': - break; - case 'startday': - if ($sameday) break; - default: - $status_reset_to_unknown = true; - $event['participants'][$uid] = calendar_so::combine_status('U',$q,$r); - // todo: report reset status to user - } - } - } $message = false; $conflicts=$this->bo->update($event,$ignore_conflicts, true, false, true, $message); diff --git a/calendar/tests/ResetParticipantStatusTest.php b/calendar/tests/ResetParticipantStatusTest.php new file mode 100644 index 0000000000..c67b4674d5 --- /dev/null +++ b/calendar/tests/ResetParticipantStatusTest.php @@ -0,0 +1,283 @@ +bo = new \calendar_boupdate(); + + // Add another user + $this->account_id = $this->make_test_user(); + + // Make check_reset_status method accessable + $class = new \ReflectionClass($this->bo); + $this->check_method = $class->getMethod('check_reset_stati'); + $this->check_method->setAccessible(true); + } + + public function tearDown() + { + + // Clean up user + $GLOBALS['egw']->accounts->delete($this->account_id); + } + + /** + * Test that various participant strings are not changed if nothing changes + * + * @param array $participant Participant to test + * + * @dataProvider participantProvider + */ + public function testNoChange($participant) + { + $this->fix_id($participant); + + // Get test event + $event = $old_event = $this->get_event(); + + // No change + $event['participant'] = $old_event['participant'] = $participant; + + // Check & reset status + $reset = $this->check_method->invokeArgs($this->bo, array(&$event, $old_event)); + + // Verify + $this->assertFalse($reset); + } + + + /** + * Test that moving the event forward 1 hour works correctly. + * - For current user, no change to status + * - For other users, respect the preference + * - For non-users, always reset status. + * + * @param type $participant + * + * @dataProvider participantProvider + */ + public function testForwardOneHour($participant) + { + $this->fix_id($participant); + $participant[$this->account_id] = 'A'; + + // Get test event + $event = $old_event = $this->get_event(); + $event['participants'] = $old_event['participants'] = $participant; + + // Forward 1 hour + $event['start'] += 3600; + $event['end'] += 3600; + + // Set preference to only if start day changes, so no reset is done + $pref = array( + 'account' => $this->account_id, + 'pref' => 'user', + 'app' => 'calendar', + 'set' => array('reset_stati' => 'startday') + ); + $pref_command = new \admin_cmd_edit_preferences($pref); + $pref_command->run(); + + + // Check & reset status + $reset = $this->check_method->invokeArgs($this->bo, array(&$event, $old_event)); + + // Verify change as expected + foreach($event['participants'] as $id => $status) + { + if($id == $this->bo->user) + { + // Current user, no change + $this->assertEquals($participant[$id], $status, "Participant $id was changed"); + } + if(is_int($id)) + { + // Users respect preference, in this case no change + $this->assertEquals($participant[$id], $status, "Participant $id was changed"); + } + else + { + // Non-user gets reset + $this->assertEquals('U', $status[0], "Participant $id did not get reset"); + } + } + } + + /** + * Test that moving the event to a different day resets or keeps status for + * user accounts according to that account's preference + * + * @param Array $change_preference One of the allowed preference values + * + * @dataProvider statiPreferenceProvider + */ + public function testChangeUsesPreference($change_preference) + { + // Get test event + $event = $old_event = $this->get_event(); + $participant = $event['participants'] = $old_event['participants'] = array( + // Current user is never changed + $this->bo->user => 'A', + // Other user will use preference + $this->account_id => 'A' + ); + + // Set preference + $pref = array( + 'account' => $this->account_id, + 'pref' => 'user', + 'app' => 'calendar', + 'set' => array('reset_stati' => $change_preference) + ); + $pref_command = new \admin_cmd_edit_preferences($pref); + $pref_command->run(); + + // Forward 1 day + $event['start'] += 24*3600; + $event['end'] += 24*3600; + + // Check & reset status + $reset = $this->check_method->invokeArgs($this->bo, array(&$event, $old_event)); + + // Verify no change in current user + $this->assertEquals($participant[$this->bo->user], $event['participants'][$this->bo->user]); + + // Other user may change though + switch($pref) + { + case 'no': + $this->assertFalse($reset); + $this->assertEquals($participant[$this->account_id], $event['participants'][$this->account_id]); + break; + case 'all': + case 'sameday': + $this->assertTrue($reset); + $this->assertEquals('U', $event['participants'][$this->account_id][0]); + break; + } + } + + protected function get_event() + { + return array( + 'title' => 'Test event for ' . $this->getName(), + 'owner' => $GLOBALS['egw_info']['user']['account_id'], + 'start' => 1602324600, + 'end' => 1602328200 + ); + } + + protected function make_test_user() + { + $account = array( + 'account_lid' => 'user_test', + 'account_firstname' => 'Test', + 'account_lastname' => 'Test' + ); + $command = new \admin_cmd_edit_user(false, $account); + $command->comment = 'Needed for unit test ' . $this->getName(); + $command->run(); + return $command->account; + } + + /** + * Account ID is unknown when participantProvider is run, so we swap in + * the ID + * + * @param Array $participants + */ + protected function fix_id(&$participants) + { + // Provider didn't know test user's ID, so swap it in + foreach($participants as $id => $status) + { + if($id == $GLOBALS['egw_info']['user']['account_lid']) + { + unset($participants[$id]); + $participants[$GLOBALS['egw_info']['user']['account_id']] = $status; + } + } + } + + /** + * Different values for the status change on event change preference + * + * @see calendar_hooks::settings() + */ + public function statiPreferenceProvider() + { + return array( + array('no'), // Never change status + array('all'),// Always change status + array('startday') // Change status of start date changes + ); + } + + public function participantProvider() + { + return array( + // Participant ID => status + + // User - 'demo' will get changed for real ID later + array(array('demo' => 'A')), + array(array('demo' => 'R')), + array(array('demo' => 'T')), + array(array('demo' => 'U')), + array(array('demo' => 'D')), + + // These don't have to be real IDs since we're not actually doing + // anything with the entry itself, just checking its type + + // Contact + array(array('c1' => 'A')), + array(array('c1' => 'R')), + array(array('c1' => 'T')), + array(array('c1' => 'U')), + array(array('c1' => 'D')), + + // Resource + array(array('r1' => 'A')), + array(array('r1' => 'R')), + array(array('r1' => 'T')), + array(array('r1' => 'U')), + array(array('r1' => 'D')), + + // All together, just for fun + array(array('demo' => 'A', 'c1' => 'D', 'r1' => 'T')) + ); + } +} \ No newline at end of file