Class: DesignManagement::Design

Inherits:
ApplicationRecord show all
Includes:
Gitlab::FileTypeDetection, Gitlab::Utils::StrongMemoize, Importable, Mentionable, Noteable, Referable, RelativePositioning, WhereComposite
Defined in:
app/models/design_management/design.rb

Constant Summary

Constants included from RelativePositioning

RelativePositioning::IDEAL_DISTANCE, RelativePositioning::MAX_GAP, RelativePositioning::MAX_POSITION, RelativePositioning::MIN_GAP, RelativePositioning::MIN_POSITION, RelativePositioning::NoSpaceLeft, RelativePositioning::START_POSITION, RelativePositioning::STEPS

Constants included from Gitlab::FileTypeDetection

Gitlab::FileTypeDetection::DANGEROUS_AUDIO_EXT, Gitlab::FileTypeDetection::DANGEROUS_IMAGE_EXT, Gitlab::FileTypeDetection::DANGEROUS_VIDEO_EXT, Gitlab::FileTypeDetection::PDF_EXT, Gitlab::FileTypeDetection::SAFE_AUDIO_EXT, Gitlab::FileTypeDetection::SAFE_IMAGE_EXT, Gitlab::FileTypeDetection::SAFE_IMAGE_FOR_SCALING_EXT, Gitlab::FileTypeDetection::SAFE_VIDEO_EXT

Constants included from Noteable

Noteable::MAX_NOTES_LIMIT

Instance Attribute Summary

Attributes included from Noteable

#system_note_timestamp

Attributes included from Importable

#imported, #importing

Class Method Summary collapse

Instance Method Summary collapse

Methods included from RelativePositioning

#max_relative_position, #min_relative_position, #move_after, #move_before, #move_between, #move_sequence_after, #move_sequence_before, #move_to_end, #move_to_start, #next_relative_position, #prev_relative_position

Methods included from Mentionable

#all_references, #create_cross_references!, #create_new_cross_references!, #directly_addressed_users, #extractors, #gfm_reference, #local_reference, #matches_cross_reference_regex?, #mentioned_users, #referenced_group_users, #referenced_groups, #referenced_mentionables, #referenced_project_users, #referenced_projects, #referenced_users, #store_mentions!

Methods included from Referable

#referable_inspect, #reference_link_text, #to_reference_base

Methods included from Gitlab::Utils::StrongMemoize

#clear_memoization, #strong_memoize, #strong_memoized?

Methods included from Gitlab::FileTypeDetection

#audio?, #dangerous_audio?, #dangerous_embeddable?, #dangerous_image?, #dangerous_video?, #embeddable?, extension_match?, #image?, #image_safe_for_scaling?, #pdf?, #video?

Methods included from Noteable

#base_class_name, #capped_notes_count, #discussion_ids_relation, #discussion_notes, #discussions, #discussions_can_be_resolved_by?, #discussions_rendered_on_frontend?, #discussions_resolvable?, #discussions_resolved?, #discussions_to_be_resolved, #etag_caching_enabled?, #expire_note_etag_cache, #grouped_diff_discussions, #has_any_diff_note_positions?, #human_class_name, #lockable?, #note_etag_key, #preloads_discussion_diff_highlighting?, #resolvable_discussions, #supports_discussions?, #supports_replying_to_individual_notes?, #supports_resolvable_notes?, #supports_suggestion?

Methods inherited from ApplicationRecord

at_most, id_in, id_not_in, iid_in, pluck_primary_key, primary_key_in, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, underscore, without_order

Class Method Details


157
158
159
160
161
162
163
164
165
166
167
168
# File 'app/models/design_management/design.rb', line 157

