Can the user reply to the post in this discussion?

@param stdClass $user The user to check
@param discussion_entity $discussion The discussion to check
@param post_entity $post The post the user wants to reply to
@return bool
14960
public function can_reply_to_post(stdClass $user, discussion_entity $discussion, post_entity $post) : bool {
        if ($post->is_private_reply()) {
            // It is not possible to reply to a private reply.
            return false;
        }

        return $this->can_post_in_discussion($user, $discussion);
    }
1336551
public function can_manually_control_post_read_status(stdClass $user) : bool {
        global $CFG;
        return $CFG->forum_usermarksread && isloggedin() && forum_tp_is_tracked($this->get_forum_record(), $user);
    }
1323944
public static function InformCheckedComments($Sender) {
      $Session = Gdn::Session();
      $HadCheckedComments = FALSE;
      $TransientKey = GetValue('TransientKey', $_POST);
      if ($Session->IsValid() && $Session->ValidateTransientKey($TransientKey)) {
         // Form was posted, so accept changes to checked items.
         $DiscussionID = GetValue('DiscussionID', $_POST, 0);
         $CheckIDs = GetValue('CheckIDs', $_POST);
         if (empty($CheckIDs))
            $CheckIDs = array();
         $CheckIDs = (array)$CheckIDs;
         
         $CheckedComments = Gdn::UserModel()->GetAttribute($Session->User->UserID, 'CheckedComments', array());
         if (!is_array($CheckedComments))
            $CheckedComments = array();
            
         if (!array_key_exists($DiscussionID, $CheckedComments)) {
            $CheckedComments[$DiscussionID] = array();
         } else {
            // Were there checked comments in this discussion before the form was posted?
            $HadCheckedComments = count($CheckedComments[$DiscussionID]) > 0; 
         }
         foreach ($CheckIDs as $Check) {
            if (GetValue('checked', $Check)) {
               if (!ArrayHasValue($CheckedComments, $Check['checkId']))
                  $CheckedComments[$DiscussionID][] = $Check['checkId'];
            } else {
               RemoveValueFromArray($CheckedComments[$DiscussionID], $Check['checkId']);
            }
         }
         
         if (count($CheckedComments[$DiscussionID]) == 0)
            unset($CheckedComments[$DiscussionID]);
            
         Gdn::UserModel()->SaveAttribute($Session->User->UserID, 'CheckedComments', $CheckedComments);
      } else if ($Session->IsValid()) {
         // No form posted, just retrieve checked items for display
         $DiscussionID = property_exists($Sender, 'DiscussionID') ? $Sender->DiscussionID : 0;
         $CheckedComments = Gdn::UserModel()->GetAttribute($Session->User->UserID, 'CheckedComments', array());
         if (!is_array($CheckedComments))
            $CheckedComments = array();
            
      }

      // Retrieve some information about the checked items
      $CountDiscussions = count($CheckedComments);
      $CountComments = 0;
      foreach ($CheckedComments as $DiscID => $Comments) {
         if ($DiscID == $DiscussionID)
            $CountComments += count($Comments); // Sum of comments in this discussion
      }
      if ($CountComments > 0) {
         $SelectionMessage =  Wrap(sprintf(
            T('You have selected %1$s in this discussion.'),
            Plural($CountComments, '%s comment', '%s comments')
         ), 'div');
         $ActionMessage = T('Take Action:');
         
         // Can the user delete the comment?
         $DiscussionModel = new DiscussionModel();
         $Discussion = $DiscussionModel->GetID($DiscussionID);
         $PermissionCategory = CategoryModel::Categories(GetValue('CategoryID', $Discussion));
         if ($Session->CheckPermission('Vanilla.Comments.Delete', TRUE, 'Category', GetValue('PermissionCategoryID', $PermissionCategory)))
            $ActionMessage .= ' '.Anchor(T('Delete'), 'vanilla/moderation/confirmcommentdeletes/'.$DiscussionID, 'Delete Popup');
         
         $Sender->EventArguments['SelectionMessage'] = &$SelectionMessage;
         $Sender->EventArguments['ActionMessage'] = &$ActionMessage;
         $Sender->EventArguments['Discussion'] = $Discussion;
         $Sender->FireEvent('BeforeCheckComments');
         $ActionMessage .= ' '.Anchor(T('Cancel'), 'vanilla/moderation/clearcommentselections/'.$DiscussionID.'/{TransientKey}/?Target={SelfUrl}', 'CancelAction');
         
         $Sender->InformMessage(
            $SelectionMessage
            .Wrap($ActionMessage, 'div', array('class' => 'Actions')),
            array(
               'CssClass' => 'NoDismiss',
               'id' => 'CheckSummary'
            )
         );
      } else if ($HadCheckedComments) {
         // Remove the message completely if there were previously checked comments in this discussion, but none now
         $Sender->InformMessage('', array('id' => 'CheckSummary'));
      }
   }
