_binary From 70130721f299d5fb9ad51e6b6756a965bda6312c Mon Sep 17 00:00:00 2001
From: Prajna Puranik <prajnagp@gmail.com>
Date: Thu, 20 Apr 2023 20:37:18 -0700
Subject: [PATCH] Added flagging and moderation functionality

---
 src/configs/Config.php                        |   4 +-
 src/configs/Createdb.php                      |  10 +
 .../components/SocialComponent.php            |  81 ++++-
 src/models/GroupModel.php                     | 289 ++++++++++++++++++
 src/models/ProfileModel.php                   |   4 +
 src/views/elements/GroupfeedElement.php       |  86 +++++-
 src/views/helpers/IconlinkHelper.php          |   2 +
 7 files changed, 472 insertions(+), 4 deletions(-)

diff --git a/src/configs/Config.php b/src/configs/Config.php
index 6fcace61e..0246ab1eb 100755
--- a/src/configs/Config.php
+++ b/src/configs/Config.php
@@ -162,7 +162,7 @@ nsconddefine('GENERATOR_STRING', "Yioop");
  * Version number for upgrade database function
  * @var int
  */
-nsdefine('DATABASE_VERSION', 78);
+nsdefine('DATABASE_VERSION', 79);
 /**
  * Minimum Version fo Yioop for which keyword ad script
  * still works with this version
@@ -636,6 +636,8 @@ nsdefine('HELP_GROUP_ID', 3);
  * belong.
  */
 nsconddefine('SEARCH_GROUP_ID', 4);
+/*ID of the group for moderators */
+nsconddefine('MODERATION_GROUP_ID', 5);
 /** Length of advertisement name string */
 nsdefine('ADVERTISEMENT_NAME_LEN', 25);
 /** Length of advertisement text description */
diff --git a/src/configs/Createdb.php b/src/configs/Createdb.php
index 670853f13..8b5529bf2 100755
--- a/src/configs/Createdb.php
+++ b/src/configs/Createdb.php
@@ -201,6 +201,16 @@ $db->execute("INSERT INTO USER_GROUP VALUES (" . PUBLIC_USER_ID . ", " .
 /* we insert 1 by 1 rather than comma separate as sqlite
    does not support comma separated inserts
  */
+ //Create a group for moderator users
+  $sql = "INSERT INTO SOCIAL_GROUPS VALUES(".MODERATION_GROUP_ID.",'Moderation','" .
+      $creation_time . "','".ROOT_ID."', '"  .INVITE_ONLY_JOIN . "', '" . GROUP_READ .
+      "', " . NON_VOTING_GROUP.", " . FOREVER . ", 0)";
+  $db->execute($sql);
+  $now = time();
+  $db->execute("INSERT INTO USER_GROUP VALUES (" . ROOT_ID . ", " .
+      MODERATION_GROUP_ID . ", " . ACTIVE_STATUS . ", $now)");
+  $db->execute("INSERT INTO USER_GROUP VALUES (" . PUBLIC_USER_ID . ", " .
+      MODERATION_GROUP_ID . ", " . ACTIVE_STATUS . ", $now)");
 $locales = [
     ['ar', 'العربية', 'rl-tb'],
     ['bn', 'বাংলা', 'lr-tb', ''],
diff --git a/src/controllers/components/SocialComponent.php b/src/controllers/components/SocialComponent.php
index 20e4aa268..da4ae4f82 100644
--- a/src/controllers/components/SocialComponent.php
+++ b/src/controllers/components/SocialComponent.php
@@ -1348,7 +1348,7 @@ class SocialComponent extends Component implements CrawlConstants
                 $user_messages_id), [$user_id]);
             $possible_arguments = ["addcomment", "addcontact", "addgroup",
                 "deletepost", "downvote", "newthread", "status", "updatepost",
-                "upvote"];
+                "upvote", "flagpost", "approveflagged", "deleteflagged"];
         }
         if (isset($_REQUEST['arg']) &&
             in_array($_REQUEST['arg'], $possible_arguments)) {
@@ -1523,6 +1523,76 @@ class SocialComponent extends Component implements CrawlConstants
                             ['page_name']);
                     }
                     break;
