thredded 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b89649352c4f5481a4e2ad05a885e21a2bb9a5d0
4
- data.tar.gz: 4b7bf4007f49a57fbf4a00b176750cb700a8a801
3
+ metadata.gz: 868d81f0b7ff77d6ae58e572377f1001be7131b7
4
+ data.tar.gz: f23376c4be14345f85932348d1b9745322ac642a
5
5
  SHA512:
6
- metadata.gz: d2e4a2b77cd7495e279b80e910c20a28f236e1103974410ec3572cb0b99c482ec662f3eb5951f4f7cda7b4e88f5a8f6cdf4c430c363bcd63cc78384a58a5fae1
7
- data.tar.gz: d36788984d19723bb7607042e2675d3da6a9103b76d2e550a8797e557e53ac4493fc2f6aee8d6496920e0dc24cbbffcd3b6bd9e96357ec3d07eb0dfb0fdc9fb7
6
+ metadata.gz: 11bf79cf05bbf641a8c78540d6d07c2522dbb6ba660de178bdbbe1d98a18958b0edbc4360eaf74b71bb6db71f3f60717eb945326791ae03903f0cf64d1fc780e
7
+ data.tar.gz: 12b1603c89e6e4660d67fb7a6ed90993c42d2edd408a261d8b15f107e201d1a47dbff2b157ad94628e74713cf9d4607f1ae2a10fcbdbf86b36b49a4dac6a5f95
data/CHANGELOG.mkdn CHANGED
@@ -1,3 +1,18 @@
1
+ # v0.6.1
2
+
3
+ This is a minor bugfix release.
4
+
5
+ ## Added
6
+
7
+ * Adds an Activity tab to moderation, with a list of all the forum topics and posts, most recent first.
8
+
9
+ ## Fixed
10
+
11
+ * Moderation history rendering of deleted content.
12
+ * Various bugs in @-mentions and highlighting.
13
+
14
+ See the full list of changes here: https://github.com/thredded/thredded/compare/v0.6.0...v0.6.1.
15
+
1
16
  # 0.6.0 - 2016-06-12
2
17
 
