Class: DesignManagement::Design

Inherits:
ApplicationRecord show all
Includes:
AtomicInternalId, CacheMarkdownField, Gitlab::FileTypeDetection, Gitlab::Utils::StrongMemoize, Import::HasImportSource, Importable, Mentionable, Noteable, Participable, Referable, RelativePositioning, Subscribable, 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 Import::HasImportSource

Import::HasImportSource::IMPORT_SOURCES

Constants included from AtomicInternalId

AtomicInternalId::MissingValueError

Constants inherited from ApplicationRecord

ApplicationRecord::MAX_PLUCK

Constants included from HasCheckConstraints

HasCheckConstraints::NOT_NULL_CHECK_PATTERN

Constants included from ResetOnColumnErrors

ResetOnColumnErrors::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

#importing, #user_contributions

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Subscribable

#lazy_subscription, #set_subscription, #subscribe, #subscribed?, #subscribed_without_subscriptions?, #subscribers, #toggle_subscription, #unsubscribe

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, #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 Import::HasImportSource

#imported?

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, nullable_column?, 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 ResetOnColumnErrors

#reset_on_union_error, #reset_on_unknown_attribute_error

Methods included from Gitlab::SensitiveSerializableHash

#serializable_hash

Class Method Details

.build_full_path(issue, design) ⇒ Object



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

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


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

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



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

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

.relative_positioning_parent_columnObject



120
121
122
# File 'app/models/design_management/design.rb', line 120

def self.relative_positioning_parent_column
  :issue_id
end

.relative_positioning_query_base(design) ⇒ Object



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

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

.to_ability_nameObject



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

def self.to_ability_name
  'design'
end

Instance Method Details

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



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

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

#clear_version_cacheObject



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

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)


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

def deleted?
  most_recent_action&.deletion?
end

#diff_refsObject



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

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

#full_pathObject



199
200
201
# File 'app/models/design_management/design.rb', line 199

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

#most_recent_actionObject



151
152
153
# File 'app/models/design_management/design.rb', line 151

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

#new_design?Boolean

Returns:

  • (Boolean)


195
196
197
# File 'app/models/design_management/design.rb', line 195

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

#notes_with_associationsObject



233
234
235
# File 'app/models/design_management/design.rb', line 233

def notes_with_associations
  notes.includes(:author)
end

#repositoryObject



214
215
216
# File 'app/models/design_management/design.rb', line 214

def repository
  project.design_repository
end

#resource_parentObject

Part of the interface of objects we can create events about



229
230
231
# File 'app/models/design_management/design.rb', line 229

def resource_parent
  project
end

#statusObject



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

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"]


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

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



218
219
220
# File 'app/models/design_management/design.rb', line 218

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)


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

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