+                case "flagpost":
+                    if (!isset($_REQUEST['post_id'])) {
+                        return $parent->redirectWithMessage(
+                            tl('social_component_flag_error'),
+                            ['page_name']);
+                        break;
+                    }
+                    $post_id = $parent->clean($_REQUEST['post_id'], "int");
+                    $group_item = $group_model->getGroupItem($post_id);
+                    if ($group_model->alreadyFlagged($user_id, $post_id)) {
+                        return $parent->redirectWithMessage(
+                            tl('social_component_already_flagged'));
+                    }
+                    $success = false;
+                    if ($group_item) {
+                        $success =
+                            $group_model->flagGroupItem($post_id, $user_id);
+                    }
+                    if ($success) {
+                        return $parent->redirectWithMessage(
+                            tl('social_component_item_flagged'),
+                            ['page_name']);
+                    } else {
+                        return $parent->redirectWithMessage(
+                            tl('social_component_no_item_flagged'),
+                            ['page_name']);
+                    }
+                    break;
+                case "approveflagged":
+                    if (!isset($_REQUEST['post_id'])){
+                        return $parent->redirectWithMessage(
+                          tl('social_component_no_approve_access'));
+                    }
+                    $post_id = $parent->clean($_REQUEST['post_id'], "int");
+                    $group_item = $group_model->getGroupItem($post_id);
+                    $success = false;
+                    if ($group_item) {
+                       $success = $group_model->approveFlaggedPost($post_id);
+                    }
+                    if ($success) {
+                        return $parent->redirectWithMessage(
+                            tl('social_component_flagged_item_approved'),
+                            ['page_name']);
+                    } else {
+                        return $parent->redirectWithMessage(
+                            tl('social_component_no_flagged_item_approved'),
+                            ['page_name']);
+                    }
+                    break;
+                case "deleteflagged":
+                    if (!isset($_REQUEST['post_id'])){
+                        return $parent->redirectWithMessage(
+                          tl('social_component_no_delete_access'));
+                    }
+                    $post_id = $parent->clean($_REQUEST['post_id'], "int");
+                    $group_item = $group_model->getGroupItem($post_id);
+                    $success = false;
+                    if ($group_item) {
+                        $success = $group_model->deleteFlaggedPost($post_id);
+                    }
+                    if ($success) {
+                        return $parent->redirectWithMessage(
+                            tl('social_component_flagged_item_deleted'),
+                            ['page_name']);
+                    } else {
+                        return $parent->redirectWithMessage(
+                            tl('social_component_no_flagged_item_deleted'),
+                            ['page_name']);
+                    }
+                    break;
                 case "downvote":
                     if (!isset($_REQUEST['group_id']) || !$_REQUEST['group_id']
                         ||!isset($_REQUEST['post_id']) ||
@@ -2702,6 +2772,15 @@ class SocialComponent extends Component implements CrawlConstants
             }
             $page['USER_ICON'] = $user_model->getUserIconUrl($page['USER_ID']);
             $page[self::TITLE] = $page['TITLE'];
+            //functionality for moderation group
+            if($page['GROUP_ID'] == 5){
+               $parent_group_id = $group_model->getParentGroupId($page['ID']);
+               $page[self::TITLE] = sprintf("Bad Post group %d",
+                    $parent_group_id);
+               $page['FLAG'] = $group_model->getFlagCount($page['ID']);
+               $page['PARENT_ITEM_ID'] =
+                    $group_model->getParentIdOfParentPost($page['ID']);
+            }
             unset($page['TITLE']);
             $description = $page['DESCRIPTION'];
             //start code for sharing crawl mixes
diff --git a/src/models/GroupModel.php b/src/models/GroupModel.php
index 04d51a89c..b7bac7974 100644
--- a/src/models/GroupModel.php
+++ b/src/models/GroupModel.php
@@ -951,6 +951,47 @@ class GroupModel extends Model implements MediaConstants
         }
         return $id;
     }
