summaryrefslogtreecommitdiff
path: root/app/models/draft_note.rb
blob: 9f7977fce68a3f3d895fd5918f7f504b976c019d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# frozen_string_literal: true
class DraftNote < ApplicationRecord
  include DiffPositionableNote
  include Gitlab::Utils::StrongMemoize
  include Sortable
  include ShaAttribute

  PUBLISH_ATTRS = %i(noteable_id noteable_type type note).freeze
  DIFF_ATTRS = %i(position original_position change_position commit_id).freeze

  sha_attribute :commit_id

  # Attribute used to store quick actions changes and users referenced.
  attr_accessor :commands_changes
  attr_accessor :users_referenced

  # Text with quick actions filtered out
  attr_accessor :rendered_note

  attr_accessor :review

  belongs_to :author, class_name: 'User'
  belongs_to :merge_request

  validates :merge_request_id, presence: true
  validates :author_id, presence: true, uniqueness: { scope: [:merge_request_id, :discussion_id] }, if: :discussion_id?
  validates :discussion_id, allow_nil: true, format: { with: /\A\h{40}\z/ }
  validates :line_code, length: { maximum: 255 }, allow_nil: true

  scope :authored_by, ->(u) { where(author_id: u.id) }

  delegate :file_path, :file_hash, :file_identifier_hash, to: :diff_file, allow_nil: true

  def self.positions
    where.not(position: nil)
      .select(:position)
      .map(&:position)
  end

  def project
    merge_request.target_project
  end

  # noteable_id and noteable_type methods
  # are used to generate discussion_id on Discussion.discussion_id
  def noteable_id
    merge_request_id
  end

  def noteable
    merge_request
  end

  def noteable_type
    "MergeRequest"
  end

  def for_commit?
    commit_id.present?
  end

  def importing?
    false
  end

  def resolvable?
    false
  end

  def emoji_awardable?
    false
  end

  def on_diff?
    position&.complete?
  end

  def type
    return 'DiffNote' if on_diff?
    return 'DiscussionNote' if discussion_id.present?

    'Note'
  end

  def references
    {
      users: users_referenced,
      commands: commands_changes
    }
  end

  def line_code
    super.presence || find_line_code
  end

  def find_line_code
    write_attribute(:line_code, diff_file&.line_code_for_position(original_position))
  end

  def publish_params
    attrs = PUBLISH_ATTRS.dup
    attrs.concat(DIFF_ATTRS) if on_diff?
    params = slice(*attrs)
    params[:in_reply_to_discussion_id] = discussion_id if discussion_id.present?
    params[:review_id] = review.id if review.present?

    params
  end

  def self.preload_author(draft_notes)
    ActiveRecord::Associations::Preloader.new.preload(draft_notes, { author: :status })
  end

  def diff_file
    strong_memoize(:diff_file) do
      file = original_position&.diff_file(project.repository)

      file&.unfold_diff_lines(original_position)

      file
    end
  end

  def commit
    @commit ||= project.commit(commit_id) if commit_id.present?
  end
end