From 2df191e31bee1cdbdddde263805ec2342c7374e5 Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Tue, 26 Jul 2016 08:36:49 -0600 Subject: [PATCH 001/391] Adding overdue issues to "due alert" emails --- app/helper/notification.php | 12 +++-- app/model/user.php | 7 +-- app/view/notification/user_due_issues.html | 61 +++++++++++++++------- app/view/notification/user_due_issues.txt | 12 ++++- 4 files changed, 65 insertions(+), 27 deletions(-) diff --git a/app/helper/notification.php b/app/helper/notification.php index 87bc3039..15cd2bec 100644 --- a/app/helper/notification.php +++ b/app/helper/notification.php @@ -274,15 +274,17 @@ public function user_reset($user_id) { } /** - * Send a user an email listing the issues due today - * @param ModelUser $user - * @param array $issues + * Send a user an email listing the issues due today and any overdue issues + * @param \Model\User $user + * @param array $due + * @param array $overdue * @return bool */ - public function user_due_issues(\Model\User $user, array $issues) { + public function user_due_issues(\Model\User $user, array $due, array $overdue) { $f3 = \Base::instance(); if($f3->get("mail.from")) { - $f3->set("issues", $issues); + $f3->set("due", $due); + $f3->set("overdue", $overdue); $subject = "Due Today - " . $f3->get("site.name"); $text = $this->_render("notification/user_due_issues.txt"); $body = $this->_render("notification/user_due_issues.html"); diff --git a/app/model/user.php b/app/model/user.php index e0d9ffbf..42c4ee43 100644 --- a/app/model/user.php +++ b/app/model/user.php @@ -174,11 +174,12 @@ public function sendDueAlert($date = '') { // Find issues assigned to user or user's group $issue = new Issue; - $issues = $issue->find(array("due_date = ? AND owner_id IN($ownerStr) AND closed_date IS NULL AND deleted_date IS NULL", $date), array("order" => "priority DESC")); + $due = $issue->find(array("due_date = ? AND owner_id IN($ownerStr) AND closed_date IS NULL AND deleted_date IS NULL", $date), array("order" => "priority DESC")); + $overdue = $issue->find(array("due_date < ? AND owner_id IN($ownerStr) AND closed_date IS NULL AND deleted_date IS NULL", $date), array("order" => "priority DESC")); - if($issues) { + if($due || $overdue) { $notif = new \Helper\Notification; - return $notif->user_due_issues($this, $issues); + return $notif->user_due_issues($this, $due, $overdue); } else { return false; } diff --git a/app/view/notification/user_due_issues.html b/app/view/notification/user_due_issues.html index 166b6b25..0a44657a 100644 --- a/app/view/notification/user_due_issues.html +++ b/app/view/notification/user_due_issues.html @@ -42,24 +42,49 @@ - - - - - - - - - - + + + + + Due today:
+ + + + + + + +
+ + + + + Overdue:
+ + + + + + + +
diff --git a/app/view/notification/user_due_issues.txt b/app/view/notification/user_due_issues.txt index 22b06e4e..d399c1fc 100644 --- a/app/view/notification/user_due_issues.txt +++ b/app/view/notification/user_due_issues.txt @@ -1,7 +1,17 @@ {{ @site.name }} + Issues due today: - + #{{ @issue.id }}: {{ @issue.name }} - {{ @site.url }}issues/{{ @issue.id }} + + + +Overdue issues: + + + #{{ @issue.id }}: {{ @issue.name }} - {{ @site.url }}issues/{{ @issue.id }} - Due {{ date("D, M j, Y", strtotime(@issue.due_date)) }} + + From e11620377b71942f6d198414ea461ba488f0546a Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Tue, 26 Jul 2016 08:42:37 -0600 Subject: [PATCH 002/391] Adding user setting to disable due issue emails --- app/controller/user.php | 1 + app/dict/en.ini | 1 + app/view/user/account.html | 6 ++++++ cron/due_alerts.php | 3 +++ 4 files changed, 11 insertions(+) diff --git a/app/controller/user.php b/app/controller/user.php index a7987e91..66ddf6be 100644 --- a/app/controller/user.php +++ b/app/controller/user.php @@ -159,6 +159,7 @@ public function save($f3) { // Update option values $user->option("disable_mde", !empty($post["disable_mde"])); + $user->option("disable_due_alerts", !empty($post["disable_due_alerts"])); } else { diff --git a/app/dict/en.ini b/app/dict/en.ini index b1c6e174..f60c3dfd 100644 --- a/app/dict/en.ini +++ b/app/dict/en.ini @@ -105,6 +105,7 @@ profile=Profile settings=Settings default=Default disable_editor=Disable Editor +disable_due_alerts=Disable Due Issue Emails ; Browse general=General diff --git a/app/view/user/account.html b/app/view/user/account.html index 0df84c30..77ca2b06 100644 --- a/app/view/user/account.html +++ b/app/view/user/account.html @@ -105,6 +105,12 @@ {{ @dict.disable_editor }} +
+ +
diff --git a/cron/due_alerts.php b/cron/due_alerts.php index 13fc40b7..33a78537 100644 --- a/cron/due_alerts.php +++ b/cron/due_alerts.php @@ -10,5 +10,8 @@ $users = $user->getAll(); foreach($users as $u) { + if($u->option('disable_due_alerts')) { + continue; + } $u->sendDueAlert(); } From b58dd951a30925dfc58579f266b6fdda6b0a8921 Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Mon, 1 Aug 2016 16:36:22 -0600 Subject: [PATCH 003/391] Fixing that stupid taskboard ID bug that's stupid --- js/taskboard.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/taskboard.js b/js/taskboard.js index 383c404e..7dcfda82 100644 --- a/js/taskboard.js +++ b/js/taskboard.js @@ -309,10 +309,10 @@ var Taskboard = { type: 'POST', url: Taskboard.addURL, data: data, - success: function() { + success: function(result) { Taskboard.newUnBlock(taskId); - $(card).find('.task-id').html('' + data.taskId + ''); - $(card).attr('id', 'task_' + data.taskId); + $(card).find('.task-id').html('' + result.id + ''); + $(card).attr('id', 'task_' + result.id); Taskboard.makeDraggable(card); }, error: function() { From c015eaab574977a10dd59253fb4395b88f8cc6d0 Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Tue, 2 Aug 2016 15:36:34 -0600 Subject: [PATCH 004/391] Use full site URL in issue ID links This fixes the links if they're generated in email notifications --- app/helper/view.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/helper/view.php b/app/helper/view.php index af6b5721..013dd67f 100644 --- a/app/helper/view.php +++ b/app/helper/view.php @@ -83,7 +83,7 @@ public function parseText($str, $options = array(), $ttl = null) { * @return string */ protected function _parseIds($str) { - $base = \Base::instance()->get("BASE"); + $url = \Base::instance()->get("site.url"); // Find all IDs $count = preg_match_all("/(?<=[^a-z\\/&]#|^#)[0-9]+(?=[^a-z\\/]|$)/i", $str, $matches); @@ -100,7 +100,7 @@ protected function _parseIds($str) { $issue = new \Model\Issue; $issues = $issue->find(array("id IN ($idsStr)")); - return preg_replace_callback("/(?<=[^a-z\\/&]|^)#[0-9]+(?=[^a-z\\/]|$)/i", function($matches) use($base, $issues) { + return preg_replace_callback("/(?<=[^a-z\\/&]|^)#[0-9]+(?=[^a-z\\/]|$)/i", function($matches) use($url, $issues) { $id = ltrim($matches[0], "#"); foreach($issues as $i) { if($i->id == $id) { @@ -111,14 +111,14 @@ protected function _parseIds($str) { if($issue->deleted_date) { $f3 = \Base::instance(); if($f3->get("user.role") == "admin" || $f3->get("user.rank") >= \Model\User::RANK_MANAGER || $f3->get("user.id") == $issue->author_id) { - return "#$id – " . htmlspecialchars($issue->name) . ""; + return "#$id – " . htmlspecialchars($issue->name) . ""; } else { return "#$id"; } } - return "#$id – " . htmlspecialchars($issue->name) . ""; + return "#$id – " . htmlspecialchars($issue->name) . ""; } - return "#$id"; + return "#$id"; }, $str); } From dab9abab7f2b9236925bdf34907d91a78cdabfc9 Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Wed, 3 Aug 2016 15:00:47 -0600 Subject: [PATCH 005/391] Don't keep all hours on copied issues: Fixes #236 --- app/model/issue.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/model/issue.php b/app/model/issue.php index b8c2cc96..6397a5ca 100644 --- a/app/model/issue.php +++ b/app/model/issue.php @@ -412,11 +412,12 @@ function duplicate($recursive = true) { $this->copyto("duplicating_issue"); $f3->clear("duplicating_issue.id"); $f3->clear("duplicating_issue.due_date"); + $f3->clear("duplicating_issue.hours_spent"); $new_issue = new Issue; $new_issue->copyfrom("duplicating_issue"); - $new_issue->clear("due_date"); $new_issue->author_id = $f3->get("user.id"); + $new_issue->hours_remaining = $new_issue->hours_total; $new_issue->created_date = date("Y-m-d H:i:s"); $new_issue->save(); @@ -445,13 +446,13 @@ protected function _duplicateTree($id, $new_id) { $child->copyto("duplicating_issue"); $f3->clear("duplicating_issue.id"); $f3->clear("duplicating_issue.due_date"); + $f3->clear("duplicating_issue.hours_spent"); $new_child = new Issue; $new_child->copyfrom("duplicating_issue"); - $new_child->clear("id"); - $new_child->clear("due_date"); $new_child->author_id = $f3->get("user.id"); - $new_child->set("parent_id", $new_id); + $new_child->hours_remaining = $new_child->hours_total; + $new_child->parent_id = $new_id; $new_child->created_date = date("Y-m-d H:i:s"); $new_child->save(false); From a26f1db75b00a102919e366ff23d98a058aa0ae8 Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Wed, 3 Aug 2016 15:26:30 -0600 Subject: [PATCH 006/391] Lots of fixes to repeat_cycle on taskboard This should fix #221 --- app/controller/taskboard.php | 6 +++--- js/taskboard.js | 13 +++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/app/controller/taskboard.php b/app/controller/taskboard.php index e3da0bb7..713baf7f 100644 --- a/app/controller/taskboard.php +++ b/app/controller/taskboard.php @@ -395,7 +395,7 @@ public function edit($f3) { if(!empty($post["hours_spent"]) && !empty($post["burndown"])) { $issue->hours_remaining -= $post["hours_spent"]; } - if($issue->hours_remaining < 0) { + if(!$issue->hours_remaining || $issue->hours_remaining < 0) { $issue->hours_remaining = 0; } if(!empty($post["dueDate"])) { @@ -403,8 +403,8 @@ public function edit($f3) { } else { $issue->due_date = null; } - if(!empty($post["repeat_cycle"])) { - $issue->repeat_cycle = $post["repeat_cycle"]; + if(isset($post["repeat_cycle"])) { + $issue->repeat_cycle = $post["repeat_cycle"] ?: null; } $issue->priority = $post["priority"]; if(!empty($post["storyId"])) { diff --git a/js/taskboard.js b/js/taskboard.js index 7dcfda82..bf55e53a 100644 --- a/js/taskboard.js +++ b/js/taskboard.js @@ -127,6 +127,18 @@ var Taskboard = { priority = $(data).find('.priority').data('val'), repeatCycle = $(data).find('.repeat_cycle').text(); + console.log({ +user: user, +userColor: userColor, +taskId: taskId, +title: title, +description: description, +hours: hours, +date: date, +priority: priority, +repeatCycle: repeatCycle, + }); + $('#task-dialog input#taskId').val(taskId); $('#task-dialog input#title').val(title); $('#task-dialog textarea#description').val(description); @@ -192,6 +204,7 @@ var Taskboard = { }, updateCard: function(card, data) { $(card).find('.title').text(data.title); + $(card).find('.repeat_cycle').text(data.repeat_cycle); if (isNumber(data.hours_spent) && data.burndown && data.hours > 0) { $(card).find('.hours').text(parseFloat(data.hours).toFixed(1) - parseFloat(data.hours_spent)); From c358c671c31c198c49cc930cbbf5d4f31c64c6af Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Wed, 3 Aug 2016 15:33:24 -0600 Subject: [PATCH 007/391] Fixing taskboard hour calculation bugs This fixes #149 among other things --- app/controller/taskboard.php | 2 +- app/view/taskboard/index.html | 1 - js/taskboard.js | 20 ++++---------------- 3 files changed, 5 insertions(+), 18 deletions(-) diff --git a/app/controller/taskboard.php b/app/controller/taskboard.php index 713baf7f..8967c1d4 100644 --- a/app/controller/taskboard.php +++ b/app/controller/taskboard.php @@ -393,7 +393,7 @@ public function edit($f3) { $issue->hours_remaining = $post["hours"]; $issue->hours_spent += $post["hours_spent"]; if(!empty($post["hours_spent"]) && !empty($post["burndown"])) { - $issue->hours_remaining -= $post["hours_spent"]; + $issue->hours_remaining -= $post["hours_spent"]; } if(!$issue->hours_remaining || $issue->hours_remaining < 0) { $issue->hours_remaining = 0; diff --git a/app/view/taskboard/index.html b/app/view/taskboard/index.html index b199dcef..8707272e 100644 --- a/app/view/taskboard/index.html +++ b/app/view/taskboard/index.html @@ -259,7 +259,6 @@
  - diff --git a/js/taskboard.js b/js/taskboard.js index bf55e53a..7b08d956 100644 --- a/js/taskboard.js +++ b/js/taskboard.js @@ -127,18 +127,6 @@ var Taskboard = { priority = $(data).find('.priority').data('val'), repeatCycle = $(data).find('.repeat_cycle').text(); - console.log({ -user: user, -userColor: userColor, -taskId: taskId, -title: title, -description: description, -hours: hours, -date: date, -priority: priority, -repeatCycle: repeatCycle, - }); - $('#task-dialog input#taskId').val(taskId); $('#task-dialog input#title').val(title); $('#task-dialog textarea#description').val(description); @@ -206,11 +194,11 @@ repeatCycle: repeatCycle, $(card).find('.title').text(data.title); $(card).find('.repeat_cycle').text(data.repeat_cycle); - if (isNumber(data.hours_spent) && data.burndown && data.hours > 0) { - $(card).find('.hours').text(parseFloat(data.hours).toFixed(1) - parseFloat(data.hours_spent)); + if (isNumber(data.hours_spent) && parseInt(data.burndown) && data.hours > 0) { + $(card).find('.hours').text(parseFloat(data.hours) - parseFloat(data.hours_spent)); $(card).find('.hours').show(); } else if (isNumber(data.hours) && data.hours > 0) { - $(card).find('.hours').text(parseFloat(data.hours).toFixed(1)); + $(card).find('.hours').text(parseFloat(data.hours)); $(card).find('.hours').show(); } else { $(card).find('.hours').hide(); @@ -233,7 +221,7 @@ repeatCycle: repeatCycle, $(card).find('.repeat_cycle').text(data.repeat_cycle); if (isNumber(data.hours) && data.hours > 0) { - $(card).find('.hours').text(parseFloat(data.hours).toFixed(1)); + $(card).find('.hours').text(parseFloat(data.hours)); $(card).find('.hours').show(); } else { $(card).find('.hours').hide(); From 3ee3fba27231fe776735d4edde07e3089410460b Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Tue, 16 Aug 2016 11:03:11 -0600 Subject: [PATCH 008/391] Preventing redundant To: header in notifications --- app/helper/notification.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/helper/notification.php b/app/helper/notification.php index 15cd2bec..0533ba82 100644 --- a/app/helper/notification.php +++ b/app/helper/notification.php @@ -17,7 +17,6 @@ public function utf8mail($to, $subject, $body, $text = null) { // Add basic headers $headers = 'MIME-Version: 1.0' . "\r\n"; - $headers .= 'To: '. $to . "\r\n"; $headers .= 'From: '. $f3->get("mail.from") . "\r\n"; // Build multipart message if necessary From a6b5c3da46c1c28c8a2d6507592c130fc8d331f5 Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Thu, 1 Sep 2016 10:47:25 -0600 Subject: [PATCH 009/391] Fixing a broken Atom feed --- app/controller/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controller/index.php b/app/controller/index.php index 2777c23d..f0d90f92 100644 --- a/app/controller/index.php +++ b/app/controller/index.php @@ -323,7 +323,7 @@ public function atom($f3) { if($get["type"] == "assigned") { $issues = $issue->find(array("author_id = ? AND status_closed = 0 AND deleted_date IS NULL", $user->id), $options); } elseif($get["type"] == "created") { - $issues = $issue->find(array("owner = ? AND status_closed = 0 AND deleted_date IS NULL", $user->id), $options); + $issues = $issue->find(array("owner_id = ? AND status_closed = 0 AND deleted_date IS NULL", $user->id), $options); } elseif($get["type"] == "all") { $issues = $issue->find("status_closed = 0 AND deleted_date IS NULL", $options + array("limit" => 50)); } else { From 8489d7fd9c83af36c53a966a2bf75ff6d78632e6 Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Thu, 1 Sep 2016 11:40:30 -0600 Subject: [PATCH 010/391] Fix backlog unsorted drag/drop handling --- js/backlog.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/backlog.js b/js/backlog.js index 0301438c..1d1d947f 100644 --- a/js/backlog.js +++ b/js/backlog.js @@ -44,7 +44,7 @@ var Backlog = { }, projectReceive: function(item, sender, receiverSerialized) { var itemId = cleanId('project', $(item).attr('id')), - receiverId = cleanId('sprint', $(item).parent().attr('data-list-id')), + receiverId = $(item).parent().attr('data-list-id'), senderId = $(sender).attr('data-list-id'); if (typeof($(sender).attr('data-list-id') !== 'undefined')) { var senderSerialized = sanitizeSortableArray('project', $(sender).sortable('serialize')), @@ -65,7 +65,7 @@ var Backlog = { }, sameReceive: function(item, receiverSerialized) { var itemId = cleanId('project', $(item).attr('id')), - receiverId = cleanId('sprint', $(item).parent().attr('data-list-id')), + receiverId = $(item).parent().attr('data-list-id'), data = { itemId: itemId, reciever: { From ebcaec0eb1a102e95c0a2fd9df8c9cf9d96179ea Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Thu, 1 Sep 2016 11:59:33 -0600 Subject: [PATCH 011/391] XSS vulnerability fixes --- app/controller/admin.php | 26 +++++++++++++++++++++ app/controller/issues.php | 9 +------ app/controller/user.php | 2 +- app/helper/view.php | 3 +++ app/view/admin/sprints/edit.html | 8 +++---- app/view/admin/sprints/new.html | 6 ++--- app/view/admin/users/edit.html | 8 +++---- app/view/blocks/footer.html | 2 +- app/view/blocks/head.html | 2 +- app/view/blocks/issue-list/bulk-update.html | 1 - app/view/issues/search.html | 4 ++-- 11 files changed, 46 insertions(+), 25 deletions(-) diff --git a/app/controller/admin.php b/app/controller/admin.php index f3346945..ac710233 100644 --- a/app/controller/admin.php +++ b/app/controller/admin.php @@ -257,6 +257,26 @@ public function user_save($f3) { } } + // Validate fields + $error = null; + if(!$f3->get("POST.name")) { + $error = "Please enter a name."; + } + if(!preg_match("/#?[0-9a-f]{3,6}/i", $f3->get("POST.task_color"))) { + $error = "Please enter a valid hex color."; + } + if(!preg_match("/[0-9a-z_-]+/i", $f3->get("POST.username"))) { + $error = "Usernames can only contain letters, numbers, hyphens, and underscores."; + } + if(!filter_var($f3->get("POST.email"), FILTER_VALIDATE_EMAIL)) { + $error = "Please enter a valid email address"; + } + if($error) { + $f3->set("error", $error); + $this->_render("admin/users/edit.html"); + return; + } + // Set basic fields $user->username = $f3->get("POST.username"); $user->email = $f3->get("POST.email"); @@ -519,6 +539,12 @@ public function sprint_new($f3) { $start = strtotime($post["start_date"]); $end = strtotime($post["end_date"]); + if(!$start || !$end) { + $f3->set("error", "Please enter a valid start and end date"); + $this->_render("admin/sprints/new.html"); + return; + } + if($end <= $start) { $f3->set("error", "End date must be after start date"); $this->_render("admin/sprints/new.html"); diff --git a/app/controller/issues.php b/app/controller/issues.php index 539697b1..5df9092b 100644 --- a/app/controller/issues.php +++ b/app/controller/issues.php @@ -283,16 +283,9 @@ public function bulk_update($f3) { return; } } - - } else { - $f3->reroute($post["url_path"] . "?" . $post["url_query"]); } - if (!empty($post["url_path"])) { - $f3->reroute($post["url_path"] . "?" . $post["url_query"]); - } else { - $f3->reroute("/issues?" . $post["url_query"]); - } + $f3->reroute("/issues?" . $post["url_query"]); } /** diff --git a/app/controller/user.php b/app/controller/user.php index 66ddf6be..a6f66e97 100644 --- a/app/controller/user.php +++ b/app/controller/user.php @@ -48,7 +48,7 @@ public function dashboard($f3) { if(is_callable(array($helper, $widget))) { $f3->set($widget, $helper->$widget()); } else { - $f3->set("error", "Widget '{$widget}' is not available."); + $f3->set("error", "Widget '" . strip_tags($widget) . "' is not available."); } unset($allWidgets[array_search($widget, $allWidgets)]); } diff --git a/app/helper/view.php b/app/helper/view.php index 013dd67f..711c5691 100644 --- a/app/helper/view.php +++ b/app/helper/view.php @@ -66,6 +66,9 @@ public function parseText($str, $options = array(), $ttl = null) { $str = $this->_parseUrls($str); } + // Simplistic XSS protection + $str = preg_replace("##i", "", $str); + // Pass to any plugin hooks $str = \Helper\Plugin::instance()->callHook("text.parse.after", $str); diff --git a/app/view/admin/sprints/edit.html b/app/view/admin/sprints/edit.html index 59eebe85..736633f3 100644 --- a/app/view/admin/sprints/edit.html +++ b/app/view/admin/sprints/edit.html @@ -10,21 +10,21 @@
{{ @dict.edit_sprint }}
- +
- +
- +
- +
diff --git a/app/view/admin/sprints/new.html b/app/view/admin/sprints/new.html index 2e9df810..188d2b7e 100644 --- a/app/view/admin/sprints/new.html +++ b/app/view/admin/sprints/new.html @@ -12,19 +12,19 @@
- +
- +
- +
diff --git a/app/view/admin/users/edit.html b/app/view/admin/users/edit.html index 7e408b5b..4b9a5752 100644 --- a/app/view/admin/users/edit.html +++ b/app/view/admin/users/edit.html @@ -20,19 +20,19 @@
- +
- +
- +

@@ -73,7 +73,7 @@
{~ if(!empty(@this_user)) @task_color = '#' . @this_user.task_color; elseif(!empty(@POST.task_color)) @task_color = @POST.task_color; ~} - +
diff --git a/app/view/blocks/footer.html b/app/view/blocks/footer.html index fca37a9a..7e53ab24 100644 --- a/app/view/blocks/footer.html +++ b/app/view/blocks/footer.html @@ -5,7 +5,7 @@ ~}
-
{{ @dblog }}
+
{{ @dblog | esc }}
diff --git a/app/view/blocks/head.html b/app/view/blocks/head.html index 3b50774d..3a809433 100644 --- a/app/view/blocks/head.html +++ b/app/view/blocks/head.html @@ -3,7 +3,7 @@ -{{ empty(@title) ? @site.name : @title . ' - ' . @site.name }} +{{ empty(@title) ? @site.name : @title . ' - ' . @site.name | esc }} diff --git a/app/view/blocks/issue-list/bulk-update.html b/app/view/blocks/issue-list/bulk-update.html index b758760c..9dccedf8 100644 --- a/app/view/blocks/issue-list/bulk-update.html +++ b/app/view/blocks/issue-list/bulk-update.html @@ -114,7 +114,6 @@
-
diff --git a/app/view/issues/search.html b/app/view/issues/search.html index c7fc3a40..151031da 100644 --- a/app/view/issues/search.html +++ b/app/view/issues/search.html @@ -19,9 +19,9 @@
From aee7c99445da769c56a0d005e055f79e16ca33d3 Mon Sep 17 00:00:00 2001 From: Alan Hardman Date: Fri, 2 Sep 2016 11:21:08 -0600 Subject: [PATCH 012/391] Fixing some minor XSS issues and other bugs --- app/controller/user.php | 17 +++++++++++++---- app/helper/dashboard.php | 2 ++ app/view/blocks/issue-list/filters.html | 4 ++-- app/view/issues/index.html | 2 +- app/view/issues/search.html | 12 +++++++++--- app/view/user/dashboard.html | 2 +- 6 files changed, 28 insertions(+), 11 deletions(-) diff --git a/app/controller/user.php b/app/controller/user.php index a6f66e97..5dfbabc1 100644 --- a/app/controller/user.php +++ b/app/controller/user.php @@ -41,18 +41,23 @@ public function dashboard($f3) { } // Load dashboard widget data - $allWidgets = array("projects", "subprojects", "tasks", "bugs", "repeat_work", "watchlist", "my_comments", "recent_comments", "open_comments", "issue_tree"); $helper = \Helper\Dashboard::instance(); - foreach($dashboard as $widgets) { - foreach($widgets as $widget) { + $allWidgets = $helper->allWidgets; + $missing = array(); + foreach($dashboard as $k=>$widgets) { + foreach($widgets as $l=>$widget) { if(is_callable(array($helper, $widget))) { $f3->set($widget, $helper->$widget()); } else { $f3->set("error", "Widget '" . strip_tags($widget) . "' is not available."); + $missing[] = array($k, $l); } unset($allWidgets[array_search($widget, $allWidgets)]); } } + foreach($missing as $kl) { + unset($dashboard[$k][$l]); + } $f3->set("unused_widgets", $allWidgets); // Get current sprint if there is one @@ -68,15 +73,19 @@ public function dashboard($f3) { /** * POST /user/dashboard + * Save dashboard widget selections * * @param \Base $f3 */ public function dashboardPost($f3) { + $helper = \Helper\Dashboard::instance(); $user = $f3->get("user_obj"); if($f3->get("POST.action") == "add") { $widgets = $user->option("dashboard"); foreach($f3->get("POST.widgets") as $widget) { - $widgets["left"][] = $widget; + if(in_array($widget, $helper->allWidgets)) { + $widgets["left"][] = $widget; + } } } else { $widgets = json_decode($f3->get("POST.widgets")); diff --git a/app/helper/dashboard.php b/app/helper/dashboard.php index 29b0d956..2a09a09f 100644 --- a/app/helper/dashboard.php +++ b/app/helper/dashboard.php @@ -10,6 +10,8 @@ class Dashboard extends \Prefab { $_projects, $_order = "priority DESC, has_due_date ASC, due_date ASC"; + public $allWidgets = array("projects", "subprojects", "tasks", "bugs", "repeat_work", "watchlist", "my_comments", "recent_comments", "open_comments", "issue_tree"); + public function getIssue() { return $this->_issue === null ? $this->_issue = new \Model\Issue\Detail : $this->_issue; } diff --git a/app/view/blocks/issue-list/filters.html b/app/view/blocks/issue-list/filters.html index 26a7a2e9..410cca6b 100644 --- a/app/view/blocks/issue-list/filters.html +++ b/app/view/blocks/issue-list/filters.html @@ -140,8 +140,8 @@ - - + + diff --git a/app/view/issues/index.html b/app/view/issues/index.html index c0311561..5f7f492b 100644 --- a/app/view/issues/index.html +++ b/app/view/issues/index.html @@ -8,7 +8,7 @@
-

{{ @dict.deleted_success,@GET.deleted | format }} {{ @dict.restore_issue }}

+

{{ @dict.deleted_success,intval(@GET.deleted) | format }} {{ @dict.restore_issue }}

diff --git a/app/view/issues/search.html b/app/view/issues/search.html index 151031da..147fcb01 100644 --- a/app/view/issues/search.html +++ b/app/view/issues/search.html @@ -19,11 +19,17 @@
diff --git a/app/view/user/dashboard.html b/app/view/user/dashboard.html index 5c47d166..e5b0203d 100644 --- a/app/view/user/dashboard.html +++ b/app/view/user/dashboard.html @@ -40,7 +40,7 @@