def self.link_reference_pattern
  @link_reference_pattern ||= begin
    path_segment = %r{issues/#{Gitlab::Regex.issue}/designs}
    ext = Regexp.new(Regexp.union(SAFE_IMAGE_EXT + DANGEROUS_IMAGE_EXT).source, Regexp::IGNORECASE)
    valid_char = %r{[^/\s]} # any char that is not a forward slash or whitespace
    filename_pattern = %r{
      (?<url_filename> #{valid_char}+ \. #{ext})
    }x

    super(path_segment, filename_pattern)
  end
end

.reference_patternObject


153
154
155
# File 'app/models/design_management/design.rb', line 153

def self.reference_pattern
  # no-op: We only support link_reference_pattern parsing
end

.relative_positioning_parent_columnObject


103
104
105
# File 'app/models/design_management/design.rb', line 103

def self.relative_positioning_parent_column
  :issue_id
end

.relative_positioning_query_base(design) ⇒ Object


99
100
101
# File 'app/models/design_management/design.rb', line 99

def self.relative_positioning_query_base(design)
  default_scoped.on_issue(design.issue_id)
end

Instance Method Details

#after_note_changed(note) ⇒ Object Also known as: after_note_created, after_note_destroyed


205
206
207
# File 'app/models/design_management/design.rb', line 205

def after_note_changed(note)
  user_notes_count_service.delete_cache unless note.system?
end

#clear_version_cacheObject


190
191
192
193
194
195
# File 'app/models/design_management/design.rb', line 190

def clear_version_cache
  [versions, actions].each(&:reset)
  %i[new_design diff_refs head_sha visible_in most_recent_action].each do |key|
    clear_memoization(key)
  end
end

#deleted?Boolean

Returns:

  • (Boolean)

117
118
119
# File 'app/models/design_management/design.rb', line 117

def deleted?
  most_recent_action&.deletion?
end

#descriptionObject


174
175
176
# File 'app/models/design_management/design.rb', line 174

def description
  ''
end

#diff_refsObject


186
187
188
# File 'app/models/design_management/design.rb', line 186

def diff_refs
  strong_memoize(:diff_refs) { head_version&.diff_refs }
end

#full_pathObject


182
183
184
# File 'app/models/design_management/design.rb', line 182

def full_path
  @full_path ||= File.join(DesignManagement.designs_directory, "issue-#{issue.iid}", filename)
end

#immediately_before?(next_design) ⇒ Boolean

Returns:

  • (Boolean)

216
217
218
219
220
221
222
223
224
225
# File 'app/models/design_management/design.rb', line 216

def immediately_before?(next_design)
  return false if next_design.relative_position <= relative_position

  interloper = self.class.on_issue(issue).where(
    "relative_position <@ int4range(?, ?, '()')",
    *[self, next_design].map(&:relative_position)
  )

  !interloper.exists?
end

#most_recent_actionObject


134
135
136
# File 'app/models/design_management/design.rb', line 134

def most_recent_action
  strong_memoize(:most_recent_action) { actions.ordered.last }
end

#new_design?Boolean

Returns:

  • (Boolean)

178
179
180
# File 'app/models/design_management/design.rb', line 178

def new_design?
  strong_memoize(:new_design) { actions.none? }
end

#repositoryObject


197
198
199
# File 'app/models/design_management/design.rb', line 197

def repository
  project.design_repository
end

#resource_parentObject

Part of the interface of objects we can create events about


212
213
214
# File 'app/models/design_management/design.rb', line 212

def resource_parent
  project
end

#statusObject


107
108
109
110
111
112
113
114
115
# File 'app/models/design_management/design.rb', line 107

def status
  if new_design?
    :new
  elsif deleted?
    :deleted
  else
    :current
  end
end

#to_ability_nameObject


170
171
172
# File 'app/models/design_management/design.rb', line 170

def to_ability_name
  'design'
end

#to_reference(from = nil, full: false) ⇒ Object

A reference for a design is the issue reference, indexed by the filename with an optional infix when full.

e.g.

#123[homescreen.png]
other-project#72[sidebar.jpg]
#38/designs[transition.gif]
#12["filename with [] in it.jpg"]

146
147
148
149
150
151
# File 'app/models/design_management/design.rb', line 146

def to_reference(from = nil, full: false)
  infix = full ? '/designs' : ''
  safe_name = Sanitize.fragment(filename)

  "#{issue.to_reference(from, full: full)}#{infix}[#{safe_name}]"
end

#user_notes_countObject


201
202
203
# File 'app/models/design_management/design.rb', line 201

def user_notes_count
  user_notes_count_service.count
end

#visible_in?(version) ⇒ Boolean

A design is visible_in? a version if:

* it was created before that version
* the most recent action before the version was not a deletion

Returns:

  • (Boolean)

124
125
126
127
128
129
130
131
132
# File 'app/models/design_management/design.rb', line 124

def visible_in?(version)
  map = strong_memoize(:visible_in) do
    Hash.new do |h, k|
      h[k] = self.class.visible_at_version(k).where(id: id).exists?
    end
  end

  map[version]
end