Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forum: Show Merged threads #2599

Merged
merged 10 commits into from Aug 3, 2018
@@ -0,0 +1,6 @@
def up(config, conn, semester, course):
with conn.cursor() as cursor:
cursor.execute("UPDATE threads SET deleted = false WHERE merged_thread_id <> -1")

def down(config, conn, semester, course):
pass
26 changes: 21 additions & 5 deletions site/app/controllers/forum/ForumController.php
Expand Up @@ -101,6 +101,10 @@ private function showDeleted() {
return ($this->core->getUser()->getGroup() <= 2 && isset($_COOKIE['show_deleted']) && $_COOKIE['show_deleted'] == "1");
}

private function showMergedThreads($currentCourse) {
return (isset($_COOKIE["{$currentCourse}_show_merged_thread"]) && $_COOKIE["{$currentCourse}_show_merged_thread"] == "1");
}

private function returnUserContentToPage($error, $isThread, $thread_id){
//Notify User
$this->core->addErrorMessage($error);
Expand Down Expand Up @@ -548,14 +552,14 @@ private function editPost(){
return null;
}

private function getSortedThreads($categories_ids, $max_thread, $show_deleted, $thread_status, $blockNumber = 1){
private function getSortedThreads($categories_ids, $max_thread, $show_deleted, $show_merged_thread, $thread_status, $blockNumber = 1){
$blockSize = 10;
$current_user = $this->core->getUser()->getId();
if(!$this->isValidCategories($categories_ids)) {
// No filter for category
$categories_ids = array();
}
$ordered_threads = $this->core->getQueries()->loadThreadBlock($categories_ids, $thread_status, $show_deleted, $current_user, $blockSize, $blockNumber);
$ordered_threads = $this->core->getQueries()->loadThreadBlock($categories_ids, $thread_status, $show_deleted, $show_merged_thread, $current_user, $blockSize, $blockNumber);
foreach ($ordered_threads as &$thread) {
$list = array();
foreach(explode("|", $thread['categories_ids']) as $id ) {
Expand All @@ -572,6 +576,7 @@ public function getThreads(){
$pageNumber = !empty($_GET["page_number"]) && is_numeric($_GET["page_number"]) ? (int)$_GET["page_number"] : -1;
$show_deleted = $this->showDeleted();
$currentCourse = $this->core->getConfig()->getCourse();
$show_merged_thread = $this->showMergedThreads($currentCourse);
$categories_ids = array_key_exists('thread_categories', $_POST) && !empty($_POST["thread_categories"]) ? explode("|", $_POST['thread_categories']) : array();
$thread_status = array_key_exists('thread_status', $_POST) && ($_POST["thread_status"] === "0" || !empty($_POST["thread_status"])) ? explode("|", $_POST['thread_status']) : array();
if(empty($categories_ids) && !empty($_COOKIE[$currentCourse . '_forum_categories'])){
Expand All @@ -587,7 +592,7 @@ public function getThreads(){
$status = (int)$status;
}
$max_thread = 0;
$threads = $this->getSortedThreads($categories_ids, $max_thread, $show_deleted, $thread_status, $pageNumber);
$threads = $this->getSortedThreads($categories_ids, $max_thread, $show_deleted, $show_merged_thread, $thread_status, $pageNumber);
$currentCategoriesIds = (!empty($_POST['currentCategoriesId'])) ? explode("|", $_POST["currentCategoriesId"]) : array();
$currentThreadId = array_key_exists('currentThreadId', $_POST) && !empty($_POST["currentThreadId"]) && is_numeric($_POST["currentThreadId"]) ? (int)$_POST["currentThreadId"] : -1;
$thread_data = array();
Expand Down Expand Up @@ -623,7 +628,8 @@ public function showThreads(){

$max_thread = 0;
$show_deleted = $this->showDeleted();
$threads = $this->getSortedThreads($category_id, $max_thread, $show_deleted, $thread_status, 1);
$show_merged_thread = $this->showMergedThreads($currentCourse);
$threads = $this->getSortedThreads($category_id, $max_thread, $show_deleted, $show_merged_thread, $thread_status, 1);

$current_user = $this->core->getUser()->getId();

Expand All @@ -637,18 +643,28 @@ public function showThreads(){
$option = ($this->core->getUser()->getGroup() <= 2 || $option != 'alpha') ? $option : 'tree';
if(!empty($_REQUEST["thread_id"])){
$thread_id = (int)$_REQUEST["thread_id"];
$thread = $this->core->getQueries()->getThread($thread_id)[0];
if($thread['merged_thread_id'] != -1){
// Redirect merged thread to parent
$this->core->addSuccessMessage("Requested thread is merged into current thread.");
$this->core->redirect($this->core->buildUrl(array('component' => 'forum', 'page' => 'view_thread', 'thread_id' => $thread['merged_thread_id'])));
return;
}
if($option == "alpha"){
$posts = $this->core->getQueries()->getPostsForThread($current_user, $thread_id, $show_deleted, 'alpha');
} else {
$posts = $this->core->getQueries()->getPostsForThread($current_user, $thread_id, $show_deleted, 'tree');
}
if(empty($posts)){
$this->core->addErrorMessage("No posts found for selected thread.");
}

}
if(empty($_REQUEST["thread_id"]) || empty($posts)) {
$posts = $this->core->getQueries()->getPostsForThread($current_user, -1, $show_deleted);
}

$this->core->getOutput()->renderOutput('forum\ForumThread', 'showForumThreads', $user, $posts, $threads, $show_deleted, $option, $max_thread);
$this->core->getOutput()->renderOutput('forum\ForumThread', 'showForumThreads', $user, $posts, $threads, $show_deleted, $show_merged_thread, $option, $max_thread);
}

private function getAllowedCategoryColor() {
Expand Down
30 changes: 18 additions & 12 deletions site/app/libraries/database/DatabaseQueries.php
Expand Up @@ -122,7 +122,7 @@ public function insertSubmittyUser(User $user) {
*
* @return ordered threads after filter
*/
public function loadThreadBlock($categories_ids, $thread_status, $show_deleted, $current_user, $blockSize, $blockNumber){
public function loadThreadBlock($categories_ids, $thread_status, $show_deleted, $show_merged_thread, $current_user, $blockSize, $blockNumber){
// $blockNumber is 1 based index
if($blockNumber < 1) {
return array();
Expand All @@ -142,10 +142,10 @@ public function loadThreadBlock($categories_ids, $thread_status, $show_deleted,
}

$query_delete = $show_deleted?"true":"deleted = false";
$query_delete .= " and merged_thread_id = -1";
$query_merge_thread = $show_merged_thread?"true":"merged_thread_id = -1";
$query_select_categories = "SELECT thread_id, array_to_string(array_agg(w.category_id),'|') as categories_ids, array_to_string(array_agg(w.category_desc),'|') as categories_desc, array_to_string(array_agg(w.color),'|') as categories_color FROM categories_list w JOIN thread_categories e ON e.category_id = w.category_id GROUP BY e.thread_id";

$query = "SELECT t.*, categories_ids, categories_desc, categories_color, (case when sf.user_id is NULL then false else true end) as favorite, (case when exists(select 1 from posts p where p.author_user_id = ? and p.thread_id = t.id) then true else false end) as current_user_posted FROM threads t JOIN ({$query_select_categories}) AS QSC ON QSC.thread_id = t.id LEFT JOIN student_favorites sf ON sf.thread_id = t.id and sf.user_id = ? WHERE {$query_delete} and ? = (SELECT count(*) FROM thread_categories tc WHERE tc.thread_id = t.id and category_id IN ({$query_multiple_qmarks})) and {$query_status} ORDER BY pinned DESC, favorite DESC, t.id DESC LIMIT ? OFFSET ?";
$query = "SELECT t.*, categories_ids, categories_desc, categories_color, (case when sf.user_id is NULL then false else true end) as favorite, (case when exists(select 1 from posts p where p.author_user_id = ? and p.thread_id = t.id) then true else false end) as current_user_posted FROM threads t JOIN ({$query_select_categories}) AS QSC ON QSC.thread_id = t.id LEFT JOIN student_favorites sf ON sf.thread_id = t.id and sf.user_id = ? WHERE {$query_delete} and {$query_merge_thread} and ? = (SELECT count(*) FROM thread_categories tc WHERE tc.thread_id = t.id and category_id IN ({$query_multiple_qmarks})) and {$query_status} ORDER BY pinned DESC, favorite DESC, t.id DESC LIMIT ? OFFSET ?";

// Parameters
$query_parameters = array();
Expand Down Expand Up @@ -208,7 +208,12 @@ public function getDeletedPostsByUser($user){

public function getFirstPostForThread($thread_id) {
$this->course_db->query("SELECT * FROM posts WHERE parent_id = -1 AND thread_id = ?", array($thread_id));
return $this->course_db->rows()[0];
$rows = $this->course_db->rows();
if(count($rows) > 0) {
return $rows[0];
} else {
return null;
}
}

public function getPost($post_id){
Expand Down Expand Up @@ -2201,7 +2206,7 @@ public function existsPost($thread_id, $post_id){

public function existsAnnouncements($show_deleted = false){
$query_delete = $show_deleted?"true":"deleted = false";
$this->course_db->query("SELECT MAX(id) FROM threads where {$query_delete} AND pinned = true");
$this->course_db->query("SELECT MAX(id) FROM threads where {$query_delete} AND merged_thread_id = -1 AND pinned = true");
$result = $this->course_db->rows();
return empty($result[0]["max"]) ? -1 : $result[0]["max"];
}
Expand Down Expand Up @@ -2276,12 +2281,13 @@ public function getCategories(){
public function getPostsForThread($current_user, $thread_id, $show_deleted = false, $option = "tree"){
$query_delete = $show_deleted?"true":"deleted = false";
if($thread_id == -1) {
$announcement_id = $this->existsAnnouncements($show_deleted);
if($announcement_id == -1){
$this->course_db->query("SELECT MAX(id) as max from threads WHERE {$query_delete} and pinned = false");
$thread_id = $this->course_db->rows()[0]["max"];
$this->course_db->query("SELECT MAX(id) as max from threads WHERE deleted = false and merged_thread_id = -1 GROUP BY pinned ORDER BY pinned DESC");
$rows = $this->course_db->rows();
if(!empty($rows)) {
$thread_id = $rows[0]["max"];
} else {
$thread_id = $announcement_id;
// No thread found, hence no posts found
return array();
}
}
$history_query = "LEFT JOIN forum_posts_history fph ON (fph.post_id is NULL OR (fph.post_id = posts.id and NOT EXISTS (SELECT 1 from forum_posts_history WHERE post_id = fph.post_id and edit_timestamp > fph.edit_timestamp )))";
Expand All @@ -2299,7 +2305,7 @@ public function getPostsForThread($current_user, $thread_id, $show_deleted = fal
}

public function getRootPostOfNonMergedThread($thread_id, &$title, &$message) {
$this->course_db->query("SELECT title FROM threads WHERE id = ? and merged_thread_id = -1 and merged_post_id = -1 and deleted = false", array($thread_id));
$this->course_db->query("SELECT title FROM threads WHERE id = ? and merged_thread_id = -1 and merged_post_id = -1", array($thread_id));
$result_rows = $this->course_db->rows();
if(count($result_rows) == 0) {
$message = "Can't find thread";
Expand Down Expand Up @@ -2335,7 +2341,7 @@ public function mergeThread($parent_thread_id, $child_thread_id, &$message){
$this->findChildren($child_root_post, $child_thread_id, $children);

// $merged_post_id is PK of linking node and $merged_thread_id is immediate parent thread_id
$this->course_db->query("UPDATE threads SET merged_thread_id = ?, merged_post_id = ?, deleted = true WHERE id = ?", array($parent_thread_id, $child_root_post, $child_thread_id));
$this->course_db->query("UPDATE threads SET merged_thread_id = ?, merged_post_id = ? WHERE id = ?", array($parent_thread_id, $child_root_post, $child_thread_id));
foreach($children as $post_id){
$this->course_db->query("UPDATE posts SET thread_id = ? WHERE id = ?", array($parent_thread_id,$post_id));
}
Expand Down
39 changes: 35 additions & 4 deletions site/app/views/forum/ForumThreadView.php
Expand Up @@ -145,7 +145,7 @@ public function searchResult($threads){
that have been created after applying filter and to be
displayed in the left panel.
*/
public function showForumThreads($user, $posts, $threadsHead, $show_deleted, $display_option, $max_thread) {
public function showForumThreads($user, $posts, $threadsHead, $show_deleted, $show_merged_thread, $display_option, $max_thread) {
if(!$this->forumAccess()){
$this->core->redirect($this->core->buildUrl(array('component' => 'navigation')));
return;
Expand All @@ -154,7 +154,7 @@ public function showForumThreads($user, $posts, $threadsHead, $show_deleted, $di
$threadExists = $this->core->getQueries()->threadExists();
$filteredThreadExists = (count($threadsHead)>0);
$currentThread = -1;
$currentCategoryId = array();
$currentCategoriesIds = array();
$currentCourse = $this->core->getConfig()->getCourse();
$threadFiltering = $threadExists && !$filteredThreadExists && !(empty($_COOKIE[$currentCourse . '_forum_categories']) && empty($_COOKIE['forum_thread_status']));

Expand Down Expand Up @@ -227,10 +227,20 @@ function changeName(element, user, visible_username, anon){
$currentThread = isset($_GET["thread_id"]) && is_numeric($_GET["thread_id"]) && (int)$_GET["thread_id"] < $max_thread && (int)$_GET["thread_id"] > 0 ? (int)$_GET["thread_id"] : $posts[0]["thread_id"];
$currentCategoriesIds = $this->core->getQueries()->getCategoriesIdForThread($currentThread);
}
if($show_merged_thread) {
$show_merged_thread_class = "active";
$show_merged_thread_action = "alterShowMergeThreadStatus(0, '{$currentCourse}');";
$show_merged_thread_title = "Hide Merged Threads";
} else {
$show_merged_thread_class = "";
$show_merged_thread_action = "alterShowMergeThreadStatus(1, '{$currentCourse}');";
$show_merged_thread_title = "Show Merged Threads";
}
$return .= <<<HTML
<div style="margin-top:5px;background-color:transparent; margin: !important auto;padding:0px;box-shadow: none;" class="content">
<div style="background-color: #E9EFEF; box-shadow:0 2px 15px -5px #888888;border-radius:3px;margin-left:20px;margin-top:10px; height:40px; margin-bottom:10px;margin-right:20px;" id="forum_bar">
<a class="btn btn-primary" style="position:relative;top:3px;left:5px;" title="Create thread" onclick="resetScrollPosition();" href="{$this->core->buildUrl(array('component' => 'forum', 'page' => 'create_thread'))}"><i class="fa fa-plus-circle"></i> Create Thread</a>
<a class="btn btn-primary {$show_merged_thread_class}" style="margin-left:10px;position:relative;top:3px;right:5px;display:inline-block;" title="{$show_merged_thread_title}" onclick="{$show_merged_thread_action}">{$show_merged_thread_title}</a>
HTML;
if($this->core->getUser()->getGroup() <= 2){
if($show_deleted) {
Expand Down Expand Up @@ -507,7 +517,18 @@ public function displayThreadList($threads, $filtering, &$activeThreadAnnounceme
$end = 10;
foreach($threads as $thread){
$first_post = $this->core->getQueries()->getFirstPostForThread($thread["id"]);
$date = date_create($first_post['timestamp']);
if(is_null($first_post)) {
// Thread without any posts(eg. Merged Thread)
$first_post = array('content' => "");
$date = null;
} else {
$date = date_create($first_post['timestamp']);
}
if($thread['merged_thread_id'] != -1){
// For the merged threads
$thread['status'] = 0;
}

$class = "thread_box";
// $current_categories_ids should be subset of $thread["categories_ids"]
$issubset = (count(array_intersect($current_categories_ids, $thread["categories_ids"])) == count($current_categories_ids));
Expand Down Expand Up @@ -575,6 +596,12 @@ public function displayThreadList($threads, $filtering, &$activeThreadAnnounceme
$return .= <<<HTML
<i class="fa fa-thumb-tack" style="padding-left:3px;position:relative; float:right; display:inline-block; color:gold; -webkit-text-stroke-width: 1px;
-webkit-text-stroke-color: black;" aria-hidden="true"></i>
HTML;
}
if($thread['merged_thread_id'] != -1) {
$return .= <<<HTML
<i class="fa fa-link" style="padding-left:3px;position:relative; float:right; display:inline-block; color: white; -webkit-text-stroke-width: 1px;
-webkit-text-stroke-color: black;" title="Thread Merged" aria-hidden="true"></i>
HTML;
}
if (!isset($thread['status'])) {
Expand Down Expand Up @@ -607,10 +634,14 @@ public function displayThreadList($threads, $filtering, &$activeThreadAnnounceme
foreach ($categories_content as $category_content) {
$return .= <<<HTML
<span class="label_forum" style="background-color: {$category_content[1]}">{$category_content[0]}</span>
HTML;
}
if(!is_null($date)) {
$return .= <<<HTML
<h5 style="float:right; font-weight:normal;margin-top:5px">{$function_date($date,"n/j g:i A")}</h5>
HTML;
}
$return .= <<<HTML
<h5 style="float:right; font-weight:normal;margin-top:5px">{$function_date($date,"n/j g:i A")}</h5>
</div>
</a>
<hr style="margin-top: 0px;margin-bottom:0px;">
Expand Down
5 changes: 5 additions & 0 deletions site/public/js/server.js
Expand Up @@ -1612,6 +1612,11 @@ function alterShowDeletedStatus(newStatus) {
location.reload();
}

function alterShowMergeThreadStatus(newStatus, course) {
document.cookie = course + "_show_merged_thread=" + newStatus + "; path=/;";
location.reload();
}

function modifyThreadList(currentThreadId, currentCategoriesId, course){
var categories_value = $("#thread_category").val();
var thread_status_value = $("#thread_status_select").val();
Expand Down