<?php /* -*- mode: php; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ include_once($UTIL_DIR . "/error.php"); include_once($UTIL_DIR . "/notify.php"); function xmlenc($message) { return htmlspecialchars($message, ENT_QUOTES, "UTF-8"); } function userList($uid) { global $users; $str = ""; $str .= "<select name=\"userid\">\n"; foreach($users->users as $user) { if($user->enabled && $user->uid != 0) { $str .= "<option value=\"".$user->uid."\""; if($user->uid == $uid) $str .= " selected"; $str .= ">".$user->name."</option>\n"; } } $str .= "</select>"; return $str; } class Task { public $id; public $title; public $deadline; public $description; public $lastreminder; public $reassignable; public $userid; public $completed; public function write($fp) { fwrite($fp, " <task id=\"" .xmlenc($this->id) . "\"\n"); fwrite($fp, " title=\"" .xmlenc($this->title) . "\"\n"); fwrite($fp, " deadline=\"" . xmlenc($this->deadline) . "\"\n"); fwrite($fp, " userid=\"" . xmlenc($this->userid) . "\"\n"); if($this->reassignable) fwrite($fp, " reassignable=\"true\"\n"); else fwrite($fp, " reassignable=\"false\"\n"); if($this->completed) fwrite($fp, " completed=\"true\"\n"); else fwrite($fp, " completed=\"false\"\n"); fwrite($fp, " lastreminder=\"" . xmlenc($this->lastreminder) . "\">\n"); fwrite($fp, " <description>".xmlenc($this->description)."</description>\n"); if($this->refs) $this->refs->write($fp, " "); fwrite($fp, " </task>\n"); } public function show() { global $users, $current_user; $str .= " <tr>\n"; $str .= " <form method=\"post\" enctype=\"multipart/form-data\" ". "action=\"?mode=tasks&action=update\">\n"; $str .= " <input type=\"hidden\" name=\"id\" value=\"".$this->id."\"/>\n"; if($this->userid == $current_user->uid) { $str .= " <td>Done<input name=\"completed\" type=\"checkbox\""; if($this->completed) $str .= " checked"; $str .= "/></td>\n"; } else { if($this->completed) $str .= " <td>Done ☑</td>\n"; else $str .= " <td>Done ☐</td>\n"; } $str .= " <td><strong>".$this->title."</strong></td>\n"; if(strlen($this->description) > 64) $str .= " <td>".substr($this->description, 0, 64)."...</td>\n"; else $str .= " <td>".$this->description."</td>\n"; if($this->reassignable && $this->userid == $current_user->uid) { $str .= " <td>".userList($this->userid)."</td>\n"; } else { $str .= " <td><em>".$users->getUser($this->userid)->name."</em></td>\n"; } $str .= " <td>Deadline ".date("j/n-Y", $this->deadline)."</td>\n"; $str .= " <td height=\"24px;\">"; if($this->userid == $current_user->uid) $str .= "<input type=\"submit\" value=\"set\"/>"; $str .= "</td>\n"; $str .= " </form>\n"; $str .= " </tr>\n"; return $str; } public function mailTextSubject() { return $this->title . " - deadline: ".date("j/n-Y", $this->deadline); } public function mailTextBody() { return $this->title . "\n\n" . $this->description . "\n\nDeadline: ".date("j/n-Y", $this->deadline); } public function Task($id, $title, $deadline, $description, $lastreminder, $reassignable, $userid, $completed) { $this->id = $id; $this->title = $title; $this->deadline = $deadline; $this->description = $description; $this->lastreminder = $lastreminder; $this->reassignable = $reassignable; $this->userid = $userid; $this->completed = $completed; } } class Tasks { private $file; public $tasks = array(); public function show() { $str = "<table>\n"; foreach($this->tasks as $task) { if($task->completed == false) { $str .= $task->show(); } } $str .= "</table>\n"; $str .= "<hr/>\n"; $str .= "<table>\n"; foreach($this->tasks as $task) { if($task->completed == true) { $str .= $task->show(); } } $str .= "</table>\n"; return $str; } public function add($task) { $this->tasks[$task->id] = $task; } public function getNextID() { $id = 0; foreach($this->tasks as $task) { if($task->id > $id) $id = $task->id; } return $id + 1; } public function write() { $fp = fopen($this->file, "w"); fwrite($fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); fwrite($fp, "<tasks>\n"); foreach($this->tasks as $task) { $task->write($fp); } fwrite($fp, "</tasks>\n"); fclose($fp); } private function read() { $dom = new DomDocument; $dom->preserveWhiteSpace = FALSE; $dom->load($this->file); $params = $dom->getElementsByTagName('task'); foreach($params as $param) { $description = ""; $dess = $param->getElementsByTagName('description'); foreach($dess as $des) { $description = $des->textContent; } $task = new Task($param->getAttribute('id'), $param->getAttribute('title'), $param->getAttribute('deadline'), $description, $param->getAttribute('lastreminder'), $param->getAttribute('reassignable') == "true", $param->getAttribute('userid'), $param->getAttribute('completed') == "true"); $this->add($task); } } public function Tasks($file) { $this->file = $file; if(file_exists($file)) $this->read(); } } function tasks_init() { global $DATA_DIR; return new Tasks($DATA_DIR . "/tasks.xml"); } function sendMail($id, $new, $reassigned) { global $tasks, $users; $task = $tasks->tasks[$id]; $task->lastreminder = time(); $tasks->write(); $user = $users->getUser($task->userid); $prefix = "Task Reminder - "; if($new) $prefix = "New Task - "; if($reassigned) $prefix = "Reassigned Task - "; $email = $user->email; $subject = $prefix . $task->mailTextSubject(); $body = $task->mailTextBody(); send($email, $subject, $body); } $tasks = tasks_init(); if($action == "tick") { $now = time(); $h = (60 * 60); $d = ($h * 24); $mininterval = $d - $h * 4; $maxinterval = $d * 7 - $h * 4; $overdueinterval = $h * 7; foreach($tasks->tasks as $task) { if($task->completed) continue; // no need for reminding if(($now > $task->deadline) && (($now - $task->lastreminder) > $overdueinterval)) { // Deadline is overdue, and it has been more than $overdueinterval since last reminder. sendMail($task->id, false, false); } elseif((($task->deadline - $now) > $maxinterval) && (($now - $task->lastreminder) > $maxinterval)) { // Deadline is a long way off, but it has been $maxinterval since last reminder. sendMail($task->id, false, false); } elseif((($task->deadline - $now) > $mininterval) && (($now - $task->lastreminder) > $mininterval)) { // Deadline is near, and it has been $mininterval since last reminder. sendMail($task->id, false, false); } } } if($action == "update") { $reassigned = false; $id = $GLOBALS['id']; $task = $tasks->tasks[$id]; if(isset($GLOBALS['completed'])) $task->completed = $GLOBALS['completed'] == "on"; if(isset($GLOBALS['userid'])) { $reassigned = $task->userid != $GLOBALS['userid']; $task->userid = $GLOBALS['userid']; } $tasks->write(); if($reassigned) sendMail($id, false, true); } if($action == "add") { $deadline = strtotime($GLOBALS['deadline_year']."-". $GLOBALS['deadline_month']."-". $GLOBALS['deadline_day']); $task = new Task($tasks->getNextID(), stripslashes($GLOBALS['title']), $deadline, stripslashes($GLOBALS['description']), 0, $GLOBALS['reassignable'] == "on", $GLOBALS['userid'], false); $tasks->add($task); $tasks->write(); sendMail($task->id, true, false); } ?> <form method="post" enctype="multipart/form-data" action="?mode=tasks&action=add"> Title: <input name="title" value=""> - User: <?php echo userList($current_user->uid); ?> - Deadline: D<input placeholder="day" name="deadline_day" style="width: 2em" value=""> M<input placeholder="month" name="deadline_month" style="width: 2em" value=""> Y<input placeholder="year" name="deadline_year" style="width: 4em" value=""><br/> Reassignable: <input name="reassignable" type="checkbox" checked><br/> <textarea name="description" cols="80" rows="2"></textarea><br/> <button style="width: 120px" type="submit">Add Task</button> </form> <hr/> <?php echo $tasks->show(); ?>