<commit_before><?php

abstract class PhabricatorInlineCommentController
  extends PhabricatorController {

  private $containerObject;

  abstract protected function createComment();
  abstract protected function newInlineCommentQuery();
  abstract protected function loadCommentForDone($id);
  abstract protected function loadObjectOwnerPHID(
    PhabricatorInlineComment $inline);
  abstract protected function newContainerObject();

  final protected function getContainerObject() {
    if ($this->containerObject === null) {
      $object = $this->newContainerObject();
      if (!$object) {
        throw new Exception(
          pht(
            'Failed to load container object for inline comment.'));
      }
      $this->containerObject = $object;
    }

    return $this->containerObject;
  }

  protected function hideComments(array $ids) {
    throw new PhutilMethodNotImplementedException();
  }

  protected function showComments(array $ids) {
    throw new PhutilMethodNotImplementedException();
  }

  private $changesetID;
  private $isNewFile;
  private $isOnRight;
  private $lineNumber;
  private $lineLength;
  private $operation;
  private $commentID;
  private $renderer;
  private $replyToCommentPHID;

  public function getCommentID() {
    return $this->commentID;
  }

  public function getOperation() {
    return $this->operation;
  }

  public function getLineLength() {
    return $this->lineLength;
  }

  public function getLineNumber() {
    return $this->lineNumber;
  }

  public function getIsOnRight() {
    return $this->isOnRight;
  }

  public function getChangesetID() {
    return $this->changesetID;
  }

  public function getIsNewFile() {
    return $this->isNewFile;
  }

  public function setRenderer($renderer) {
    $this->renderer = $renderer;
    return $this;
  }

  public function getRenderer() {
    return $this->renderer;
  }

  public function setReplyToCommentPHID($phid) {
    $this->replyToCommentPHID = $phid;
    return $this;
  }

  public function getReplyToCommentPHID() {
    return $this->replyToCommentPHID;
  }

  public function processRequest() {
    $request = $this->getRequest();
    $viewer = $this->getViewer();

    if (!$request->validateCSRF()) {
      return new Aphront404Response();
    }

    $this->readRequestParameters();

    $op = $this->getOperation();
    switch ($op) {
      case 'hide':
      case 'show':
        $ids = $request->getStrList('ids');
        if ($ids) {
          if ($op == 'hide') {
            $this->hideComments($ids);
          } else {
            $this->showComments($ids);
          }
        }

        return id(new AphrontAjaxResponse())->setContent(array());
      case 'done':
        $inline = $this->loadCommentForDone($this->getCommentID());

        $is_draft_state = false;
        $is_checked = false;
        switch ($inline->getFixedState()) {
          case PhabricatorInlineComment::STATE_DRAFT:
            $next_state = PhabricatorInlineComment::STATE_UNDONE;
            break;
          case PhabricatorInlineComment::STATE_UNDRAFT:
            $next_state = PhabricatorInlineComment::STATE_DONE;
            $is_checked = true;
            break;
          case PhabricatorInlineComment::STATE_DONE:
            $next_state = PhabricatorInlineComment::STATE_UNDRAFT;
            $is_draft_state = true;
            break;
          default:
          case PhabricatorInlineComment::STATE_UNDONE:
            $next_state = PhabricatorInlineComment::STATE_DRAFT;
            $is_draft_state = true;
            $is_checked = true;
            break;
        }

        $inline->setFixedState($next_state)->save();

        return id(new AphrontAjaxResponse())
          ->setContent(
            array(
              'isChecked' => $is_checked,
              'draftState' => $is_draft_state,
            ));
      case 'delete':
      case 'undelete':
      case 'refdelete':
        // NOTE: For normal deletes, we just process the delete immediately
        // and show an "Undo" action. For deletes by reference from the
        // preview ("refdelete"), we prompt first (because the "Undo" may
        // not draw, or may not be easy to locate).

        if ($op == 'refdelete') {
          if (!$request->isFormPost()) {
            return $this->newDialog()
              ->setTitle(pht('Really delete comment?'))
              ->addHiddenInput('id', $this->getCommentID())
              ->addHiddenInput('op', $op)
              ->appendParagraph(pht('Delete this inline comment?'))
              ->addCancelButton('#')
              ->addSubmitButton(pht('Delete'));
          }
        }

        $is_delete = ($op == 'delete' || $op == 'refdelete');

        $inline = $this->loadCommentByIDForEdit($this->getCommentID());

        if ($is_delete) {
          $inline->setIsDeleted(1);
        } else {
          $inline->setIsDeleted(0);
        }

        $this->saveComment($inline);

        return $this->buildEmptyResponse();
      case 'edit':
      case 'save':
        $inline = $this->loadCommentByIDForEdit($this->getCommentID());
        if ($op === 'save') {
          $this->updateCommentContentState($inline);

          $inline->setIsEditing(false);

          if (!$inline->isVoidComment($viewer)) {
            $this->saveComment($inline);

            return $this->buildRenderedCommentResponse(
              $inline,
              $this->getIsOnRight());
          } else {
            $inline->setIsDeleted(1);

            $this->saveComment($inline);

            return $this->buildEmptyResponse();
          }
        } else {
          // NOTE: At time of writing, the "editing" state of inlines is
          // preserved by simulating a click on "Edit" when the inline loads.

          // In this case, we don't want to "saveComment()", because it
          // recalculates object drafts and purges versioned drafts.

          // The recalculation is merely unnecessary (state doesn't change)
          // but purging drafts means that loading a page and then closing it
          // discards your drafts.

          // To avoid the purge, only invoke "saveComment()" if we actually
          // have changes to apply.

          $is_dirty = false;
          if (!$inline->getIsEditing()) {
            $inline->setIsEditing(true);
            $is_dirty = true;
          }

          if ($this->hasContentState()) {
            $this->updateCommentContentState($inline);<commit_msg>When a new, deleted, draft inline is revived with "Undo", undelete it<commit_after><?php

abstract class PhabricatorInlineCommentController
  extends PhabricatorController {

  private $containerObject;

  abstract protected function createComment();
  abstract protected function newInlineCommentQuery();
  abstract protected function loadCommentForDone($id);
  abstract protected function loadObjectOwnerPHID(
    PhabricatorInlineComment $inline);
  abstract protected function newContainerObject();

  final protected function getContainerObject() {
    if ($this->containerObject === null) {
      $object = $this->newContainerObject();
      if (!$object) {
        throw new Exception(
          pht(
            'Failed to load container object for inline comment.'));
      }
      $this->containerObject = $object;
    }

    return $this->containerObject;
  }

  protected function hideComments(array $ids) {
    throw new PhutilMethodNotImplementedException();
  }

  protected function showComments(array $ids) {
    throw new PhutilMethodNotImplementedException();
  }

  private $changesetID;
  private $isNewFile;
  private $isOnRight;
  private $lineNumber;
  private $lineLength;
  private $operation;
  private $commentID;
  private $renderer;
  private $replyToCommentPHID;

  public function getCommentID() {
    return $this->commentID;
  }

  public function getOperation() {
    return $this->operation;
  }

  public function getLineLength() {
    return $this->lineLength;
  }

  public function getLineNumber() {
    return $this->lineNumber;
  }

  public function getIsOnRight() {
    return $this->isOnRight;
  }

  public function getChangesetID() {
    return $this->changesetID;
  }

  public function getIsNewFile() {
    return $this->isNewFile;
  }

  public function setRenderer($renderer) {
    $this->renderer = $renderer;
    return $this;
  }

  public function getRenderer() {
    return $this->renderer;
  }

  public function setReplyToCommentPHID($phid) {
    $this->replyToCommentPHID = $phid;
    return $this;
  }

  public function getReplyToCommentPHID() {
    return $this->replyToCommentPHID;
  }

  public function processRequest() {
    $request = $this->getRequest();
    $viewer = $this->getViewer();

    if (!$request->validateCSRF()) {
      return new Aphront404Response();
    }

    $this->readRequestParameters();

    $op = $this->getOperation();
    switch ($op) {
      case 'hide':
      case 'show':
        $ids = $request->getStrList('ids');
        if ($ids) {
          if ($op == 'hide') {
            $this->hideComments($ids);
          } else {
            $this->showComments($ids);
          }
        }

        return id(new AphrontAjaxResponse())->setContent(array());
      case 'done':
        $inline = $this->loadCommentForDone($this->getCommentID());

        $is_draft_state = false;
        $is_checked = false;
        switch ($inline->getFixedState()) {
          case PhabricatorInlineComment::STATE_DRAFT:
            $next_state = PhabricatorInlineComment::STATE_UNDONE;
            break;
          case PhabricatorInlineComment::STATE_UNDRAFT:
            $next_state = PhabricatorInlineComment::STATE_DONE;
            $is_checked = true;
            break;
          case PhabricatorInlineComment::STATE_DONE:
            $next_state = PhabricatorInlineComment::STATE_UNDRAFT;
            $is_draft_state = true;
            break;
          default:
          case PhabricatorInlineComment::STATE_UNDONE:
            $next_state = PhabricatorInlineComment::STATE_DRAFT;
            $is_draft_state = true;
            $is_checked = true;
            break;
        }

        $inline->setFixedState($next_state)->save();

        return id(new AphrontAjaxResponse())
          ->setContent(
            array(
              'isChecked' => $is_checked,
              'draftState' => $is_draft_state,
            ));
      case 'delete':
      case 'undelete':
      case 'refdelete':
        // NOTE: For normal deletes, we just process the delete immediately
        // and show an "Undo" action. For deletes by reference from the
        // preview ("refdelete"), we prompt first (because the "Undo" may
        // not draw, or may not be easy to locate).

        if ($op == 'refdelete') {
          if (!$request->isFormPost()) {
            return $this->newDialog()
              ->setTitle(pht('Really delete comment?'))
              ->addHiddenInput('id', $this->getCommentID())
              ->addHiddenInput('op', $op)
              ->appendParagraph(pht('Delete this inline comment?'))
              ->addCancelButton('#')
              ->addSubmitButton(pht('Delete'));
          }
        }

        $is_delete = ($op == 'delete' || $op == 'refdelete');

        $inline = $this->loadCommentByIDForEdit($this->getCommentID());

        if ($is_delete) {
          $inline->setIsDeleted(1);
        } else {
          $inline->setIsDeleted(0);
        }

        $this->saveComment($inline);

        return $this->buildEmptyResponse();
      case 'edit':
      case 'save':
        $inline = $this->loadCommentByIDForEdit($this->getCommentID());
        if ($op === 'save') {
          $this->updateCommentContentState($inline);

          $inline->setIsEditing(false);

          if (!$inline->isVoidComment($viewer)) {
            $inline->setIsDeleted(0);

            $this->saveComment($inline);

            return $this->buildRenderedCommentResponse(
              $inline,
              $this->getIsOnRight());
          } else {
            $inline->setIsDeleted(1);

            $this->saveComment($inline);

            return $this->buildEmptyResponse();
          }
        } else {
          // NOTE: At time of writing, the "editing" state of inlines is
          // preserved by simulating a click on "Edit" when the inline loads.

          // In this case, we don't want to "saveComment()", because it
          // recalculates object drafts and purges versioned drafts.

          // The recalculation is merely unnecessary (state doesn't change)
          // but purging drafts means that loading a page and then closing it
          // discards your drafts.

          // To avoid the purge, only invoke "saveComment()" if we actually
          // have changes to apply.

          $is_dirty = false;
          if (!$inline->getIsEditing()) {
            $inline
              ->setIsDeleted(0)
              ->setIsEditing(true);

            $is_dirty = true;
          }

          if ($this->hasContentState()) {
            $this->updateCommentContentState($inline);
{'fraction_non_alphanumeric': 0.11934471407793003, 'fraction_numerical': 0.0010717293117966777, 'mean_word_length': 2.3267125031830913, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 129, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '677217', 'n_tokens_mistral': 3676, 'n_tokens_neox': 3601, 'n_words': 855}