/** * go through all accounts and collect information * * returns array of count of... [$num_notification_sent, $num_warnings] */ public static function sendNotifications() { global $PH; $people = Person::getPeople(array('visible_only' => false, 'can_login' => true)); $num_notifications_sent = 0; $num_warnings = 0; foreach ($people as $p) { if ($p->settings & USER_SETTING_NOTIFICATIONS) { if ($p->office_email || $p->personal_email) { $now = time(); $last = strToGMTime($p->notification_last); $period = $p->notification_period * 60 * 60 * 24; if (strToGMTime($p->notification_last) + $period < time() || $period == -1) { $email = new EmailNotification($p); if ($email->information_count) { $result = $email->send(); if ($result === true) { ### reset activation-flag ### $p->settings &= USER_SETTING_SEND_ACTIVATION ^ RIGHT_ALL; $p->notification_last = gmdate("Y-m-d H:i:s"); $p->update(); $num_notifications_sent++; } else { if ($result !== false) { $num_warnings++; new FeedbackWarning(sprintf(__('Failure sending mail: %s'), $result)); } } } } } } } return array($num_notifications_sent, $num_warnings); }
static function RateItem($item) { $rate = 1; $age = time() - strToGMTime($item->modified); if ($age < 24 * 60 * 60 * 20) { $rate *= RATE_MODIFIED_20_DAYS_AGO; } else { if ($age < 62 * 60 * 60 * 20) { $rate *= RATE_MODIFIED_2_MONTHS_AGO; } } if ($item->state != 1) { $rate *= $rate_deleted; } if ($item->project && ($project = Project::getById($item->project))) { if ($project->status == STATUS_TEMPLATE) { $rate *= RATE_PROJECT_IS_TEMPLATE; } else { if ($project->status <= STATUS_OPEN) { $rate *= RATE_PROJECT_IS_OPEN; } else { if ($project->status > STATUS_COMPLETED) { $rate *= RATE_PROJECT_IS_CLOSED; } } } } return $rate; }
/** * export selected efforts as a CSV ready for copy and paste into a spread-sheet @ingroup pages ** */ function effortShowAsCSV() { global $PH; global $g_effort_status_names; $effort_ids = getPassedIds('effort', 'efforts_*'); if (!$effort_ids) { $PH->abortWarning(__("Select some efforts(s) to show")); exit; } $efforts = array(); $different_fields = array(); $edit_fields = array('status', 'pub_level', 'task'); foreach ($effort_ids as $id) { if ($effort = Effort::getEditableById($id)) { $efforts[] = $effort; ### check project for first task if (count($efforts) == 1) { ### make sure all are of same project ### if (!($project = Project::getVisibleById($effort->project))) { $PH->abortWarning('could not get project'); } } else { if ($effort->project != $efforts[0]->project) { $PH->abortWarning(__("For editing all efforts must be of same project.")); } foreach ($edit_fields as $field_name) { if ($effort->{$field_name} != $efforts[0]->{$field_name}) { $different_fields[$field_name] = true; } } } } } $page = new Page(array('use_jscalendar' => true)); $page->cur_tab = 'projects'; $page->options[] = new naviOption(array('target_id' => 'effortEdit')); $page->type = __("Edit multiple efforts", "Page title"); $page->title = sprintf(__("%s efforts for copy and pasting into a spread-sheet", "Page title"), count($efforts)); echo new PageHeader(); echo new PageContentOpen(); $block = new PageBlock(array('id' => 'functions', 'reduced_header' => true)); $block->render_blockStart(); $format = "[Date][Weekday][Task][Comment][Duration]"; preg_match_all("/\\[(.*?)\\]/", $format, $matches); $overallDuration = 0; echo "<textarea style='width:96%; height:300px;'>"; echo join("\t", $matches[1]) . "\n"; foreach ($efforts as $e) { preg_match_all("/\\[(.*?)\\]/", $format, $matches); $separator = ""; foreach ($matches[1] as $matchedFormat) { echo $separator; switch ($matchedFormat) { case "Date": echo gmstrftime("%Y-%m-%d", strToGMTime($e->time_start)); break; case "Weekday": echo gmstrftime("%a", strToGMTime($e->time_start)); break; case "Task": if ($t = Task::getVisibleById($e->task)) { echo $t->name; } break; case "Comment": echo $e->name; break; case "Duration": $durationInMinutes = round((strToGMTime($e->time_end) - strToGMTime($e->time_start)) / 60, 0); $roundUpTo15 = ceil($durationInMinutes / 15) * 15 / 60; $overallDuration += $roundUpTo15; echo number_format($roundUpTo15, 2, $dec_point = ',', ''); break; } $separator = "\t"; } echo "\n"; } echo "</textarea>"; echo "<br>"; echo __("Overall Duration:") . $overallDuration . "h"; $block->render_blockEnd(); echo new PageContentClose(); echo new PageHtmlEnd(); exit; }
function render_tr(&$item, $style = "") { if ($ip = ItemPerson::getAll(array('item' => $item->id, 'notify_if_unchanged_min' => NOTIFY_1DAY))) { $period = ''; switch ($ip[0]->notify_if_unchanged) { case NOTIFY_1DAY: $period = 24 * 60 * 60; break; case NOTIFY_2DAYS: $period = 2 * 24 * 60 * 60; break; case NOTIFY_3DAYS: $period = 3 * 24 * 60 * 60; break; case NOTIFY_4DAYS: $period = 4 * 24 * 60 * 60; break; case NOTIFY_5DAYS: $period = 5 * 24 * 60 * 60; break; case NOTIFY_1WEEK: $period = 7 * 24 * 60 * 60; break; case NOTIFY_2WEEKS: $period = 2 * 7 * 24 * 60 * 60; break; case NOTIFY_3WEEKS: $period = 3 * 7 * 24 * 60 * 60; break; case NOTIFY_1MONTH: $period = 4 * 7 * 24 * 60 * 60; break; case NOTIFY_2MONTH: $period = 2 * 4 * 7 * 24 * 60 * 60; break; } $notify_date = $ip[0]->notify_date; if ($notify_date != '0000-00-00 00:00:00') { $send_date = strToGMTime($notify_date) + $period; $current_date = time(); if ($send_date > $current_date) { $days = round(($send_date - $current_date) / 60 / 60 / 24); print "<td>" . sprintf(__('in %s day(s)'), $days) . "</td>"; } else { $days = round(($current_date - $send_date) / 60 / 60 / 24); print "<td>" . sprintf(__('since %s day(s)'), $days) . "</td>"; } } else { print "<td> </td>"; } } else { print "<td> </td>"; } }
/** * records history events in rss/rss_$project->id.xml * * must be called from a project-related page! * * * @param project - current project object used in: proj.inc.php <- function call */ static function updateRSS($project) { global $PH; global $auth; if (!$project) { return NULL; } /** * only show changes by others */ if (Auth::isAnonymousUser()) { $not_modified_by = NULL; } else { $not_modified_by = $auth->cur_user->id; } ### get all the changes (array of history items) ## $changes = ChangeLine::getChangeLines(array('project' => $project->id, 'unviewed_only' => false, 'limit_rowcount' => 20, 'type' => array(ITEM_TASK, ITEM_FILE), 'limit_offset' => 0)); /* $changes= DbProjectItem::getAll(array( 'project' => $project->id, # query only this project history 'alive_only' => false, # get deleted entries 'visible_only' => false, # ignore user viewing rights 'limit_rowcount' => 20, # show only last 20 entries in rss feed #'show_assignments' => false, # ignore simple assignment events )); */ $url = confGet('SELF_PROTOCOL') . '://' . confGet('SELF_URL'); # url part of the link to the task $from_domain = confGet('SELF_DOMAIN'); # domain url if (confGet('USE_MOD_REWRITE')) { $url = str_replace('index.php', '', $url); } ### define general rss file settings ### $rss = new UniversalFeedCreator(); $rss->title = "StreberPM: " . $project->name; $rss->description = "Latest Project News"; $rss->link = "{$url}?go=projView&prj={$project->id}"; $rss->syndicationURL = $url; # go through all retrieved changes and create rss feed foreach ($changes as $ch) { $item = $ch->item; $name_author = __('???'); if ($person = Person::getVisibleById($item->modified_by)) { $name_author = $person->name; } $str_updated = ''; if ($new = $ch->item->isChangedForUser()) { if ($new == 1) { $str_updated = __('New'); } else { $str_updated = __('Updated'); } } $feeditem = new FeedItem(); $feeditem->title = $item->name . " (" . $ch->txt_what . ' ' . __("by") . ' ' . $name_author . ")"; $feeditem->link = $url . "?go=itemView&item={$item->id}"; $feeditem->date = gmdate("r", strToGMTime($item->modified)); $feeditem->source = $url; $feeditem->author = $name_author; switch ($ch->type) { case ChangeLine::COMMENTED: $feeditem->description = $ch->html_details; break; case ChangeLine::NEW_TASK: $feeditem->description = str_replace("\n", "<br>", $item->description); break; default: $feeditem->description = $ch->type . " " . str_replace("\n", "<br>", $item->description); break; } $rss->addItem($feeditem); } /** * all history items processed ... * save the rss 2.0 feed to rss/rss_$project->id.xml ... * false stands for not showing the resulting feed file -> create in background */ $rss->saveFeed("RSS2.0", "_rss/proj_{$project->id}.xml", false); }
function validateEditRequestTime($abort_on_failure = true) { global $PH; global $auth; if (!($edit_request_time = get('edit_request_time'))) { if ($abort_on_failure) { $PH->abortWarning("undefined edit request time", ERROR_BUG); exit; } else { return NULL; } } $last_modified = strToGMTime($this->modified); if ($edit_request_time < $last_modified) { if ($this->modified_by != $auth->cur_user->id) { if ($abort_on_failure) { require_once confGet('DIR_STREBER') . 'db/class_person.inc.php'; if ($person = Person::getVisibleById($this->modified_by)) { $link_person = $person->getLink(); } else { $link_person = __('Unknown'); } $time_ago = floor((time() - $last_modified) / 60) + 1; $PH->abortWarning(sprintf(__("Item has been modified during your editing by %s (%s minutes ago). Your changes can not be submitted."), $link_person, $time_ago), ERROR_NOTE); } else { return NULL; } } } return true; }
function render_tr(&$obj, $style = "") { if (!isset($obj) || !$obj instanceof Effort) { trigger_error("ListBlock->render_tr() called without valid object", E_USER_WARNING); return; } $value = round((strToGMTime($obj->time_end) - strToGMTime($obj->time_start)) / 60 / 60, 1) . "h"; print "<td>{$value}</td>"; }
function newEffortFromTimeTracking() { global $PH; global $auth; require_once confGet('DIR_STREBER') . 'db/class_effort.inc.php'; $time_end = intval(get('effort_end_seconds')); if ($time_end == 0) { $time_end = null; } $new_effort = new Effort(array('id' => 0, 'time_start' => getGMTString(get('effort_start_seconds')), 'time_end' => getGMTString($time_end), 'name' => get('description'), 'billing' => get('billing'), 'productivity' => get('productivity'))); ### get project ### $new_effort->project = get('effort_project_id'); if (!($project = Project::getVisibleById($new_effort->project))) { $PH->abortWarning(__("Could not get project of effort")); } if (!$project->isPersonVisibleTeamMember($auth->cur_user)) { $PH->abortWarning("ERROR: Insufficient rights"); } ### link to task ### $task_id = get('effort_task_id'); if (!(is_null($task_id) || $task_id == 0)) { if ($task_id == 0) { $new_effort->task = 0; } else { if ($task = Task::getVisibleById($task_id)) { $new_effort->task = $task->id; } } } else { if (get('task_name') != "") { ### create new task $newtask = new Task(array('id' => 0, 'name' => get('task_name'), 'project' => $project->id)); $newtask->insert(); $new_effort->task = $newtask->id; } } ### get person ### $new_effort->person = $auth->cur_user->id; ### go back to from if validation fails ### $failure = false; if (strToGMTime($new_effort->time_end) - strToGMTime($new_effort->time_start) < 0) { $failure = true; new FeedbackWarning(__("Cannot start before end.")); } ### write to db ### $new_effort->insert(); ### display taskView #### if (!$PH->showFromPage()) { $PH->show('projView', array('prj' => $effort->project)); } }
/** * get Open Efforts sum * sums up open and new efforts (e.I. everything that's not closed, balanced or not billable) */ function getOpenEffortsSum() { $sum = 0.0; require_once confGet('DIR_STREBER') . 'db/class_effort.inc.php'; $efforts = Effort::getAll(array('project' => $this->id, 'effort_status_max' => EFFORT_STATUS_OPEN)); foreach ($efforts as $e) { $sum += 1.0 * strToGMTime($e->time_end) - 1.0 * strToGMTime($e->time_start); } return $sum; }
private function addUntouchedMonitoredItems() { $unchanged_headline_html = ''; $unchanged_headline_txt = ''; $unchanged_body_html = ''; $unchanged_body_plaintext = ''; $monitored_items_unchanged = ItemPerson::getAll(array('is_bookmark' => 1, 'notify_if_unchanged_min' => NOTIFY_1DAY, 'person' => $this->recipient->id)); if (!$monitored_items_unchanged) { return; } foreach ($monitored_items_unchanged as $miu) { ## reminder period ## $period = ''; switch ($miu->notify_if_unchanged) { case NOTIFY_1DAY: $period = 24 * 60 * 60; break; case NOTIFY_2DAYS: $period = 2 * 24 * 60 * 60; break; case NOTIFY_3DAYS: $period = 3 * 24 * 60 * 60; break; case NOTIFY_4DAYS: $period = 4 * 24 * 60 * 60; break; case NOTIFY_5DAYS: $period = 5 * 24 * 60 * 60; break; case NOTIFY_1WEEK: $period = 7 * 24 * 60 * 60; break; case NOTIFY_2WEEKS: $period = 2 * 7 * 24 * 60 * 60; break; case NOTIFY_3WEEKS: $period = 3 * 7 * 24 * 60 * 60; break; case NOTIFY_1MONTH: $period = 4 * 7 * 24 * 60 * 60; break; case NOTIFY_2MONTH: $period = 2 * 4 * 7 * 24 * 60 * 60; break; } $date = $miu->notify_date; if ($pi = DbProjectItem::getVisibleById($miu->item)) { $mod_date = $pi->modified; if ($date != '0000-00-00 00:00:00') { $date = strToGMTime($date) + $period; $date = date('Y-m-d H:i:s', $date); if ($date >= $mod_date && strToGMTime($date) <= time()) { $diff = strToGMTime($date) - strToGMTime($mod_date); if ($diff >= $period) { ### diff in days ### $information_count++; $days = round((time() - strToGMTime($miu->notify_date)) / 60 / 60 / 24); $object = DbProjectItem::getObjectById($pi->id); $unchanged_body_html .= '<li>' . sprintf(__("%s (not touched since %s day(s))"), asHtml($object->name), $days) . '</li>'; $unchanged_body_plaintext .= '- ' . sprintf(__("%s (not touched since %s day(s))"), $object->name, $days) . '\\n\\r'; } } } } } if ($unchanged_body_html) { $this->information_count++; $this->body_html .= "<h3>" . __('Unchanged monitored items:', 'notification') . "</h3>" . "<ul>" . $unchanged_body_html . "</ul>"; $this->body_plaintext .= "\n\r" . __('Unchanged monitored items:', 'notification') . "\n\r" . $unchanged_body_plaintext; } }
/** * converts a time string like 2005-05-02 23:23:32 from the client's timezone to database GMT-String */ function clientTimeStrToGMTString($str) { global $auth; $time_offset = 0; if (isset($auth->cur_user)) { $time_offset = $auth->cur_user->time_offset; } return getGMTString(strToGMTime($str) - $time_offset - confGet('SERVER_TIME_OFFSET')); }
/** * renders a time as distance ago... (expects GMT times) */ function renderTimeAgo($t) { $duration = time() - strToGMTime($t); if (strToGMTime($t) == 0) { return __("never"); } if ($duration < 60 * 5) { return __('just now'); } if ($duration < 60 * 60) { return sprintf(__('%smin ago'), ceil($duration / 60)); } if ($duration < 60 * 60 * 2) { return __('1 hour ago'); } if ($duration < 60 * 60 * 24) { return sprintf(__('%sh ago'), ceil($duration / 60 / 60)); } if ($duration < 60 * 60 * 24 * 62) { return sprintf(__('%s days ago'), ceil($duration / 60 / 60 / 24)); } if ($duration < 60 * 60 * 24 * 365 * 2) { return sprintf(__('%s months ago'), ceil($duration / 60 / 60 / 24 / 30)); } if ($duration < 60 * 60 * 24 * 365 * 20) { return sprintf(__('%s years ago'), ceil($duration / 60 / 60 / 24 / 365)); } }
function render_tr(&$obj, $style = "") { measure_start('col_timedue'); $class = ""; $title = "planned end undefined."; $value = ""; if ($obj->planned_end && $obj->planned_end != '0000-00-00' && $obj->planned_end != '0000-00-00 00:00:00') { if ($obj->status >= STATUS_COMPLETED) { if ($obj->status == STATUS_COMPLETED) { $value = __("Review"); $title = __("Task status set to completed and needs approval."); } else { $title = sprintf(__("Item was approved on: %s:", "date a task was approved"), renderDate($obj->date_closed)); $value = __("done"); } } else { $daysLeft = floor((strToGMTime($obj->planned_end) - time()) / 24 / 60 / 60); switch ($daysLeft) { case 0: $value = __("Today"); $title = __("This task is planned to be completed today."); break; case 1: $value = __("Tomorrow"); $title = __("This task is planned to be completed tomorrow."); break; case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: $value = __("Next week"); $title = sprintf(__("due: %s"), renderDate($obj->planned_end)); break; default: $value = abs($daysLeft) . " <span class='entity'>" . __("days"); if ($daysLeft < 0) { $class = "overDue"; $title = __("this task is overdue!"); $value .= __("late", "time status of a task"); } else { $value .= __("remain", "time status of a task"); if ($obj->planned_start && $obj->planned_start != '0000-00-00' && $obj->planned_start != '0000-00-00 00:00:00') { if (floor((strToGMTime($obj->planned_start) - time()) / 24 / 60 / 60) + 1 >= 1) { $value = __("Pending"); $title = sprintf(__("planned for %s", "a certain date"), renderTimestamp($obj->planned_start)); } else { $title = sprintf(__("start: %s"), renderDate($obj->planned_start)) . " / " . sprintf(__("due: %s"), renderDate($obj->planned_end)); } } else { $title = sprintf(__("due: %s"), renderDate($obj->planned_end)); } } break; } } $value .= "</span>"; print "<td class='timeDue {$class}' title='{$title}'>{$value}</td>"; measure_stop('col_timedue'); } else { print "<td></td>"; } }
function render_tr(&$task, $style = "") { global $PH; if (!isset($task) || !is_object($task)) { trigger_error("ListBlock->render_tr() called without valid object", E_USER_WARNING); return; } ### days left ### $due_str = $task->planned_end; $html_due = ''; if ($due_str == "0000-00-00" || $due_str == "0000-00-00 00:00:00") { $html_due = ''; } else { $due_days = floor((strToGMTime($task->planned_end) - time()) / 24 / 60 / 60) + 1; if ($due_days == 0) { $html_due = __("Due Today"); } else { if ($due_days < 0) { $class = 'overDue'; $html_due = '<span class=overdue>' . sprintf(__("%s days late"), -$due_days) . '</span>'; } else { $html_due = sprintf(__("%s days left"), $due_days); } } } $buffer = renderDateHtml($task->planned_end); if ($html_due && $task->status < STATUS_CLOSED) { $buffer .= '<br><span class=sub>(' . $html_due . ')</span>'; } if ($this->parent_block->sum_estimated_max) { $buffer .= '<br><span class=sub>' . sprintf(__('%s required'), renderEstimatedDuration(($this->parent_block->sum_estimated_max + $this->parent_block->sum_estimated_min) / 2 - ($this->parent_block->sum_completion_max + $this->parent_block->sum_completion_min) / 2)) . '</span>'; } echo '<td class=nowrap>' . $buffer . '</td>'; }
/** * Submit changes to an effort @ingroup pages */ function effortEditSubmit() { global $PH; global $auth; ### Validate form crc if (!validateFormCrc()) { $PH->abortWarning(__('Invalid checksum for hidden form elements')); } ### get effort #### $id = getOnePassedId('effort'); if ($id == 0) { $effort = new Effort(array('id' => 0)); } else { $effort = Effort::getEditableById($id); if (!$effort) { $PH->abortWarning(__("Could not get effort")); return; } $effort->validateEditRequestTime(); } ### cancel ### if (get('form_do_cancel')) { if (!$PH->showFromPage()) { $PH->show('projView', array('prj' => $effort->project)); } exit; } ### get project ### $effort->project = get('effort_project'); if (!($project = Project::getVisibleById($effort->project))) { $PH->abortWarning(__("Could not get project of effort")); } if (!$project->isPersonVisibleTeamMember($auth->cur_user)) { $PH->abortWarning("ERROR: Insufficient rights"); } ### get person ### if ($effort->person = get('effort_person')) { if (!($person = Person::getVisibleById($effort->person))) { $PH->abortWarning(__("Could not get person of effort")); } } # retrieve all possible values from post-data # NOTE: # - this could be an security-issue. # - TODO: as some kind of form-edit-behaviour to field-definition foreach ($effort->fields as $f) { $name = $f->name; $f->parseForm($effort); } ### times as duration ### if ($as_duration = get('effort_as_duration')) { $effort->as_duration = $as_duration; ### make sure day of time_end stays the same if date changes... ### if (($time_start = $effort->time_start) && ($time_end = $effort->time_end)) { $effort->time_end = gmdate("Y-m-d", strToClientTime($time_end)) . " " . gmdate("H:i:s", strToClientTime($time_end)); $effort->time_start = gmdate("Y-m-d", strToClientTime($time_end)) . " " . gmdate("00:00:00", strToClientTime($time_end)); } else { trigger_error("Getting time_start and time_end failed", E_USER_WARNING); } } ### pub level ### if ($pub_level = get('effort_pub_level')) { ### not a new effort ### if ($effort->id) { if ($pub_level > $effort->getValidUserSetPublicLevels()) { $PH->abortWarning('invalid data', ERROR_RIGHTS); } } #else { # #@@@ check for person create rights #} $effort->pub_level = $pub_level; } ## effort status ## if ($effort_status = get('effort_status')) { $effort->status = $effort_status; } if ($effort_billing = get('effort_billing')) { $effort->billing = intval($effort_billing); } if ($effort_productivity = get('effort_productivity')) { $effort->productivity = intval($effort_productivity); } ### link to task ### $task_id = get('effort_task'); if (!is_null($task_id)) { if ($task_id == 0) { $effort->task = 0; } else { if ($task = Task::getVisibleById($task_id)) { $effort->task = $task->id; } } } ### go back to from if validation fails ### $failure = false; if (!$effort->name) { $failure = true; new FeedbackWarning(__("Name required")); } if (strToGMTime($effort->time_end) - strToGMTime($effort->time_start) < 0) { $failure = true; new FeedbackWarning(__("Cannot start before end.")); } ### validation of the Datetime fields### if (!$as_duration) { if (strToGMTime($effort->time_start) == 0) { $failure = true; $name = $effort->fields['time_start']->name; $field_id = $effort->_type . '_' . $name; $value_time = get($field_id . '_time'); new FeedbackWarning(sprintf(__("<b>%s</b> is not a valid value for start time."), $value_time)); $effort->time_start = getGMTString(); } if (strToGMTime($effort->time_end) == 0) { $failure = true; $name = $effort->fields['time_end']->name; $field_id = $effort->_type . '_' . $name; $value_time = get($field_id . '_time'); new FeedbackWarning(sprintf(__("<b>%s</b> is not a valid value for end time."), $value_time)); $effort->time_end = getGMTString(); } } else { ##As duration if (strToGMTime($effort->time_end) == 0) { $failure = true; $name = $effort->fields['time_end']->name; $field_id = $effort->_type . '_' . $name; $value_time = get($field_id . '_time'); new FeedbackWarning(sprintf(__("<b>%s</b> is not a valid value for hours."), $value_time)); $effort->time_end = gmdate("Y-m-d", time()) . " 00:00:00"; } } if ($failure) { $PH->show('effortEdit', NULL, $effort); exit; } ### write to db ### if ($effort->id == 0) { $effort->insert(); } else { $effort->update(); } ### display taskView #### if (!$PH->showFromPage()) { $PH->show('projView', array('prj' => $effort->project)); } }