Class: DesignManagement::Design

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

Constant Summary

Constants included from CacheMarkdownField

CacheMarkdownField::INVALIDATED_BY

Constants included from Gitlab::RelativePositioning

Gitlab::RelativePositioning::IDEAL_DISTANCE, Gitlab::RelativePositioning::IllegalRange, Gitlab::RelativePositioning::InvalidPosition, Gitlab::RelativePositioning::IssuePositioningDisabled, Gitlab::RelativePositioning::MAX_GAP, Gitlab::RelativePositioning::MAX_POSITION, Gitlab::RelativePositioning::MIN_GAP, Gitlab::RelativePositioning::MIN_POSITION, Gitlab::RelativePositioning::NoSpaceLeft, Gitlab::RelativePositioning::START_POSITION, Gitlab::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

Constants included from AtomicInternalId

AtomicInternalId::MissingValueError

Constants inherited from ApplicationRecord

ApplicationRecord::MAX_PLUCK

Constants included from ResetOnUnionError

ResetOnUnionError::MAX_RESET_PERIOD

Instance Attribute Summary

Attributes included from CacheMarkdownField

#skip_markdown_cache_validation

Attributes included from Noteable

#system_note_timestamp

Attributes included from Importable

#imported, #importing

Class Method Summary collapse

Instance Method Summary collapse

Methods included from CacheMarkdownField

#attribute_invalidated?, #banzai_render_context, #cached_html_for, #cached_html_up_to_date?, #can_cache_field?, #invalidated_markdown_cache?, #latest_cached_markdown_version, #local_version, #mentionable_attributes_changed?, #mentioned_filtered_user_ids_for, #parent_user, #refresh_markdown_cache, #refresh_markdown_cache!, #rendered_field_content, #skip_project_check?, #store_mentions!, #updated_cached_html_for

Methods included from Participable

#participant?, #participants, #visible_participants

Methods included from RelativePositioning

#check_repositioning_allowed!, #could_not_move, #exclude_self, #model_class, #move_after, #move_before, #move_between, #move_to_end, #move_to_start, mover, #next_object_by_relative_position, #relative_positioning_scoped_items, #reset_relative_position, #update_relative_siblings

Methods included from Gitlab::RelativePositioning

range

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, #user_mention_class, #user_mention_identifier

Methods included from Referable

#referable_inspect, #reference_link_text, #to_reference_base

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, #broadcast_notes_changed, #capped_notes_count, #commenters, #creatable_note_email_address, #discussion_ids_relation, #discussion_notes, #discussion_root_note_ids, #discussions, #discussions_can_be_resolved_by?, #discussions_rendered_on_frontend?, #discussions_resolvable?, #discussions_resolved?, #discussions_to_be_resolved, #grouped_diff_discussions, #has_any_diff_note_positions?, #human_class_name, #lockable?, #noteable_target_type_name, #preloads_discussion_diff_highlighting?, #real_time_notes_enabled?, #resolvable_discussions, #supports_creating_notes_by_email?, #supports_discussions?, #supports_replying_to_individual_notes?, #supports_resolvable_notes?, #supports_suggestion?

Methods included from AtomicInternalId

group_init, #internal_id_read_scope, #internal_id_scope_attrs, #internal_id_scope_usage, namespace_init, project_init, scope_attrs, scope_usage

Methods inherited from ApplicationRecord

cached_column_list, #create_or_load_association, declarative_enum, default_select_columns, id_in, id_not_in, iid_in, pluck_primary_key, primary_key_in, #readable_by?, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, #to_ability_name, underscore, where_exists, where_not_exists, with_fast_read_statement_timeout, without_order

Methods included from SensitiveSerializableHash

#serializable_hash

Class Method Details

.build_full_path(issue, design) ⇒ Object



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

def self.build_full_path(issue, design)
  File.join(DesignManagement.designs_directory, "issue-#{issue.iid}", design.filename)
end


172
173
174
175
176
177
178
179
180
181
182
183
# File 'app/models/design_management/design.rb', line 172

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{[[:word:]\.\-\+]}
    filename_pattern = %r{
      (?<url_filename> #{valid_char}+ \. #{ext})
    }x

    compose_link_reference_pattern(path_segment, filename_pattern)
  end
end

.reference_patternObject



168
169
170
# File 'app/models/design_management/design.rb', line 168

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

.relative_positioning_parent_columnObject



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

def self.relative_positioning_parent_column
  :issue_id
end

.relative_positioning_query_base(design) ⇒ Object



114
115
116
# File 'app/models/design_management/design.rb', line 114

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



216
217
218
# File 'app/models/design_management/design.rb', line 216

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

#clear_version_cacheObject



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

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)


132
133
134
# File 'app/models/design_management/design.rb', line 132

def deleted?
  most_recent_action&.deletion?
end

#diff_refsObject



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

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

#full_pathObject



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

def full_path
  @full_path ||= self.class.build_full_path(issue, self)
end

#most_recent_actionObject



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

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

#new_design?Boolean

Returns:

  • (Boolean)


189
190
191
# File 'app/models/design_management/design.rb', line 189

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

#notes_with_associationsObject



227
228
229
# File 'app/models/design_management/design.rb', line 227

def notes_with_associations
  notes.includes(:author)
end

#repositoryObject



208
209
210
# File 'app/models/design_management/design.rb', line 208

def repository
  project.design_repository
end

#resource_parentObject

Part of the interface of objects we can create events about



223
224
225
# File 'app/models/design_management/design.rb', line 223

def resource_parent
  project
end

#statusObject



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

def status
  if new_design?
    :new
  elsif deleted?
    :deleted
  else
    :current
  end
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"]


161
162
163
164
165
166
# File 'app/models/design_management/design.rb', line 161

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



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

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)


139
140
141
142
143
144
145
146
147
# File 'app/models/design_management/design.rb', line 139

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