* Calendar: adding default alarm for regular or whole-day events, preference is shared with CalDAV clients

This commit is contained in:
Ralf Becker 2014-05-28 10:03:57 +00:00
parent bb5b1163cb
commit f0e391220f
7 changed files with 203 additions and 17 deletions

View File

@ -146,6 +146,23 @@ class calendar_bo
'OPT-PARTICIPANT' => 'Optional', 'OPT-PARTICIPANT' => 'Optional',
'NON-PARTICIPANT' => 'None', 'NON-PARTICIPANT' => 'None',
); );
/**
* Alarm times
*
* @var array
*/
var $alarms = array(
300 => '5 Minutes',
600 => '10 Minutes',
900 => '15 Minutes',
1800 => '30 Minutes',
3600 => '1 Hour',
7200 => '2 Hours',
43200 => '12 Hours',
86400 => '1 Day',
172800 => '2 Days',
604800 => '1 Week',
);
/** /**
* @var array $resources registered scheduling resources of the calendar (gets cached in the session for performance reasons) * @var array $resources registered scheduling resources of the calendar (gets cached in the session for performance reasons)
*/ */
@ -253,6 +270,34 @@ class calendar_bo
$this->categories = new categories($this->user,'calendar'); $this->categories = new categories($this->user,'calendar');
$this->customfields = config::get_customfields('calendar'); $this->customfields = config::get_customfields('calendar');
foreach($this->alarms as $secs => &$label)
{
$label = self::secs2label($secs);
}
}
/**
* Generate translated label for a given number of seconds
*
* @param int $secs
* @return string
*/
static public function secs2label($secs)
{
if ($secs <= 3600)
{
$label = lang('%1 minutes', $secs/60);
}
elseif($secs <= 86400)
{
$label = lang('%1 hours', $secs/3600);
}
else
{
$label = lang('%1 days', $secs/86400);
}
return $label;
} }
/** /**

View File

@ -154,7 +154,8 @@ class calendar_hooks
{ {
if (!$hook_data['setup']) // does not work on setup time if (!$hook_data['setup']) // does not work on setup time
{ {
ExecMethod('calendar.calendar_bo.check_set_default_prefs'); $bo = new calendar_bo();
$bo->check_set_default_prefs();
} }
$mainscreen = array( $mainscreen = array(
'0' => lang('None'), '0' => lang('None'),
@ -276,7 +277,7 @@ class calendar_hooks
} }
$settings = array( $settings = array(
array( '1.section' => array(
'type' => 'section', 'type' => 'section',
'title' => lang('General settings'), 'title' => lang('General settings'),
'no_lang'=> true, 'no_lang'=> true,
@ -411,7 +412,7 @@ class calendar_hooks
'admin' => False, 'admin' => False,
'forced' => 'all', 'forced' => 'all',
), ),
array( '2.section' => array(
'type' => 'section', 'type' => 'section',
'title' => lang('appointment settings'), 'title' => lang('appointment settings'),
'no_lang'=> true, 'no_lang'=> true,
@ -429,6 +430,47 @@ class calendar_hooks
'admin' => False, 'admin' => False,
'default'=> 60, 'default'=> 60,
), ),
'default-alarm' => array(
'type' => 'select',
'label' => 'Default alarm for regular events',
'name' => 'default-alarm',
'values' => isset($bo) ? array(0 => lang('None'))+$bo->alarms : array(),
'help' => 'Alarm added automatic to new events before event start-time',
'xmlrpc' => True,
'admin' => False,
'default' => 0,
),
'default-alarm-wholeday' => array(
'type' => 'select',
'label' => 'Default alarm for whole-day events',
'name' => 'default-alarm-wholeday',
'values' => isset($bo) ? array(0 => lang('None'))+$bo->alarms : array(),
'help' => lang('Alarm added automatic to new events before event start-time').' ('.lang('Midnight').')',
'xmlrpc' => True,
'admin' => False,
'default' => 0,
)
);
if (isset($bo)) // add custom time-spans set by CalDAV clients, not in our prefs
{
$prefs = $GLOBALS['egw_info']['user']['preferences']['calendar'];
$data = array(
'prefs' => &$prefs, // use reference to get preference value back
'preprocess' => true,
'type' => 'user',
);
self::verify_settings($data);
foreach(array('default-alarm', 'default-alarm-wholeday') as $name)
{
$value = $prefs[$name];
if ($value > 0 && !isset($bo->alarms[$value]))
{
$settings[$name]['values'][$value] = calendar_bo::secs2label($value);
ksort($settings[$name]['values']);
}
}
}
$settings += array(
'defaultresource_sel' => array( 'defaultresource_sel' => array(
'type' => 'select', 'type' => 'select',
'label' => 'default type of resources selection', 'label' => 'default type of resources selection',
@ -458,7 +500,7 @@ class calendar_hooks
'xmlrpc' => True, 'xmlrpc' => True,
'admin' => False, 'admin' => False,
), ),
array( '3.section' => array(
'type' => 'section', 'type' => 'section',
'title' => lang('notification settings'), 'title' => lang('notification settings'),
'no_lang'=> true, 'no_lang'=> true,
@ -579,7 +621,7 @@ class calendar_hooks
'xmlrpc' => True, 'xmlrpc' => True,
'admin' => False, 'admin' => False,
), ),
array( '4.section' => array(
'type' => 'section', 'type' => 'section',
'title' => lang('Data exchange settings'), 'title' => lang('Data exchange settings'),
'no_lang'=> true, 'no_lang'=> true,
@ -696,6 +738,87 @@ class calendar_hooks
return $settings; return $settings;
} }
/**
* Verify settings hook called to generate errors about settings used here to store default alarms in CalDAV prefs
*
* @param array $data
* array $data['prefs']
* string $data['type'] 'user', 'default' or 'forced'
* boolean $data['preprocess'] true data just shown to user, false: data stored by user
*/
public static function verify_settings(array $data)
{
//error_log(__METHOD__."(".array2string($data).")");
// caldav perfs are always user specific and cant by switched off
if ($data['type'] == 'user')
{
$account_lid = $GLOBALS['egw_info']['user']['account_lid'];
foreach(array(
'default-alarm' => 'default-alarm-vevent-datetime:/'.$account_lid.'/:urn:ietf:params:xml:ns:caldav',
'default-alarm-wholeday' => 'default-alarm-vevent-date:/'.$account_lid.'/:urn:ietf:params:xml:ns:caldav',
) as $name => $dav)
{
$pref =& $GLOBALS['egw_info']['user']['preferences']['groupdav'][$dav];
if (true) $pref = str_replace("\r", '', $pref); // remove CR messing up multiline preg_match
$val = $data['prefs'][$name];
//error_log(__METHOD__."() groupdav[$dav]=$pref, calendar[$name]=$val");
if ($data['preprocess']) // showing preferences
{
if ((string)$data['prefs'][$name] === '') // no calendar pref --> read value from caldav
{
$matches = null;
if (preg_match('/^ACTION:NONE$/i', $pref))
{
$data['prefs'][$name] = '0';
}
elseif (preg_match('/^TRIGGER:-PT(\d+(M|H|D))$/mi', $pref, $matches))
{
static $factors = array(
'M' => 60,
'H' => 3600,
'D' => 86400,
);
$factor = $factors[strtoupper($matches[2])];
$data['prefs'][$name] = $factor*(int)$matches[1];
}
else
{
$data['prefs'][$name] = '0';
}
error_log(__METHOD__."() setting $name={$data['prefs'][$name]} from $dav='$pref'");
}
}
else // storing preferences
{
if (empty($pref) || !preg_match('/^TRIGGER:/m', $pref))
{
$pref = 'BEGIN:VALARM
TRIGGER:-PT1H
ATTACH;VALUE=URI:Basso
ACTION:AUDIO
END:VALARM';
}
if (!$val)
{
$pref = preg_replace('/^ACTION:.*$/m', 'ACTION:NONE', $pref);
}
elseif ($val < 3600)
{
$pref = preg_replace('/^TRIGGER:.*$/m', 'TRIGGER:-PT'.number_format($val/60, 0).'M', $pref);
}
else
{
$pref = preg_replace('/^TRIGGER:.*$/m', 'TRIGGER:-PT'.number_format($val/3600, 0).'H', $pref);
}
$GLOBALS['egw']->preferences->add('groupdav', $dav, $pref, 'user');
error_log(__METHOD__."() storing $name=$val --> $dav='$pref'");
}
}
$GLOBALS['egw']->preferences->save_repository();
}
}
public static function config_validate() public static function config_validate()
{ {
$GLOBALS['egw_info']['server']['found_validation_hook'] = array('calendar_purge_old'); $GLOBALS['egw_info']['server']['found_validation_hook'] = array('calendar_purge_old');

View File

@ -1125,8 +1125,7 @@ class calendar_uiforms extends calendar_ui
'status' => $this->bo->verbose_status, 'status' => $this->bo->verbose_status,
'duration' => $this->durations, 'duration' => $this->durations,
'role' => $this->bo->roles, 'role' => $this->bo->roles,
'new_alarm[options]' =>array(300 => lang('5 Minutes'), 600 => lang('10 Minutes'), 900 => lang('15 Minutes'), 1800 => lang('30 Minutes'), 3600 => lang('1 Hour'), 7200 => lang('2 Hours'), 'new_alarm[options]' => $this->bo->alarms+array(0 => lang('Custom')),
43200 => lang('12 Hours'), 86400 => lang('1 Day'), 172800 => lang('2 Days'), 604800 => lang('1 Week'), 0 => lang('Custom')),
'before_after'=>array(0 => lang('Before'), 1 => lang('After')), 'before_after'=>array(0 => lang('Before'), 1 => lang('After')),
'action' => array( 'action' => array(
'copy' => array('label' => 'Copy', 'title' => 'Copy this event'), 'copy' => array('label' => 'Copy', 'title' => 'Copy this event'),

View File

@ -1,6 +1,9 @@
%1 %2 in %3 calendar de %1 %2 im %3 %1 %2 in %3 calendar de %1 %2 im %3
%1 days calendar de %1 Tage
%1 event(s) %2 calendar de %1 Termin(e) %2 %1 event(s) %2 calendar de %1 Termin(e) %2
%1 event(s) %2, %3 failed because of insufficent rights !!! calendar de %1 Termin(e) %2, %3 wegen fehlender Rechte !!! %1 event(s) %2, %3 failed because of insufficent rights !!! calendar de %1 Termin(e) %2, %3 wegen fehlender Rechte !!!
%1 hours calendar de %1 Stunden
%1 minutes calendar de %1 Minuten
%1 participants removed because of missing invite grants calendar de %1 Teilnehmer entfernt wegen fehlender Einladungsrechte %1 participants removed because of missing invite grants calendar de %1 Teilnehmer entfernt wegen fehlender Einladungsrechte
%1 records imported calendar de %1 Datensätze importiert %1 records imported calendar de %1 Datensätze importiert
%1 records read (not yet imported, you may go back and uncheck test import) calendar de %1 Datensätze gelesen (noch nicht importiert, Sie können zurück gehen und Test Import ausschalten) %1 records read (not yet imported, you may go back and uncheck test import) calendar de %1 Datensätze gelesen (noch nicht importiert, Sie können zurück gehen und Test Import ausschalten)
@ -33,6 +36,7 @@ after current date calendar de Nach dem aktuellen Datum
age: calendar de Alter: age: calendar de Alter:
alarm calendar de Alarm alarm calendar de Alarm
alarm added calendar de Alarm zugefügt alarm added calendar de Alarm zugefügt
alarm added automatic to new events before event start-time calendar de Der Alarm wird automatisch bei neuen Termin vor dem Startdatum eingefügt
alarm deleted calendar de Alarm gelöscht alarm deleted calendar de Alarm gelöscht
alarm for %1 at %2 in %3 calendar de Alarm für %1 am %2 in %3 alarm for %1 at %2 in %3 calendar de Alarm für %1 am %2 in %3
alarm management calendar de Alarm Management alarm management calendar de Alarm Management
@ -113,6 +117,7 @@ creator calendar de Ersteller
csv calendar de CSV csv calendar de CSV
csv-fieldname calendar de CSV-Feldname csv-fieldname calendar de CSV-Feldname
csv-filename calendar de CSV-Dateiname csv-filename calendar de CSV-Dateiname
custom calendar de Benutzerdefiniert
custom fields common de Benutzerdefinierte Felder custom fields common de Benutzerdefinierte Felder
custom_2 common de frei / besetzt custom_2 common de frei / besetzt
daily calendar de Täglich daily calendar de Täglich
@ -125,6 +130,8 @@ days calendar de Tage
days of the week for a weekly repeated event calendar de Wochentage für wöchentlich wiederholten Termin days of the week for a weekly repeated event calendar de Wochentage für wöchentlich wiederholten Termin
days repeated calendar de wiederholte Tage days repeated calendar de wiederholte Tage
dayview calendar de Tagesansicht dayview calendar de Tagesansicht
default alarm for regular events calendar de Default-Alarm für normale Termine
default alarm for whole-day events calendar de Default-Alarm für ganztägige Termine
default appointment length (in minutes) calendar de Standardlänge eines neuen Kalendereintrags (in Minuten) default appointment length (in minutes) calendar de Standardlänge eines neuen Kalendereintrags (in Minuten)
default calendar filter calendar de Standard-Filter des Kalenders default calendar filter calendar de Standard-Filter des Kalenders
default calendar view calendar de Standard-Ansicht des Kalenders default calendar view calendar de Standard-Ansicht des Kalenders
@ -314,6 +321,7 @@ maximum available quantity of %1 exceeded! calendar de Maximale Anzahl von %1 er
meeting request calendar de Terminanfrage meeting request calendar de Terminanfrage
meetingrequest to all participants calendar de Terminanforderung an alle Teilnehmer meetingrequest to all participants calendar de Terminanforderung an alle Teilnehmer
merge document... calendar de Dokument einfügen... merge document... calendar de Dokument einfügen...
midnight calendar de Mitternacht
minutes calendar de Minuten minutes calendar de Minuten
modified calendar de Geändert modified calendar de Geändert
modifier calendar de Geändert von modifier calendar de Geändert von

View File

@ -1,6 +1,9 @@
%1 %2 in %3 calendar en %1 %2 in %3 %1 %2 in %3 calendar en %1 %2 in %3
%1 days calendar en %1 days
%1 event(s) %2 calendar en %1 event(s) %2 %1 event(s) %2 calendar en %1 event(s) %2
%1 event(s) %2, %3 failed because of insufficent rights !!! calendar en %1 event(s) %2, %3 failed because of insufficient rights! %1 event(s) %2, %3 failed because of insufficent rights !!! calendar en %1 event(s) %2, %3 failed because of insufficient rights!
%1 hours calendar en %1 hours
%1 minutes calendar en %1 minutes
%1 participants removed because of missing invite grants calendar en %1 participants removed because of missing invite grants. %1 participants removed because of missing invite grants calendar en %1 participants removed because of missing invite grants.
%1 records imported calendar en %1 records imported. %1 records imported calendar en %1 records imported.
%1 records read (not yet imported, you may go back and uncheck test import) calendar en %1 records read. Not yet imported, go back and uncheck Test import. %1 records read (not yet imported, you may go back and uncheck test import) calendar en %1 records read. Not yet imported, go back and uncheck Test import.
@ -33,6 +36,7 @@ after current date calendar en After current date
age: calendar en Age: age: calendar en Age:
alarm calendar en Alarm alarm calendar en Alarm
alarm added calendar en Alarm added. alarm added calendar en Alarm added.
alarm added automatic to new events before event start-time calendar en Alarm added automatic to new events before event start-time
alarm deleted calendar en Alarm deleted. alarm deleted calendar en Alarm deleted.
alarm for %1 at %2 in %3 calendar en Alarm for %1 at %2 in %3 alarm for %1 at %2 in %3 calendar en Alarm for %1 at %2 in %3
alarm management calendar en Alarm management alarm management calendar en Alarm management
@ -113,6 +117,7 @@ creator calendar en Creator
csv calendar en CSV csv calendar en CSV
csv-fieldname calendar en CSV field name csv-fieldname calendar en CSV field name
csv-filename calendar en CSV file name csv-filename calendar en CSV file name
custom calendar en Custom
custom fields common en Custom fields custom fields common en Custom fields
custom_2 common en Free/Busy custom_2 common en Free/Busy
daily calendar en Daily daily calendar en Daily
@ -125,6 +130,8 @@ days calendar en Days
days of the week for a weekly repeated event calendar en Days of the week for a weekly repeated event days of the week for a weekly repeated event calendar en Days of the week for a weekly repeated event
days repeated calendar en Days repeated days repeated calendar en Days repeated
dayview calendar en Day view dayview calendar en Day view
default alarm for regular events calendar en Default alarm for regular events
default alarm for whole-day events calendar en Default alarm for whole-day events
default appointment length (in minutes) calendar en Default appointment length in minutes default appointment length (in minutes) calendar en Default appointment length in minutes
default calendar filter calendar en Default calendar filter default calendar filter calendar en Default calendar filter
default calendar view calendar en Default calendar view default calendar view calendar en Default calendar view
@ -314,6 +321,7 @@ maximum available quantity of %1 exceeded! calendar en Maximum available quantit
meeting request calendar en Meeting request meeting request calendar en Meeting request
meetingrequest to all participants calendar en Meetingrequest to all participants meetingrequest to all participants calendar en Meetingrequest to all participants
merge document... calendar en Merge document... merge document... calendar en Merge document...
midnight calendar en Midnight
minutes calendar en Minutes minutes calendar en Minutes
modified calendar en Modified modified calendar en Modified
modifier calendar en Modifier modifier calendar en Modifier

View File

@ -38,6 +38,7 @@ $setup_info['calendar']['hooks']['admin'] = 'calendar_hooks::admin';
$setup_info['calendar']['hooks']['deleteaccount'] = 'calendar.calendar_so.deleteaccount'; $setup_info['calendar']['hooks']['deleteaccount'] = 'calendar.calendar_so.deleteaccount';
$setup_info['calendar']['hooks']['home'] = 'calendar_hooks::home'; $setup_info['calendar']['hooks']['home'] = 'calendar_hooks::home';
$setup_info['calendar']['hooks']['settings'] = 'calendar_hooks::settings'; $setup_info['calendar']['hooks']['settings'] = 'calendar_hooks::settings';
$setup_info['calendar']['hooks']['verify_settings'] = 'calendar_hooks::verify_settings';
$setup_info['calendar']['hooks']['sidebox_menu'] = 'calendar.calendar_ui.sidebox_menu'; $setup_info['calendar']['hooks']['sidebox_menu'] = 'calendar.calendar_ui.sidebox_menu';
$setup_info['calendar']['hooks']['search_link'] = 'calendar_hooks::search_link'; $setup_info['calendar']['hooks']['search_link'] = 'calendar_hooks::search_link';
$setup_info['calendar']['hooks']['config_validate'] = 'calendar_hooks::config_validate'; $setup_info['calendar']['hooks']['config_validate'] = 'calendar_hooks::config_validate';

View File

@ -140,12 +140,6 @@ class preferences_settings
'preferences' : $content['current_app']; 'preferences' : $content['current_app'];
egw_framework::includeCSS('preferences','app'); egw_framework::includeCSS('preferences','app');
$sel_options = $readonlys = null;
$content = $this->get_content($appname, $type, $sel_options, $readonlys, $preserve['types'], $tpl);
$preserve['appname'] = $preserve['old_appname'] = $content['appname'];
$preserve['type'] = $preserve['old_type'] = $content['type'];
if (isset($old_tab)) $content['tabs'] = $old_tab;
// if not just saved, call validation before, to be able to show failed validation of current prefs // if not just saved, call validation before, to be able to show failed validation of current prefs
if (!isset($button)) if (!isset($button))
{ {
@ -153,6 +147,13 @@ class preferences_settings
$msg = $this->process_array($GLOBALS['egw']->preferences->$attribute, $msg = $this->process_array($GLOBALS['egw']->preferences->$attribute,
(array)$GLOBALS['egw']->preferences->{$attribute}[$appname], $preserve['types'], $appname, $attribute, true); (array)$GLOBALS['egw']->preferences->{$attribute}[$appname], $preserve['types'], $appname, $attribute, true);
} }
$sel_options = $readonlys = null;
$content = $this->get_content($appname, $type, $sel_options, $readonlys, $preserve['types'], $tpl);
$preserve['appname'] = $preserve['old_appname'] = $content['appname'];
$preserve['type'] = $preserve['old_type'] = $content['type'];
if (isset($old_tab)) $content['tabs'] = $old_tab;
if ($msg) egw_framework::message($msg, $msg_type ? $msg_type : 'error'); if ($msg) egw_framework::message($msg, $msg_type ? $msg_type : 'error');
$tpl->exec('preferences.preferences_settings.index', $content, $sel_options, $readonlys, $preserve, 2); $tpl->exec('preferences.preferences_settings.index', $content, $sel_options, $readonlys, $preserve, 2);
@ -250,8 +251,9 @@ class preferences_settings
// //
if(($error .= $GLOBALS['egw']->hooks->single(array( if(($error .= $GLOBALS['egw']->hooks->single(array(
'location' => 'verify_settings', 'location' => 'verify_settings',
'prefs' => $repository[$appname], 'prefs' => &$repository[$appname],
'type' => $type 'type' => $type,
'preprocess' => $only_verify,
), ),
$appname $appname
))) )))