+    /**
+     * Adds a flagged group item to the moderation group
+     *
+     * @param int $parent_id thread id to use for the item
+     * @param int $group_id what group the item should be added to
+     * @param int $user_id of user making the post
+     * @param string $title title of the group feed item
+     * @param string $description actual content of the post
+     * @param int $type flag saying what kind of group item this is. One of
+     *      STANDARD_GROUP_ITEM, WIKI_GROUP_ITEM (used for threads discussing
+     *      a wiki page)
+     * @param int $post_time timstamp for when this group item was created
+     *      default to the current time
+     * @param string $url a url associated with this group item (mainly for
+     *      search group)
+     * @return int $id of item added
+     */
+    public function addGroupItemModeration($parent_id, $group_id, $user_id,
+        $title, $description, $flag, $parent_item_id, $parent_group_id,
+        $type= C\STANDARD_GROUP_ITEM, $post_time = 0, $url = "")
+    {
+        $db = $this->db;
+        if ($post_time == 0) {
+            $post_time = time();
+        }
+        if($this->isGroupEncrypted($parent_group_id)){
+            $key = $this->getGroupKey($parent_group_id);
+            $title = $this->decrypt($title, $key);
+            $description = $this->decrypt($description, $key);
+        }
+        $sql = "INSERT INTO GROUP_ITEM (PARENT_ID, GROUP_ID, USER_ID, URL,
+             TITLE, DESCRIPTION, PUBDATE, EDIT_DATE, FLAG, PARENT_ITEM_ID, TYPE)
+             VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+        $db->execute($sql, [$parent_id, $group_id, $user_id, $url, $title,
+             $description, $post_time, $post_time, $flag, $parent_item_id,
+             $type]);
+        $id = $db->insertID("GROUP_ITEM");
+        $update_sql = "UPDATE GROUP_ITEM SET PARENT_ID = ? WHERE ID = ?";
+        $db->execute($update_sql, [$id, $id]);
+        return $id;
+    }
     /**
      * Encrypts  data based on provided key.
      *
@@ -992,6 +1033,47 @@ class GroupModel extends Model implements MediaConstants
         }
         return $out_data;
     }
+    /**
+     * Encrypts flag value based on provided key.
+     *
+     * @param string $data what data to encrypt
+     * @param string $key what key to use to encrypt
+     * @param string $cipher_method a cipher encrypt/decrypt method
+     *      supported by OpenSSL
+     * @return string $out_data the encrypted string
+     */
+    public function encryptFlag($data, $key, $cipher_method = 'AES-256-ECB')
+    {
+        $block_length = 16;
+        $padding = $block_length - (strlen($data) % $block_length);
+        $data = $data . str_repeat(chr($padding), $padding);
+        $key = pack('H*', $key);
+        $cipher_method = strtolower($cipher_method);
+        $encrypted = openssl_encrypt($data, $cipher_method, $key,
+                     OPENSSL_RAW_DATA|OPENSSL_NO_PADDING);
+        return base64_encode($encrypted);
+    }
+    /**
+     * Decrypts flag value based on provided key.
+     *
+     * @param string $data what data to decrypt
+     * @param string $key what key to use to decrypt
+     * @param string $cipher_method a cipher encrypt/decrypt method
+     *      supported by OpenSSL
+     * @return string $out_data the decrypted string
+     */
+    public function decryptFlag($encrypted_data, $key,
+    $cipher_method = 'AES-256-ECB')
+    {
+        $encrypted_data = base64_decode($encrypted_data);
+        $key = pack('H*', $key);
+        $cipher_method = strtolower($cipher_method);
+        $out_data = openssl_decrypt($encrypted_data, $cipher_method, $key,
+                     OPENSSL_RAW_DATA|OPENSSL_NO_PADDING);
+        $padding = ord(substr($out_data, -1));
+        $out_data = substr($out_data, 0, -$padding);
+        return $out_data;
+    }
     /**
      * Updates a group feed item's title and description. This assumes
      * the given item already exists.
@@ -1044,6 +1126,213 @@ class GroupModel extends Model implements MediaConstants
         }
         return $affected_rows;
     }
+    /**
+     * Flags a group feed item in the GROUP_ITEM table.
+     *
+     * @param int $post_id of item to be flagged
+     * @param int $user_id the id of the person trying to flag the item
+     * If user does not belong to the group, the item won't be flagged
+     */
+    public function flagGroupItem($post_id, $user_id)
+    {
+        $db = $this->db;
+        $sql = "SELECT * FROM GROUP_ITEM WHERE ID = ?";
+        $stmt = $db->execute($sql, [$post_id]);
+        $result = $stmt->fetch();
+        $group_id = $result['GROUP_ID'];
+        $flag_count = $this->getFlagCount($post_id);
+        if ($this->isGroupEncrypted($group_id))
+        {
+            $threshold = $this->getThresholdValue($group_id);
+            $key = $this->getGroupKey($group_id);
+            if($flag_count == 0){
+                $flag_count = $this->encryptFlag(strval($flag_count), $key);
+            }
+            if ($flag_count === $threshold) {
+                $flag_count_decrypt = $this->decryptFlag(
+                base64_decode($flag_count), $key);
+                $this->addGroupItemModeration(0, 5, $result['USER_ID'],
+                       $result['TITLE'],$result['DESCRIPTION'],
+                       $flag_count_decrypt, $post_id, $group_id,
+                       C\STANDARD_GROUP_ITEM, 0, "");
+            }else{
+                $flag_count = $this->encryptFlag(strval($flag_count), $key);
+            }
+        }
+        else{
+            $flag_count = $flag_count + 1;
+            $threshold = 3;
+            if($flag_count > $threshold){
+                return false;
+            }
+            if($flag_count ===  $threshold){
+                $this->addGroupItemModeration(0, 5, $result['USER_ID'],
+                       $result['TITLE'],$result['DESCRIPTION'], $flag_count,
+                       $post_id, $group_id, C\STANDARD_GROUP_ITEM, 0, "");
+            }
+        }
+        $sql = "INSERT INTO GROUP_ITEM_FLAG VALUES (?, ?)";
+        $this->db->execute($sql, [$user_id, $post_id]);
+        $update_sql = "UPDATE GROUP_ITEM SET FLAG = ? WHERE ID = ?
+                AND GROUP_ID IN (SELECT GROUP_ID FROM USER_GROUP
+                WHERE USER_ID = ?)";
+        $db->execute($update_sql, [$flag_count, $post_id, $user_id]);
+        $affected_rows = $db->affectedRows();
+        return  $affected_rows;
+    }
+    /**
+     * Retrieves flag column value from the database
+     *
+     * @param int $post_id of thread whose flag value needs to be fetched
+     */
+    public function getFlagCount($post_id)
+    {
+        $db = $this->db;
+        $sql = "SELECT FLAG FROM GROUP_ITEM WHERE ID = ?";
+        $stmt = $db->execute($sql, [$post_id]);
+        if (!$stmt) {
+            return false;
+        }
+        if (!($row = $db->fetchArray($stmt))) {
+            return false;
+        }
+        return $row['FLAG'];
+    }
+    /**
+     * Checks if post is already flagged
+     *
+     * @param int $post_id to check if the thread is already flagged
+     */
+    public function alreadyFlagged($user_id, $post_id)
+    {
+        $db = $this->db;
+        $sql = "SELECT COUNT(*) AS NUM FROM GROUP_ITEM_FLAG WHERE USER_ID = ?
+                AND ITEM_ID = ?";
+        $result = $db->execute($sql, [$user_id, $post_id]);
+        if (!$result) {
+             return false;
+        }
+        $row = $db->fetchArray($result);
+        if (!$row || !isset($row['NUM'])) {
+            return false;
+        }
+        return ($row['NUM'] > 0);
+    }
+    /**
+     * Get the group id of the parent thread
+     *
+     * @param int $post_id denotes the thread
+     */
+    public function getParentGroupId($post_id)
+    {
+       $db = $this->db;
+       $sql = "SELECT GROUP_ID FROM GROUP_ITEM WHERE ID =
+               (SELECT PARENT_ITEM_ID FROM GROUP_ITEM WHERE ID = ?)";
+       $stmt = $db->execute($sql, [$post_id]);
+        if (!$stmt) {
+            return false;
+        }
+        if (!($row = $db->fetchArray($stmt))) {
+            return false;
+        }
+        return $row['GROUP_ID'];
+    }
+    /**
+     * Get the minimum number of times a post has to be flagged to be reviewed
+     * by the moderator
+     *
+     * @param int $group_id to get threshold value for the given group
+     */
+    public function getThresholdValue($group_id)
+    {
+       $key = $this->getGroupKey($group_id);
+       $x = 3;
+       $res = 0;
+       while($x > 0){
+         $res = $this->encryptFlag(strval($res), $key);
+         $x--;
+       }
+       return $res;
+    }
+    /**
+     * Get the id of the parent thread of a post
+     *
+     * @param int $post_id denotes the thread
+     */
+    public function getParentPostById($post_id)
+    {
+        $db = $this->db;
+        $sql = "SELECT ID FROM GROUP_ITEM WHERE ID =
+                (SELECT PARENT_ITEM_ID FROM GROUP_ITEM WHERE ID = ?)";
+        $stmt = $db->execute($sql, [$post_id]);
+        if (!$stmt) {
+            return false;
+        }
+        if (!($row = $db->fetchArray($stmt))) {
+            return false;
+        }
+        return $row['ID'];
+    }
+    /**
+     * Get parent_id of the parent thread of a given post
+     *
+     * @param int $post_id denotes the post
+     */
+    public function getParentIdOfParentPost($post_id)
+    {
+        $db = $this->db;
+        $sql = "SELECT PARENT_ID FROM GROUP_ITEM WHERE ID =
+                (SELECT PARENT_ITEM_ID FROM GROUP_ITEM WHERE ID = ?)";
+        $stmt = $db->execute($sql, [$post_id]);
+        if (!$stmt) {
+            return false;
+        }
+        if (!($row = $db->fetchArray($stmt))) {
+            return false;
+        }
+        return $row['PARENT_ID'];
+
+    }
+    /**
+     * Moderator approves a flagged post
+     *
+     * @param int $post_id to fetch the flagged post
+     */
+    public function approveFlaggedPost($post_id)
+    {
+         //get parent_item_id and go to the original post
+         $item_id= $this->getParentPostById($post_id);
+         //reset flag column value to zero
+         $db = $this->db;
+         $update_sql = "UPDATE GROUP_ITEM SET FLAG = 0 WHERE ID = ?";
+         $db->execute($update_sql, [$item_id]);
+         $reset_sql = "UPDATE GROUP_ITEM SET FLAG = -1 WHERE ID = ?";
+         $db->execute($reset_sql, [$post_id]);
+         $affected_rows = $db->affectedRows();
+         return  $affected_rows;
+    }
+    /**
+     * Moderator deletes a flagged post
+     *
+     * @param int $post_id to fetch the flagged post
+     */
+    public function deleteFlaggedPost($post_id)
+    {
+         $description = "This post has been flagged";
+         $parent_group_id = $this->getParentGroupId($post_id);
+         if($this->isGroupEncrypted($parent_group_id)){
+            $key = $this->getGroupKey($parent_group_id);
+            $description = $this->encrypt($description, $key);
+         }
+         $item_id = $this->getParentPostById($post_id);
+         $db = $this->db;
+         $update_sql = "UPDATE GROUP_ITEM SET DESCRIPTION =? WHERE ID = ?";
+         $db->execute($update_sql, [$description, $item_id]);
+         $reset_sql = "UPDATE GROUP_ITEM SET FLAG = -1 WHERE ID = ?";
+         $db->execute($reset_sql, [$post_id]);
+         $affected_rows = $db->affectedRows();
+         return  $affected_rows;
+    }
     /**
      * Gets the group feed items visible to a user with $user_id
      * and which match the supplied search criteria found in $search_array,
diff --git a/src/models/ProfileModel.php b/src/models/ProfileModel.php
index 946a5222a..c3c91579c 100755
--- a/src/models/ProfileModel.php
+++ b/src/models/ProfileModel.php
@@ -195,6 +195,8 @@ class ProfileModel extends Model
                 C\TIMESTAMP_LEN . "),
                 EDIT_DATE NUMERIC(" . C\TIMESTAMP_LEN . "),
                 UPS $integer DEFAULT 0, DOWNS $integer DEFAULT 0,
+                FLAG $integer DEFAULT 0,
+                PARENT_ITEM_ID $integer DEFAULT 0,
                 TYPE $integer DEFAULT " . C\STANDARD_GROUP_ITEM . ")",
             "GI_GROUP_ID_INDEX" => "CREATE INDEX GI_GROUP_ID_INDEX ON
                 GROUP_ITEM (GROUP_ID)",
@@ -210,6 +212,8 @@ class ProfileModel extends Model
                 GI_PARENT_ID_PUBDATE_INDEX ON GROUP_ITEM (PARENT_ID, PUBDATE)",
             "GROUP_ITEM_VOTE" => "CREATE TABLE GROUP_ITEM_VOTE(
                 USER_ID $integer, ITEM_ID $integer)",
+            "GROUP_ITEM_FLAG" => "CREATE TABLE GROUP_ITEM_FLAG(
+                USER_ID $integer, ITEM_ID $integer)",
             "GROUP_ITEM_RECOMMENDATION" => "CREATE TABLE
                 GROUP_ITEM_RECOMMENDATION (USER_ID $integer NOT NULL,
                 ITEM_ID $integer NOT NULL, ITEM_TYPE $integer NOT NULL,
diff --git a/src/views/elements/GroupfeedElement.php b/src/views/elements/GroupfeedElement.php
index a4c9e1a08..df5e6316b 100644
--- a/src/views/elements/GroupfeedElement.php
+++ b/src/views/elements/GroupfeedElement.php
@@ -202,6 +202,10 @@ class GroupfeedElement extends Element implements CrawlConstants
         $is_thread = !empty($data['JUST_THREAD']);
         $is_group = !empty($data['JUST_GROUP_ID']);
         $is_user = !empty($data['JUST_USER_ID']);
+        $parent_item_id = (!empty($data['WIKI_PARENT_ID'])) ?
+            $data['WIKI_PARENT_ID'] : (
+            (empty($data['PAGES'][0]["PARENT_ITEM_ID"])) ?
+            -1 : $data['PAGES'][0]["PARENT_ITEM_ID"]);
         $is_page_with_comments = ($data['ELEMENT'] == 'wiki');
         $is_all_feed = !$is_thread && !$is_group && !$is_page_with_comments &&
             !$is_user;
@@ -366,6 +370,21 @@ class GroupfeedElement extends Element implements CrawlConstants
                     tl('groupfeed_element_delete') ?>" >🗑<span class="none"><?=
                     tl('groupfeed_element_delete') ?></span></span></a>
                 </div><?php
+            }else if(in_array($member_access, $can_comment) && $is_thread){
+            ?>
+            <div class="float-opposite button-container">
+            <?php
+            $flag_url = (empty($data['WIKI_FEED_BASE'])) ?
+                          $paging_query : $data['WIKI_FEED_BASE'];
+            ?>
+            <a onclick="return confirm('<?=
+             tl('groupfeed_element_confirm_flag') ?>');"
+             href="<?= $flag_url .'&amp;arg=flagpost&amp;' . "post_id=" .
+             $page['ID'] ?>">
+             <?php $this->view->helper("iconlink")->renderButton(
+             $flag_url .'&amp;arg=flagpost&amp;' . "post_id=" . $page['ID'],
+             "flag");?></a>
+            </div><?php
             }
             $title_class = "";
             if (!empty($data['DISCUSS_THREAD'])) {
@@ -410,7 +429,21 @@ class GroupfeedElement extends Element implements CrawlConstants
             </div>
             <div class="<?=$feed_item_body ?>" <?=$feed_item_body_first
              ?> ><?php
-            if (!$is_thread || $first_page) {?>
+            if (!$is_thread && $first_page && isset($page['GROUP_ID'])
+             && $page['GROUP_ID'] == 5 && isset($page['FLAG']) &&
+             $page['FLAG'] == -1){
+             ?>
+                <h2><a href="<?= $this->formatHref(B\feedsUrl('thread',
+                $page['PARENT_ID'], true, $data['CONTROLLER']) . $token) ?>"
+                <?= $no_follow ?> <?=$title_class ?> id='title<?=$page['ID']?>'
+                <?php
+                if ($open_in_tabs) {
+                     ?> target="_blank" rel="noopener"<?php
+                }
+                ?> style="color: green;"><?= $page[self::TITLE] ?></a></h2>
+                <?php
+             }
+            else if (!$is_thread || $first_page) {?>
                 <h2><a href="<?= $this->formatHref(B\feedsUrl('thread',
                     $page['PARENT_ID'], true, $data['CONTROLLER']) .
                     $token) ?>" <?= $no_follow ?> <?=$title_class ?>
@@ -419,7 +452,7 @@ class GroupfeedElement extends Element implements CrawlConstants
                         ?> target="_blank" rel="noopener"<?php
                     }
                     ?>><?= $page[self::TITLE] ?></a><?php
-                    if (!$is_page_with_comments) {
+                    if (!$is_page_with_comments && $page['GROUP_ID'] != 5) {
                         if (isset($page['NUM_POSTS'])) {
                             e(" (");
                             e(tl('groupfeed_element_num_posts',
@@ -502,6 +535,7 @@ class GroupfeedElement extends Element implements CrawlConstants
                     $page["MEMBER_ACCESS"], $can_comment)) {
                 $this->drawCommentForm($data['JUST_THREAD'], $data["GROUP_ID"],
                     $data);
+                $this->showOriginalPost($data["GROUP_ID"], $data, $parent_item_id);
             }
         }
     }
@@ -619,6 +653,30 @@ class GroupfeedElement extends Element implements CrawlConstants
             "for=\"comment-add-comment\" ><?=
             tl('groupfeed_element_comment') ?></label></button>");
         </script>
+        <?php if ($group_id == 5) {
+                $flag_url = C\BASE_URL . "/group?" .
+                C\CSRF_TOKEN . "=" . $data[C\CSRF_TOKEN];
+           ?>
+
+           <button class="button-box"
+            onclick="if(confirm('Are you sure you want to approve ' +
+            'this flagged post?')) {
+            window.location.href='<?php echo $flag_url .
+            '&amp;arg=approveflagged&amp;'."post_id=" . $thread_id ?>';
+            }">
+            <label>Approve</label>
+          </button>
+
+           <button class="button-box"
+            onclick="if(confirm('Are you sure you want to delete ' +
+            'this flagged post?')) {
+            window.location.href='<?php echo $flag_url .
+            '&amp;arg=deleteflagged&amp;'."post_id=" . $thread_id ?>';
+            }">
+           <label>Delete</label>
+           </button>
+
+          <?php } ?>
         <noscript>
         <h2><label for="comment-add-comment" ><b><?=
             tl('groupfeed_element_comment') ?></b></label></h2>
@@ -668,6 +726,30 @@ class GroupfeedElement extends Element implements CrawlConstants
         </div>
         <?php
     }
+    /**
+    * Used to display the original thread of the flagged comment
+    *
+    * @param int $group_id of group to draw form for
+    * @param array $data containing other field needed to draw the form
+    * @param int $parent_item retrieves the original thread of flagged comment
+    */
+     private function showOriginalPost($group_id, $data, $parent_item_id)
+     {
+        ?>
+        <div class="button-group-result">
+        <?php if($group_id == 5){
+           $original_post_url = C\BASE_URL . "/thread" .
+           "/" . $parent_item_id . "?" . C\CSRF_TOKEN . "=" .
+           $data[C\CSRF_TOKEN];
+        ?>
+        <button class="button-box"
+        onclick="window.location.href='<?php echo $original_post_url ?>';">
+        <label> Original Post</label>
+        </button>
+        <?php } ?>
+        </div>
+        <?php
+    }
     /**
      * Used to render the dropdown for paths within the top group feed
      * drop down
diff --git a/src/views/helpers/IconlinkHelper.php b/src/views/helpers/IconlinkHelper.php
index 723e05d4b..d2d3b8686 100644
--- a/src/views/helpers/IconlinkHelper.php
+++ b/src/views/helpers/IconlinkHelper.php
@@ -61,6 +61,8 @@ class IconlinkHelper extends Helper
             "crawls" => [tl('iconlink_helper_manage_crawls'),  '🕸️'],
             "delete" => [tl('iconlink_helper_delete'), '🗑️',
                 tl('iconlink_helper_confirm')],
+            "flag" => [tl('iconlink_helper_flag'), '🏳️',
+                tl('iconlink_helper_flag_confirm')],
             "discuss_page" => [
                 tl('iconlink_helper_discuss_page'), '🗣️'],
             "edit" => [ tl('iconlink_helper_edit'),  '✏️'],
-- 
2.37.1 (Apple Git-137.1)