404100
protected function feedback_post_action(\cm_info $cm, $contextid, $userid, $eventnames, $after = false) {

        if (empty($this->activitylogs[$contextid][$userid])) {
            return false;
        }

        $logs = $this->activitylogs[$contextid][$userid];

        if (empty($logs['\mod_forum\event\assessable_uploaded'])) {
            // No feedback viewed if there is no submission.
            return false;
        }

        // First user post time.
        $firstpost = $logs['\mod_forum\event\assessable_uploaded']->timecreated[0];

        // We consider feedback any other user post in any of this forum discussions.
        foreach ($this->activitylogs[$contextid] as $anotheruserid => $logs) {
            if ($anotheruserid == $userid) {
                continue;
            }
            if (empty($logs['\mod_forum\event\assessable_uploaded'])) {
                continue;
            }
            $firstpostsenttime = $logs['\mod_forum\event\assessable_uploaded']->timecreated[0];

            if (parent::feedback_post_action($cm, $contextid, $userid, $eventnames, $firstpostsenttime)) {
                return true;
            }
            // Continue with the next user.
        }

        return false;
    }
725129
public function canJoinConversation($user, $conversation)
    {
        $thread = $this->find($conversation);

        if ($thread) {
            if (($thread->first_user_id == $user->id) || ($thread->second_user_id == $user->id)) {
                return true;
            }
        }

        return false;
    }
1303783
public function addComment($user, string $comment) : Comment
    {
        return $this->comments()->create([
            'user_id' => $user->id,
            'comment' => $comment,
        ]);
    }
832031
public function is_discussion_locked(discussion_entity $discussion) : bool {
        if ($discussion->is_locked()) {
            return true;
        }

        return $this->is_discussion_time_locked($discussion);
    }
1298165
public function can_pin_discussions(stdClass $user) : bool {
        return $this->forum->get_type() !== 'single' &&
                has_capability('mod/forum:pindiscussions', $this->get_context(), $user);
    }
236803
public function get_first_discussion_in_forum(forum_entity $forum) : ?discussion_entity {
        $records = $this->get_db()->get_records(self::TABLE, [
            'forum' => $forum->get_id(),
        ], 'timemodified ASC', '*', 0, 1);

        $records = $this->transform_db_records_to_entities($records);
        return count($records) ? array_shift($records) : null;
    }
464456
public function isEntityLocked(User $user, LockableEntityInterface $entity)
    {
        /** @var LockableEntity $lockable */
        $lockable = $this->getLockableEntity($entity);

        if ($this->lockEnabled) {
            $this->removeExpiredLocks($lockable);
            $locks = $this->getEntityVersionLocksByLockableEntity($lockable, $user);

            if ($locks === null || !count($locks)) {
                $this->createEntityVersionLock($user, $lockable);

                $lockable->setUpdated(new \DateTime());
                $this->objectManager->flush();

                return false;
            }

            return true;
        }

        return false;
    }
559900
public function get_discussion_view_first_unread_post_url_from_discussion(discussion_entity $discussion) {
        $viewurl = $this->get_discussion_view_url_from_discussion_id($discussion->get_id());
        $viewurl->set_anchor('unread');

        return $viewurl;
    }
947595
protected function feedback_submitted(\cm_info $cm, $contextid, $userid, $after = false) {
        if (empty($this->activitylogs[$contextid][$userid]) ||
                empty($this->activitylogs[$contextid][$userid]['\mod_lesson\event\lesson_ended'])) {
            return false;
        }

        // Multiple lesson attempts completed counts as submitted after feedback.
        return (2 >= count($this->activitylogs[$contextid][$userid]['\mod_lesson\event\lesson_ended']));
    }
280467
public function can_view_discussion(stdClass $user, discussion_entity $discussion) : bool {
        $forumrecord = $this->get_forum_record();
        $discussionrecord = $this->get_discussion_record($discussion);
        $context = $this->get_context();

        return forum_user_can_see_discussion($forumrecord, $discussionrecord, $context, $user);
    }
1276089
public function messagesSendResponse($token, $text, $discussion_id)
    {
        $params = array(
            'token'         => $token,
            'text'          => $text,
            'discussion_id' => $discussion_id
        );

        return $this->query('messages/send.json', $params, 'post');
    }
682571
public function must_post_before_viewing_discussion(stdClass $user, discussion_entity $discussion) : bool {
        $forum = $this->get_forum();

        if ($forum->get_type() === 'qanda') {
            // If it's a Q and A forum then the user must either have the capability to view without
            // posting or the user must have posted before they can view the discussion.
            return !has_capability('mod/forum:viewqandawithoutposting', $this->get_context(), $user) &&
                !forum_user_has_posted($forum->get_id(), $discussion->get_id(), $user->id);
        } else {
            // No other forum types require posting before viewing.
            return false;
        }
    }
971566
public function updateComment( $comment, $user=null, $time = null , $notified = null )
    {
        if ( $time === null )
        {
            $time = time();
        }

        $beforeUpdating = $this->beforeUpdatingComment( $comment, $notified, $time );
        if ( $beforeUpdating !== true )
        {
            return $beforeUpdating;
        }
        $comment->store();

        $afterUpdating = $this->afterUpdatingComment( $comment, $notified, $time );
        if ( $afterUpdating !== true )
        {
            return $afterUpdating;
        }
        return true;
    }
802424
public function can_split_discussions(stdClass $user) : bool {
        $forum = $this->get_forum();
        return $forum->get_type() !== 'single' && has_capability('mod/forum:splitdiscussions', $this->get_context(), $user);
    }