1# frozen_string_literal: true 2class DraftNote < ApplicationRecord 3 include DiffPositionableNote 4 include Gitlab::Utils::StrongMemoize 5 include Sortable 6 include ShaAttribute 7 8 PUBLISH_ATTRS = %i(noteable_id noteable_type type note).freeze 9 DIFF_ATTRS = %i(position original_position change_position commit_id).freeze 10 11 sha_attribute :commit_id 12 13 # Attribute used to store quick actions changes and users referenced. 14 attr_accessor :commands_changes 15 attr_accessor :users_referenced 16 17 # Text with quick actions filtered out 18 attr_accessor :rendered_note 19 20 attr_accessor :review 21 22 belongs_to :author, class_name: 'User' 23 belongs_to :merge_request 24 25 validates :merge_request_id, presence: true 26 validates :author_id, presence: true, uniqueness: { scope: [:merge_request_id, :discussion_id] }, if: :discussion_id? 27 validates :discussion_id, allow_nil: true, format: { with: /\A\h{40}\z/ } 28 29 scope :authored_by, ->(u) { where(author_id: u.id) } 30 31 delegate :file_path, :file_hash, :file_identifier_hash, to: :diff_file, allow_nil: true 32 33 def self.positions 34 where.not(position: nil) 35 .select(:position) 36 .map(&:position) 37 end 38 39 def project 40 merge_request.target_project 41 end 42 43 # noteable_id and noteable_type methods 44 # are used to generate discussion_id on Discussion.discussion_id 45 def noteable_id 46 merge_request_id 47 end 48 49 def noteable 50 merge_request 51 end 52 53 def noteable_type 54 "MergeRequest" 55 end 56 57 def for_commit? 58 commit_id.present? 59 end 60 61 def importing? 62 false 63 end 64 65 def resolvable? 66 false 67 end 68 69 def emoji_awardable? 70 false 71 end 72 73 def on_diff? 74 position&.complete? 75 end 76 77 def type 78 return 'DiffNote' if on_diff? 79 return 'DiscussionNote' if discussion_id.present? 80 81 'Note' 82 end 83 84 def references 85 { 86 users: users_referenced, 87 commands: commands_changes 88 } 89 end 90 91 def line_code 92 @line_code ||= diff_file&.line_code_for_position(original_position) 93 end 94 95 def publish_params 96 attrs = PUBLISH_ATTRS.dup 97 attrs.concat(DIFF_ATTRS) if on_diff? 98 params = slice(*attrs) 99 params[:in_reply_to_discussion_id] = discussion_id if discussion_id.present? 100 params[:review_id] = review.id if review.present? 101 102 params 103 end 104 105 def self.preload_author(draft_notes) 106 ActiveRecord::Associations::Preloader.new.preload(draft_notes, { author: :status }) 107 end 108 109 def diff_file 110 strong_memoize(:diff_file) do 111 file = original_position&.diff_file(project.repository) 112 113 file&.unfold_diff_lines(original_position) 114 115 file 116 end 117 end 118 119 def commit 120 @commit ||= project.commit(commit_id) if commit_id.present? 121 end 122end 123