diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-04 15:09:39 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-04 15:09:39 +0300 |
commit | 8322f051740fba113c5c1f6fba96b9c943240746 (patch) | |
tree | bc695dfd5538f9378041f4a4fa6bd097ecf58954 /app/models/concerns/cache_markdown_field.rb | |
parent | f9fe7cda4bdbc477d8d76e5def4023f7d03bab46 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/models/concerns/cache_markdown_field.rb')
-rw-r--r-- | app/models/concerns/cache_markdown_field.rb | 62 |
1 files changed, 59 insertions, 3 deletions
diff --git a/app/models/concerns/cache_markdown_field.rb b/app/models/concerns/cache_markdown_field.rb index 49fc780f372..45944401c2d 100644 --- a/app/models/concerns/cache_markdown_field.rb +++ b/app/models/concerns/cache_markdown_field.rb @@ -70,8 +70,12 @@ module CacheMarkdownField def refresh_markdown_cache! updates = refresh_markdown_cache - - save_markdown(updates) + if updates.present? && save_markdown(updates) + # save_markdown updates DB columns directly, so compute and save mentions + # by calling store_mentions! or we end-up with missing mentions although those + # would appear in the notes, descriptions, etc in the UI + store_mentions! if mentionable_attributes_changed?(updates) + end end def cached_html_up_to_date?(markdown_field) @@ -106,7 +110,19 @@ module CacheMarkdownField def updated_cached_html_for(markdown_field) return unless cached_markdown_fields.markdown_fields.include?(markdown_field) - refresh_markdown_cache! if attribute_invalidated?(cached_markdown_fields.html_field(markdown_field)) + if attribute_invalidated?(cached_markdown_fields.html_field(markdown_field)) + # Invalidated due to Markdown content change + # We should not persist the updated HTML here since this will depend on whether the + # Markdown content change will be persisted. Both will be persisted together when the model is saved. + if changed_attributes.key?(markdown_field) + refresh_markdown_cache + else + # Invalidated due to stale HTML cache + # This could happen when the Markdown cache version is bumped or when a model is imported and the HTML is empty. + # We persist the updated HTML here so that subsequent calls to this method do not have to regenerate the HTML again. + refresh_markdown_cache! + end + end cached_html_for(markdown_field) end @@ -140,6 +156,46 @@ module CacheMarkdownField nil end + def store_mentions! + refs = all_references(self.author) + + references = {} + references[:mentioned_users_ids] = refs.mentioned_users&.pluck(:id).presence + references[:mentioned_groups_ids] = refs.mentioned_groups&.pluck(:id).presence + references[:mentioned_projects_ids] = refs.mentioned_projects&.pluck(:id).presence + + # One retry is enough as next time `model_user_mention` should return the existing mention record, + # that threw the `ActiveRecord::RecordNotUnique` exception in first place. + self.class.safe_ensure_unique(retries: 1) do + user_mention = model_user_mention + + # this may happen due to notes polymorphism, so noteable_id may point to a record + # that no longer exists as we cannot have FK on noteable_id + break if user_mention.blank? + + user_mention.mentioned_users_ids = references[:mentioned_users_ids] + user_mention.mentioned_groups_ids = references[:mentioned_groups_ids] + user_mention.mentioned_projects_ids = references[:mentioned_projects_ids] + + if user_mention.has_mentions? + user_mention.save! + else + user_mention.destroy! + end + end + + true + end + + def mentionable_attributes_changed?(changes = saved_changes) + return false unless is_a?(Mentionable) + + self.class.mentionable_attrs.any? do |attr| + changes.key?(cached_markdown_fields.html_field(attr.first)) && + changes.fetch(cached_markdown_fields.html_field(attr.first)).last.present? + end + end + included do cattr_reader :cached_markdown_fields do Gitlab::MarkdownCache::FieldData.new |