summaryrefslogtreecommitdiff
path: root/app/models/discussion.rb
blob: 27ed0480e6d014b832dc6622da4b33636ba4c0a3 (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
128
129
130
class Discussion
  cattr_accessor :memoized_values, instance_accessor: false do
    []
  end

  include ResolvableDiscussion

  attr_reader :notes, :noteable

  delegate  :created_at,
            :project,
            :author,

            :noteable,
            :for_commit?,
            :for_merge_request?,

            to: :first_note

  def self.build(notes, noteable = nil)
    notes.first.discussion_class(noteable).new(notes, noteable)
  end

  def self.build_collection(notes, noteable = nil)
    notes.group_by { |n| n.discussion_id(noteable) }.values.map { |notes| build(notes, noteable) }
  end

  def self.discussion_id(note)
    Digest::SHA1.hexdigest(build_discussion_id(note).join("-"))
  end

  # Optionally override the discussion ID at runtime depending on circumstances
  def self.override_discussion_id(note)
    nil
  end

  def self.build_discussion_id(note)
    noteable_id = note.noteable_id || note.commit_id
    [:discussion, note.noteable_type.try(:underscore), noteable_id]
  end

  def self.original_discussion_id(note)
    original_discussion_id = build_original_discussion_id(note)
    if original_discussion_id
      Digest::SHA1.hexdigest(original_discussion_id.join("-"))
    else
      note.discussion_id
    end
  end

  # Optionally build a separate original discussion ID that will never change,
  # if the main discussion ID _can_ change, like in the case of DiffDiscussion.
  def self.build_original_discussion_id(note)
    nil
  end

  def initialize(notes, noteable = nil)
    @notes = notes
    @noteable = noteable
  end

  def ==(other)
    other.class == self.class &&
      other.noteable == self.noteable &&
      other.id == self.id &&
      other.notes == self.notes
  end

  def last_updated_at
    last_note.created_at
  end

  def last_updated_by
    last_note.author
  end

  def id
    first_note.discussion_id(noteable)
  end

  alias_method :to_param, :id

  def original_id
    first_note.original_discussion_id
  end

  def diff_discussion?
    false
  end

  def individual_note?
    false
  end

  def new_discussion?
    notes.length == 1
  end

  def last_note
    @last_note ||= notes.last
  end

  def collapsed?
    resolved?
  end

  def expanded?
    !collapsed?
  end

  def reply_attributes
    first_note.slice(:type, :noteable_type, :noteable_id, :commit_id)
  end

  private

  def update
    # Do not select `Note.resolvable`, so that system notes remain in the collection
    notes_relation = Note.where(id: notes.map(&:id))

    yield(notes_relation)

    # Set the notes array to the updated notes
    @notes = notes_relation.fresh.to_a

    self.class.memoized_values.each do |var|
      instance_variable_set(:"@#{var}", nil)
    end
  end
end