3
18
  **NB:** If updating to this version from 0.5.x, you will need to copy and run [this migration](https://github.com/thredded/thredded/blob/66f64068b9501ff4e8686c95894b6795aae6082f/db/upgrade_migrations/20160611094616_upgrade_v0_5_to_v0_6.rb).
data/README.mkdn CHANGED
@@ -44,7 +44,7 @@ application and not an engine like Thredded.
44
44
  Add the gem to your Gemfile:
45
45
 
46
46
  ```ruby
47
- gem 'thredded', '~> 0.6.0'
47
+ gem 'thredded', '~> 0.6.1'
48
48
  ```
49
49
 
50
50
  Add the Thredded [initializer] to your parent app by running the install generator.
@@ -154,11 +154,12 @@ Thredded does not provide a user's profile page, but it provides a helper for re
154
154
  in your app's user profile page.
155
155
 
156
156
  To use it:
157
+
157
158
  1. Include `Thredded::ApplicationHelper` in the app's helpers module.
158
159
  2. Render the partial like this:
159
160
 
160
161
  ```erb
161
- <%= render 'thredded/users/_posts',
162
+ <%= render 'thredded/users/posts',
162
163
  posts: Thredded.posts_page_view(
163
164
  scope: user.thredded_posts.order_newest_first.limit(5),
164
165
  current_user: current_user) %>
@@ -11,7 +11,8 @@
11
11
  .thredded--pending-moderation &--moderation-navigation--pending,
12
12
  .thredded--moderation-history &--moderation-navigation--history,
13
13
  .thredded--moderation-users &--moderation-navigation--users,
14
- .thredded--moderation-user &--moderation-navigation--users{
14
+ .thredded--moderation-user &--moderation-navigation--users,
15
+ .thredded--moderation-activity &--moderation-navigation--activity {
15
16
  @extend %thredded--nav-tabs--item-current;
16
17
  }
17
18
 
@@ -13,7 +13,8 @@
13
13
  .thredded--pending-moderation &--user-navigation--moderation,
14
14
  .thredded--moderation-history &--user-navigation--moderation,
15
15
  .thredded--moderation-users &--user-navigation--moderation,
16
- .thredded--moderation-user &--user-navigation--moderation {
16
+ .thredded--moderation-user &--user-navigation--moderation,
17
+ .thredded--moderation-activity &--user-navigation--moderation {
17
18
  @extend %thredded--nav-tabs--item-current;
18
19
  }
19
20
 
@@ -1,16 +1,23 @@
1
1
  # frozen_string_literal: true
2
+ require_dependency 'html/pipeline/at_mention_filter'
2
3
  module Thredded
3
4
  class AtNotificationExtractor
4
- # Matches the names in @joe, @"Joe 1", but not email@host.com.
5
- # The matched name is captured and may contain the surrounding quotes.
6
- MATCH_NAME_RE = /(?:^|[\s>])@([\w]+|"[\w ]+")(?=\W|$)/
7
-
8
- def initialize(content)
9
- @content = content
5
+ def initialize(post)
6
+ @post = post
10
7
  end
11
8
 
9
+ # @return [Array<Thredded.user_class>]
12
10
  def run
13
- @content.scan(MATCH_NAME_RE).map(&:first).map { |m| m.start_with?('"') ? m[1..-2] : m }.uniq
11
+ view_context = Thredded::ApplicationController.new.view_context
12
+ # Do not highlight @-mentions at first, because:
13
+ # * When parsing, @-mentions within <a> tags will not be considered.
14
+ # * We can't always generate the user URL here because request.host is not available.
15
+ html = @post.filtered_content(view_context, users_provider: nil)
16
+ HTML::Pipeline::AtMentionFilter.new(
17
+ html,
18
+ view_context: view_context,
19
+ users_provider: -> (user_names) { @post.readers_from_user_names(user_names).to_a }
20
+ ).mentioned_users
14
21
  end
15
22
  end
16
23
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require_dependency 'thredded/at_notification_extractor'
2
3
  module Thredded
3
4
  class AutofollowMentionedUsers
4
5
  def initialize(post)
@@ -12,10 +13,9 @@ module Thredded
12
13
  end
13
14
 
14
15
  def autofollowers
15
- user_names = Thredded::AtNotificationExtractor.new(post.content).run
16
- autofollowers = post.readers_from_user_names(user_names).to_a
17
- autofollowers.delete post.user
18
- exclude_those_opting_out_of_at_notifications(autofollowers)
16
+ autofollowers = Thredded::AtNotificationExtractor.new(post).run
17
+ autofollowers.delete(post.user)
18
+ exclude_those_opting_out_of_at_notifications autofollowers
19
19
  end
20
20
 
21
21
  private
@@ -26,6 +26,19 @@ module Thredded
26
26
  .page(current_page)
27
27
  end
28
28
 
29
+ def activity
30
+ @posts = PostsPageView.new(
31
+ thredded_current_user,
32
+ moderatable_posts
33
+ .order_newest_first
34
+ .preload(:user, :postable)
35
+ .page(current_page)
36
+ )
37
+ if flash[:last_moderated_record_id]
38
+ @last_moderated_record = accessible_post_moderation_records.find(flash[:last_moderated_record_id].to_i)
39
+ end
40
+ end
41
+
29
42
  def moderate_post
30
43
  return head(:bad_request) unless Thredded::Post.moderation_states.include?(params[:moderation_state])
31
44
  flash[:last_moderated_record_id] = ModeratePost.run!(
@@ -25,11 +25,8 @@ module Thredded
25
25
 
26
26
  # @param view_context [Object] the context of the rendering view.
27
27
  # @return [String] formatted and sanitized html-safe post content.
28
- def filtered_content(view_context)
29
- Thredded::ContentFormatter.new(
30
- view_context,
31
- users_provider: -> (names) { readers_from_user_names(names) }
32
- ).format_content(content)
28
+ def filtered_content(view_context, users_provider: -> (names) { readers_from_user_names(names) })
29
+ Thredded::ContentFormatter.new(view_context, users_provider: users_provider).format_content(content)
33
30
  end
34
31
 
35
32
  private
@@ -4,7 +4,7 @@ module Thredded
4
4
  include ModerationState
5
5
 
6
6
  belongs_to :user, class_name: Thredded.user_class, inverse_of: :thredded_user_detail
7
- validates :user_id, presence: true
7
+ validates :user_id, presence: true, uniqueness: true
8
8
 
9
9
  has_many :topics, class_name: 'Thredded::Topic', foreign_key: :user_id, primary_key: :user_id
10
10
  has_many :private_topics, class_name: 'Thredded::PrivateTopic', foreign_key: :user_id, primary_key: :user_id
@@ -3,7 +3,7 @@ module Thredded
3
3
  class UserTopicFollow < ActiveRecord::Base
4
4
  enum reason: [:manual, :posted, :mentioned]
5
5
 
6
- belongs_to :user, inverse_of: :thredded_topic_follows
6
+ belongs_to :user, inverse_of: :thredded_topic_follows, class_name: Thredded.user_class
7
7
  belongs_to :topic, inverse_of: :user_follows
8
8
 
9
9
  validates :user_id, presence: true
@@ -7,6 +7,9 @@
7
7
  <li class="thredded--moderation-navigation--item thredded--moderation-navigation--history">
8
8
  <%= link_to t('thredded.nav.moderation_history'), moderation_history_path %>
9
9
  </li>
10
+ <li class="thredded--moderation-navigation--item thredded--moderation-navigation--activity">
11
+ <%= link_to t('thredded.nav.moderation_activity'), moderation_activity_path %>
12
+ </li>
10
13
  <li class="thredded--moderation-navigation--item thredded--moderation-navigation--users">
11
14
  <%= link_to t('thredded.nav.moderation_users'), users_moderation_path %>
12
15
  </li>
@@ -10,5 +10,10 @@
10
10
  %>
11
11
  <%= render 'thredded/posts_common/content', post: post %>
12
12
  <%= render 'thredded/posts_common/actions', post: post %>
13
+ <% if post.blocked? %>
14
+ <p class="thredded--alert thredded--alert-danger">
15
+ <%= render 'thredded/shared/content_moderation_blocked_state', moderation_record: post.last_moderation_record %>
16
+ </p>
17
+ <% end %>
13
18
  <%= render 'post_moderation_actions', post: post %>
14
19
  <% end %>
@@ -23,12 +23,12 @@
23
23
  <%= t('thredded.moderation.posts_content_changed_since_moderation_html', post_url: post_permalink_path(post)) %>
24
24
  </p>
25
25
  <% end %>
26
- <%= t 'thredded.moderation.post_deleted_notice' unless post %>
26
+ <%= content_tag :em, t('thredded.moderation.post_deleted_notice') unless post %>
27
27
  </header>
28
28
  <article class="thredded--post">
29
29
  <% post_user_link = capture do %>
30
- <% if post.user %>
31
- <%= link_to post.user, user_moderation_path(post.user.id) %>
30
+ <% if record.post_user %>
31
+ <%= link_to record.post_user, user_moderation_path(record.post_user.id) %>
32
32
  <% else %>
33
33
  <%= safe_join [record.post_user_name, content_tag(:em, t('thredded.null_user_name'))].compact, ', ' %>
34
34
  <% end %>
@@ -3,5 +3,10 @@
3
3
  <%= render 'thredded/posts_common/header_with_topic', post: post %>
4
4
  <%= render 'thredded/posts_common/content', post: post %>
5
5
  <%= render 'thredded/posts_common/actions', post: post %>
6
+ <% if post.blocked? %>
7
+ <p class="thredded--alert thredded--alert-danger">
8
+ <%= render 'thredded/shared/content_moderation_blocked_state', moderation_record: post.last_moderation_record %>
9
+ </p>
10
+ <% end %>
6
11
  <%= render 'post_moderation_actions', post: post %>
7
12
  <% end %>
@@ -0,0 +1,18 @@
1
+ <% content_for :thredded_page_title, t('thredded.nav.moderation') %>
2
+ <% content_for :thredded_page_id, 'thredded--moderation-activity' %>
3
+ <%= render 'nav' %>
4
+
5
+ <%= thredded_page do %>
6
+ <h1><%= t 'thredded.recent_activity' %></h1>
7
+ <%= content_tag :section, class: 'thredded--main-section' do %>
8
+ <% if @last_moderated_record %>
9
+ <div class="thredded--moderated-notice">
10
+ <%= render 'post_moderation_record', post_moderation_record: @last_moderated_record %>
11
+ </div>
12
+ <% end %>
13
+ <% if @posts.present? %>
14
+ <%= render partial: 'post', collection: @posts %>
15
+ <%= paginate @posts %>
16
+ <% end %>
17
+ <% end %>
18
+ <% end %>
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  en:
3
3
  thredded:
4
+ recent_activity: Recent activity
4
5
  errors:
5
6
  login_required: Please sign in first.
6
7
  not_authorized: You are not authorized to access this page.
@@ -9,7 +10,7 @@ en:
9
10
  form:
10
11
  update: Update
11
12
  content_moderation_states:
12
- content_blocked_notice: Blocked by a moderator
13
+ content_blocked_notice: Blocked
13
14
  content_blocked_notice_with_record_html: Blocked by %{moderator} %{time_ago}
14
15
  messageboard:
15
16
  create: Create a New Messageboard
@@ -51,6 +52,7 @@ en:
51
52
  moderation_history: History
52
53
  moderation_pending: Pending
53
54
  moderation_users: Users
55
+ moderation_activity: Activity
54
56
  private_topics: Private Messages
55
57
  settings: Notification Settings
56
58
  null_user_name: Deleted user
@@ -140,7 +142,7 @@ en:
140
142
  users:
141
143
  last_active_html: "Last active %{time_ago}"
142
144
  posted_in_topic_html: "Posted in %{topic_link}"
143
- recent_activity: Recent activity
145
+ recent_activity: :thredded.recent_activity
144
146
  started_topic_html: "Started %{topic_link}"
145
147
  user_posted_in_topic_html: "%{user_link} posted in %{topic_link}"
146
148
  user_since_html: "User since %{time_ago}"
@@ -2,7 +2,7 @@
2
2
  pt-BR:
3
3
  thredded:
4
4
  content_moderation_states:
5
- content_blocked_notice: Bloqueado por um moderador
5
+ content_blocked_notice: Bloqueado
6
6
  content_blocked_notice_with_record_html: Bloqueados por %{moderator} %{time_ago}
7
7
  errors:
8
8
  login_required: Por favor, autentique-se primeiro.
@@ -48,6 +48,7 @@ pt-BR:
48
48
  edit_private_topic: :thredded.nav.edit_topic
49
49
  edit_topic: Editar
50
50
  moderation: Moderação
51
+ moderation_activity: Atividade
51
52
  moderation_history: História
52
53
  moderation_pending: Pendente
53
54
  moderation_users: Usuários
@@ -108,6 +109,7 @@ pt-BR:
108
109
  create_btn: Inicie sua primeira conversa privada
109
110
  title: Você não possui mensagens privadas.
110
111
  updated_notice: Título atualizado
112
+ recent_activity: Atividade recente
111
113
  search:
112
114
  form:
113
115
  btn_submit: :thredded.search.form.label
@@ -144,7 +146,7 @@ pt-BR:
144
146
  posts_count:
145
147
  one: Postado uma vez
146
148
  other: vezes %{count} Publicado
147
- recent_activity: Atividade recente
149
+ recent_activity: :thredded.recent_activity
148
150
  started_topic_html: Começou %{topic_link}
149
151
  started_topics_count:
150
152
  one: Começou um tópico
data/config/routes.rb CHANGED
@@ -35,6 +35,7 @@ Thredded::Engine.routes.draw do
35
35
  get '/history(/page-:page)', action: :history, as: :moderation_history
36
36
  get '/users(/page-:page)', action: :users, as: :users_moderation
37
37
  get '/users/:id(/page-:page)', action: :user, as: :user_moderation
38
+ get '/activity(/page-:page)', action: :activity, as: :moderation_activity
38
39
  end
39
40
  post '', action: :moderate_post, as: :moderate_post
40
41
  post '/user/:id', action: :moderate_user, as: :moderate_user
data/heroku.gemfile.lock CHANGED
@@ -9,7 +9,7 @@ GIT
9
9
  PATH
10
10
  remote: .
11
11
  specs:
12
- thredded (0.6.0)
12
+ thredded (0.6.1)
13
13
  active_record_union (>= 1.1.1)
14
14
  autoprefixer-rails
15
15
  autosize-rails
@@ -30,7 +30,6 @@ PATH
30
30
  rails (>= 4.2.0)
31
31
  rails-timeago
32
32
  rb-gravatar
33
- rinku
34
33
  sanitize
35
34
  sass (>= 3.4.21)
36
35
  select2-rails (~> 3.5)
@@ -212,7 +211,6 @@ GEM
212
211
  rb-gravatar (1.0.5)
213
212
  ref (2.0.0)
214
213
  request_store (1.3.1)
215
- rinku (2.0.0)
216
214
  rollbar (2.11.5)
217
215
  multi_json
218
216
  sanitize (4.0.1)
@@ -228,7 +226,7 @@ GEM
228
226
  tilt (>= 1.1, < 3)
229
227
  select2-rails (3.5.10)
230
228
  thor (~> 0.14)
231
- sprockets (3.6.0)
229
+ sprockets (3.6.1)
232
230
  concurrent-ruby (~> 1.0)
233
231
  rack (> 1, < 3)
234
232
  sprockets-es6 (0.9.0)
@@ -1,23 +1,76 @@
1
1
  # frozen_string_literal: true
2
- require 'thredded/at_users'
3
-
4
2
  module HTML
5
3
  class Pipeline
6
4
  class AtMentionFilter < Filter
5
+ DEFAULT_IGNORED_ANCESTOR_TAGS = %w(pre code tt a style).freeze
6
+
7
7
  # @param context [Hash]
8
8
  # @options context :users_provider [#call(usernames)] given usernames, returns a list of users.
9
- def initialize(text, context = nil, result = nil)
10
- super text, context, result
11
- @text = text.to_s.delete("\r")
9
+ def initialize(doc, context = nil, result = nil)
10
+ super doc, context, result
12
11
  @users_provider = context[:users_provider]
13
12
  @view_context = context[:view_context]
14
13
  end
15
14
 
16
15
  def call
17
- return html unless @users_provider
18
- html = Thredded::AtUsers.render(@text, @users_provider, @view_context)
19
- html.rstrip!
20
- html
16
+ return doc unless @users_provider
17
+ process_text_nodes! do |node|
18
+ content = node.to_html
19
+ next unless content.include?('@')
20
+ highlight! content
21
+ node.replace content
22
+ end
23
+ doc
24
+ end
25
+
26
+ # @return [Array<Thredded.user_class>] users that were @-mentioned
27
+ def mentioned_users
28
+ return [] unless @users_provider
29
+ names = []
30
+ process_text_nodes! { |node| names.concat mentioned_names(node.to_html) }
31
+ names.uniq!
32
+ @users_provider.call(names)
33
+ end
34
+
35
+ private
36
+
37
+ MATCH_NAME_RE = /(?:^|[\s>])@([\w]+|"[\w ]+")(?=\W|$)/
38
+
39
+ def mentioned_names(text_node_html)
40
+ text_node_html.scan(MATCH_NAME_RE).map(&:first).map { |m| m.start_with?('"') ? m[1..-2] : m }
41
+ end
42
+
43
+ def highlight!(text_node_html)
44
+ names = mentioned_names(text_node_html)
45
+ return unless names.present?
46
+ @users_provider.call(names).each do |user|
47
+ name = user.to_s
48
+ maybe_quoted_name = name.include?(' ') ? %("#{name}") : name
49
+ url = Thredded.user_path(@view_context, user)
50
+ text_node_html.gsub!(
51
+ /(^|[\s>])(@#{Regexp.escape maybe_quoted_name})([^a-z\d]|$)/i,
52
+ %(\\1<a href="#{ERB::Util.html_escape url}">@#{ERB::Util.html_escape maybe_quoted_name}</a>\\3)
53
+ )
54
+ end
55
+ end
56
+
57
+ # Yields text nodes that should be processed.
58
+ def process_text_nodes!
59
+ doc.search('.//text()').each do |node|
60
+ next if has_ancestor?(node, ignored_ancestor_tags)
61
+ yield node
62
+ end
63
+ end
64
+
65
+ # Return ancestor tags to stop the at-mention highlighting.
66
+ #
67
+ # @return [Array<String>] Ancestor tags.
68
+ def ignored_ancestor_tags
69
+ if @context[:ignored_ancestor_tags]
70
+ DEFAULT_IGNORED_ANCESTOR_TAGS | @context[:ignored_ancestor_tags]
71
+ else
72
+ DEFAULT_IGNORED_ANCESTOR_TAGS
73
+ end
21
74
  end
22
75
  end
23
76
  end
@@ -43,13 +43,12 @@ module Thredded
43
43
  mattr_accessor :pipeline_filters
44
44
 
45
45
  self.pipeline_filters = [
46
- HTML::Pipeline::AtMentionFilter,
47
46
  HTML::Pipeline::VimeoFilter,
48
47
  HTML::Pipeline::YoutubeFilter,
49
48
  HTML::Pipeline::BbcodeFilter,
50
49
  HTML::Pipeline::MarkdownFilter,
50
+ HTML::Pipeline::AtMentionFilter,
51
51
  HTML::Pipeline::EmojiFilter,
52
- HTML::Pipeline::AutolinkFilter,
53
52
  HTML::Pipeline::SanitizationFilter,
54
53
  ].freeze
55
54
 
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Thredded
3
- VERSION = '0.6.0'
3
+ VERSION = '0.6.1'
4
4
  end
data/thredded.gemspec CHANGED
@@ -36,7 +36,6 @@ Gem::Specification.new do |s|
36
36
  # html-pipeline dependencies, see https://github.com/jch/html-pipeline#dependencies
37
37
  s.add_dependency 'gemoji'
38
38
  s.add_dependency 'github-markdown'
39
- s.add_dependency 'rinku'
40
39
  s.add_dependency 'sanitize'
41
40
 
42
41
  # frontend
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thredded
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Oliveira
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-06-12 00:00:00.000000000 Z
12
+ date: 2016-06-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bbcoder
@@ -235,20 +235,6 @@ dependencies:
235
235
  - - ">="
236
236
  - !ruby/object:Gem::Version
237
237
  version: '0'
238
- - !ruby/object:Gem::Dependency
239
- name: rinku
240
- requirement: !ruby/object:Gem::Requirement
241
- requirements:
242
- - - ">="
243
- - !ruby/object:Gem::Version
244
- version: '0'
245
- type: :runtime
246
- prerelease: false
247
- version_requirements: !ruby/object:Gem::Requirement
248
- requirements:
249
- - - ">="
250
- - !ruby/object:Gem::Version
251
- version: '0'
252
238
  - !ruby/object:Gem::Dependency
253
239
  name: sanitize
254
240
  requirement: !ruby/object:Gem::Requirement
@@ -788,6 +774,7 @@ files:
788
774
  - app/views/thredded/moderation/_user_moderation_state.html.erb
789
775
  - app/views/thredded/moderation/_user_post.html.erb
790
776
  - app/views/thredded/moderation/_users_search_form.html.erb
777
+ - app/views/thredded/moderation/activity.html.erb
791
778
  - app/views/thredded/moderation/history.html.erb
792
779
  - app/views/thredded/moderation/pending.html.erb
793
780
  - app/views/thredded/moderation/user.html.erb
@@ -871,7 +858,6 @@ files:
871
858
  - lib/html/pipeline/bbcode_filter.rb
872
859
  - lib/tasks/thredded_tasks.rake
873
860
  - lib/thredded.rb
874
- - lib/thredded/at_users.rb
875
861
  - lib/thredded/content_formatter.rb
876
862
  - lib/thredded/engine.rb
877
863
  - lib/thredded/errors.rb
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
- module Thredded
3
- class AtUsers
4
- # @param users_provider [#call(usernames)] given usernames, returns a list of users.
5
- def self.render(content, users_provider, view_context)
6
- at_names = AtNotificationExtractor.new(content).run
7
-
8
- if at_names.any?
9
- members = users_provider.call(at_names)
10
-
11
- members.each do |member|
12
- member_path = Thredded.user_path(view_context, member)
13
- name = member.to_s
14
- content.gsub!(/(^|[\s>])(@#{name.include?(' ') ? %("#{name}") : name})\b/i,
15
- %(\1<a href="#{ERB::Util.html_escape member_path}">@#{ERB::Util.html_escape name}</a>))
16
- end
17
- end
18
-
19
- content
20
- end
21
- end
22
- end