$tracking_mode_part = '';
$record_type_part = '';
$plugins_part = '';
+ $lock_spec_part = '';
if (isset($fields['address'])) $addr_part = ', address = '.$mdb2->quote($fields['address']);
if (isset($fields['currency'])) $currency_part = ', currency = '.$mdb2->quote($fields['currency']);
if (isset($fields['tracking_mode'])) $tracking_mode_part = ', tracking_mode = '.intval($fields['tracking_mode']);
if (isset($fields['record_type'])) $record_type_part = ', record_type = '.intval($fields['record_type']);
if (isset($fields['plugins'])) $plugins_part = ', plugins = '.$mdb2->quote($fields['plugins']);
+ if (isset($fields['lock_spec'])) $lock_spec_part = ', lock_spec = '.$mdb2->quote($fields['lock_spec']);
$sql = "update tt_teams set $name_part $addr_part $currency_part $locktime_part $lang_part $decimal_mark_part
- $date_format_part $time_format_part $week_start_part $tracking_mode_part $record_type_part $plugins_part where id = $team_id";
+ $date_format_part $time_format_part $week_start_part $tracking_mode_part $record_type_part
+ $plugins_part $lock_spec_part where id = $team_id";
$affected = $mdb2->exec($sql);
if (is_a($affected, 'PEAR_Error')) {
var $custom_logo = 0; // Whether to use a custom logo for team.
var $address = null; // Address for invoices.
var $lock_interval = 0; // Lock interval in days for time records.
+ var $lock_spec = null; // Cron specification for record locking.
var $rights = 0; // A mask of user rights.
// Constructor.
$mdb2 = getConnection();
$sql = "SELECT u.id, u.login, u.name, u.team_id, u.role, u.client_id, u.email, t.name as team_name,
- t.address, t.currency, t.locktime, t.lang, t.decimal_mark, t.date_format, t.time_format, t.week_start, t.tracking_mode, t.record_type, t.plugins, t.custom_logo
+ t.address, t.currency, t.locktime, t.lang, t.decimal_mark, t.date_format, t.time_format, t.week_start,
+ t.tracking_mode, t.record_type, t.plugins, t.lock_spec, t.custom_logo
FROM tt_users u LEFT JOIN tt_teams t ON (u.team_id = t.id) WHERE ";
if ($id)
$sql .= "u.id = $id";
$this->address = $val['address'];
$this->currency = $val['currency'];
$this->plugins = $val['plugins'];
+ $this->lock_spec = $val['lock_spec'];
$this->custom_logo = $val['custom_logo'];
$this->lock_interval = $val['locktime'];
// isDateLocked checks whether a specifc date is locked for modifications.
function isDateLocked($date)
{
- if ($this->isPluginEnabled('lk')) {
+ if ($this->isPluginEnabled('lk') && $this->lock_spec) {
+ // This is legacy code...
+ /*
// Determine lock date. Entries earlier than lock date cannot be created or modified.
$lockdate = 0;
if ($this->lock_interval > 0) {
}
if($lockdate && $date->before($lockdate))
return true;
+ */
+
+ // New code with cron specification.
+ require_once(LIBRARY_DIR.'/tdcron/class.tdcron.php');
+ require_once(LIBRARY_DIR.'/tdcron/class.tdcron.entry.php');
+
+ // Calculate the last occurrence of a lock.
+ $last = tdCron::getLastOccurrence($this->lock_spec, mktime());
+ $lockdate = new DateAndTime(DB_DATEFORMAT, strftime('%Y-%m-%d', $last));
+ if ($date->before($lockdate)) {
+ return true;
+ }
}
return false;
}
<br>
<table cellspacing="0" cellpadding="4" width="100%" border="0">
<tr>
- <td align="center"> Anuko Time Tracker 1.9.21.3467 | Copyright © <a href="https://www.anuko.com/lp/tt_3.htm" target="_blank">Anuko</a> |
+ <td align="center"> Anuko Time Tracker 1.9.22.3468 | Copyright © <a href="https://www.anuko.com/lp/tt_3.htm" target="_blank">Anuko</a> |
<a href="https://www.anuko.com/lp/tt_4.htm" target="_blank">{$i18n.footer.credits}</a> |
<a href="https://www.anuko.com/lp/tt_5.htm" target="_blank">{$i18n.footer.license}</a> |
<a href="https://www.anuko.com/lp/tt_7.htm" target="_blank">{$i18n.footer.improve}</a>
<td>
<table cellspacing="1" cellpadding="2" border="0">
<tr>
- <td align="right" nowrap>{$i18n.label.lock_interval}:</td>
- <td>{$forms.lockingForm.lock_interval.control}</td>
+ <td align="right">{$i18n.label.cron_schedule}:</td>
+ <td>{$forms.lockingForm.lock_spec.control} <a href="https://www.anuko.com/lp/tt_6.htm" target="_blank">{$i18n.label.what_is_it}</a></td>
</tr>
<tr>
<td colspan="2"> </td>
setChange("ALTER TABLE tt_invoices ADD COLUMN status tinyint(4) default '1'");
setChange("DROP INDEX name_idx on tt_invoices");
setChange("create unique index name_idx on tt_invoices(team_id, name, status)");
+ setChange("ALTER TABLE tt_teams ADD COLUMN lock_spec varchar(255) default NULL");
}
// The update_clients function updates projects field in tt_clients table.
exit();
}
-$cl_lock_interval = $request->isPost() ? $request->getParameter('lock_interval') : $user->lock_interval;
+$cl_lock_spec = $request->isPost() ? $request->getParameter('lock_spec') : $user->lock_spec;
$form = new Form('lockingForm');
-$form->addInput(array('type'=>'text','maxlength'=>'10','name'=>'lock_interval','value'=>$cl_lock_interval));
+$form->addInput(array('type'=>'text','maxlength'=>'100','name'=>'lock_spec','style'=>'width: 250px;','value'=>$cl_lock_spec));
$form->addInput(array('type'=>'submit','name'=>'btn_save','value'=>$i18n->getKey('button.save')));
if ($request->isPost()) {
- if ($cl_lock_interval == null || trim($cl_lock_interval) == '') $cl_lock_interval = 0;
+ // Validate user input.
+ if (!ttValidCronSpec($cl_lock_spec)) $err->add($i18n->getKey('error.field'), $i18n->getKey('label.cron_schedule'));
- if (ttTeamHelper::update($user->team_id, array(
- 'name' => $user->team,
- 'locktime' => $cl_lock_interval))) {
- header('Location: time.php');
- exit();
- } else {
- $err->add($i18n->getKey('error.db'));
+ if ($err->no()) {
+ if (ttTeamHelper::update($user->team_id, array(
+ 'name' => $user->team,
+ 'lock_spec' => $cl_lock_spec))) {
+ header('Location: time.php');
+ exit();
+ } else {
+ $err->add($i18n->getKey('error.db'));
+ }
}
} // isPost
`tracking_mode` smallint(2) NOT NULL DEFAULT '1', # tracking mode ("projects" or "projects and tasks")
`record_type` smallint(2) NOT NULL DEFAULT '0', # time record type ("start and finish", "duration", or both)
`plugins` varchar(255) default NULL, # a list of enabled plugins for team
+ `lock_spec` varchar(255) default NULL, # Cron specification for record locking,
+ # for example: "0 10 * * 1" for "weekly on Mon at 10:00".
`custom_logo` tinyint(4) default '0', # whether to use a custom logo or not
`status` tinyint(4) default '1', # team status
PRIMARY KEY (`id`)