thredded 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.mkdn +21 -0
- data/README.mkdn +17 -1
- data/app/assets/stylesheets/thredded/_thredded.scss +1 -0
- data/app/assets/stylesheets/thredded/base/_grid.scss +6 -0
- data/app/assets/stylesheets/thredded/base/_nav.scss +51 -0
- data/app/assets/stylesheets/thredded/base/_variables.scss +1 -0
- data/app/assets/stylesheets/thredded/components/_base.scss +4 -0
- data/app/assets/stylesheets/thredded/components/_post.scss +19 -6
- data/app/assets/stylesheets/thredded/components/_topics.scss +6 -0
- data/app/assets/stylesheets/thredded/layout/_moderation.scss +53 -8
- data/app/assets/stylesheets/thredded/layout/_navigation.scss +1 -1
- data/app/assets/stylesheets/thredded/layout/_user-navigation.scss +7 -47
- data/app/assets/stylesheets/thredded/layout/_user.scss +10 -0
- data/app/commands/thredded/moderate_post.rb +1 -1
- data/app/controllers/thredded/messageboards_controller.rb +1 -1
- data/app/controllers/thredded/moderation_controller.rb +39 -5
- data/app/helpers/thredded/application_helper.rb +4 -2
- data/app/models/concerns/thredded/content_moderation_state.rb +15 -8
- data/app/models/concerns/thredded/post_common.rb +1 -0
- data/app/models/concerns/thredded/topic_common.rb +0 -1
- data/app/models/thredded/messageboard.rb +4 -4
- data/app/models/thredded/post.rb +2 -0
- data/app/models/thredded/post_moderation_record.rb +3 -1
- data/app/models/thredded/topic.rb +17 -0
- data/app/models/thredded/user_extender.rb +7 -0
- data/app/policies/thredded/post_policy.rb +2 -0
- data/app/policies/thredded/topic_policy.rb +6 -6
- data/app/view_models/thredded/post_view.rb +19 -1
- data/app/view_models/thredded/posts_page_view.rb +1 -0
- data/app/view_models/thredded/topic_view.rb +5 -1
- data/app/views/thredded/messageboards/_messageboard.html.erb +3 -3
- data/app/views/thredded/moderation/_nav.html.erb +16 -0
- data/app/views/thredded/moderation/_post.html.erb +9 -2
- data/app/views/thredded/moderation/_post_moderation_record.html.erb +22 -19
- data/app/views/thredded/moderation/_user_moderation_state.html.erb +3 -0
- data/app/views/thredded/moderation/_user_post.html.erb +7 -0
- data/app/views/thredded/moderation/_users_search_form.html.erb +10 -0
- data/app/views/thredded/moderation/history.html.erb +2 -8
- data/app/views/thredded/moderation/pending.html.erb +3 -10
- data/app/views/thredded/moderation/user.html.erb +42 -0
- data/app/views/thredded/moderation/users.html.erb +38 -0
- data/app/views/thredded/posts/_post.html.erb +4 -0
- data/app/views/thredded/posts_common/_header.html.erb +1 -0
- data/app/views/thredded/posts_common/_header_with_topic.html.erb +15 -0
- data/app/views/thredded/posts_common/_header_with_user_and_topic.html.erb +18 -0
- data/app/views/thredded/search/_form.html.erb +3 -1
- data/app/views/thredded/shared/_content_moderation_blocked_state.html.erb +8 -0
- data/app/views/thredded/shared/_nav.html.erb +8 -4
- data/app/views/thredded/topics/_topic.html.erb +6 -0
- data/app/views/thredded/users/_post.html.erb +6 -0
- data/app/views/thredded/users/_posts.html.erb +7 -0
- data/config/locales/en.yml +29 -3
- data/config/locales/pt-BR.yml +34 -9
- data/config/routes.rb +7 -2
- data/db/migrate/20160329231848_create_thredded.rb +22 -21
- data/db/upgrade_migrations/20160611094616_upgrade_v0_5_to_v0_6.rb +25 -0
- data/heroku.gemfile.lock +2 -2
- data/lib/thredded.rb +17 -5
- data/lib/thredded/version.rb +1 -1
- metadata +15 -2
@@ -18,12 +18,14 @@ module Thredded
|
|
18
18
|
end
|
19
19
|
|
20
20
|
# @param datetime [DateTime]
|
21
|
+
# @param default [String] a string to return if time is nil.
|
21
22
|
# @return [String] html_safe datetime presentation
|
22
|
-
def time_ago(datetime)
|
23
|
+
def time_ago(datetime, default: '-')
|
23
24
|
timeago_tag datetime,
|
24
25
|
lang: I18n.locale.to_s.downcase,
|
25
26
|
format: -> (t, _opts) { t.year == Time.current.year ? :short : :long },
|
26
|
-
nojs: true
|
27
|
+
nojs: true,
|
28
|
+
default: default
|
27
29
|
end
|
28
30
|
|
29
31
|
def paginate(collection, args = {})
|
@@ -14,19 +14,24 @@ module Thredded
|
|
14
14
|
# @type [Arel::Table]
|
15
15
|
table = arel_table
|
16
16
|
# @type [Arel::Nodes::Node]
|
17
|
-
|
17
|
+
visible =
|
18
18
|
if Thredded.content_visible_while_pending_moderation
|
19
|
+
# All non-blocked content
|
19
20
|
table[:moderation_state].not_eq(moderation_states[:blocked])
|
20
21
|
else
|
22
|
+
# Only approved content
|
21
23
|
table[:moderation_state].eq(moderation_states[:approved])
|
22
24
|
end
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
if user && !user.thredded_anonymous?
|
26
|
+
# Own content
|
27
|
+
visible = visible.or(table[:user_id].eq(user.id))
|
28
|
+
# Content that one can moderate
|
29
|
+
moderatable_messageboard_ids = user.thredded_can_moderate_messageboards.map(&:id)
|
30
|
+
if moderatable_messageboard_ids.present?
|
31
|
+
visible = visible.or(table[:messageboard_id].in(moderatable_messageboard_ids))
|
28
32
|
end
|
29
|
-
|
33
|
+
end
|
34
|
+
where(visible)
|
30
35
|
end)
|
31
36
|
end
|
32
37
|
|
@@ -41,7 +46,9 @@ module Thredded
|
|
41
46
|
|
42
47
|
# Whether this is visible to the given user based on the moderation state.
|
43
48
|
def moderation_state_visible_to_user?(user)
|
44
|
-
moderation_state_visible_to_all? ||
|
49
|
+
moderation_state_visible_to_all? ||
|
50
|
+
(!user.thredded_anonymous? &&
|
51
|
+
(user_id == user.id || user.thredded_can_moderate_messageboards.map(&:id).include?(messageboard_id)))
|
45
52
|
end
|
46
53
|
|
47
54
|
private
|
@@ -25,8 +25,8 @@ module Thredded
|
|
25
25
|
has_many :user_messageboard_preferences, dependent: :destroy
|
26
26
|
has_many :posts, dependent: :destroy
|
27
27
|
has_many :topics, dependent: :destroy, inverse_of: :messageboard
|
28
|
-
|
29
|
-
|
28
|
+
|
29
|
+
belongs_to :last_topic, class_name: 'Thredded::Topic'
|
30
30
|
|
31
31
|
has_many :user_details, through: :posts
|
32
32
|
has_many :messageboard_users,
|
@@ -54,8 +54,8 @@ module Thredded
|
|
54
54
|
scope :top_level_messageboards, -> { where(group: nil) }
|
55
55
|
scope :by_messageboard_group, ->(group) { where(group: group.id) }
|
56
56
|
|
57
|
-
def
|
58
|
-
|
57
|
+
def last_user
|
58
|
+
last_topic.try(:last_user)
|
59
59
|
end
|
60
60
|
|
61
61
|
def slug_candidates
|
data/app/models/thredded/post.rb
CHANGED
@@ -21,6 +21,8 @@ module Thredded
|
|
21
21
|
has_many :moderation_records,
|
22
22
|
class_name: 'Thredded::PostModerationRecord',
|
23
23
|
dependent: :nullify
|
24
|
+
has_one :last_moderation_record, -> { order_newest_first },
|
25
|
+
class_name: 'Thredded::PostModerationRecord'
|
24
26
|
|
25
27
|
validates :messageboard_id, presence: true
|
26
28
|
|
@@ -8,6 +8,8 @@ module Thredded
|
|
8
8
|
end
|
9
9
|
validates :previous_moderation_state, presence: true
|
10
10
|
|
11
|
+
scope :order_newest_first, -> { order(created_at: :desc, id: :desc) }
|
12
|
+
|
11
13
|
belongs_to :messageboard, inverse_of: :post_moderation_records
|
12
14
|
validates :messageboard_id, presence: true
|
13
15
|
belongs_to :post, inverse_of: :moderation_records
|
@@ -37,7 +39,7 @@ module Thredded
|
|
37
39
|
post: post,
|
38
40
|
post_content: post.content,
|
39
41
|
post_user: post.user,
|
40
|
-
post_user_name: post.user.send
|
42
|
+
post_user_name: post.user.try(:send, Thredded.user_name_column),
|
41
43
|
messageboard_id: post.messageboard_id,
|
42
44
|
)
|
43
45
|
end
|
@@ -63,6 +63,8 @@ module Thredded
|
|
63
63
|
source: :user,
|
64
64
|
through: :user_follows
|
65
65
|
|
66
|
+
after_commit :update_messageboard_last_topic, on: [:create, :destroy]
|
67
|
+
|
66
68
|
def self.find_by_slug!(slug)
|
67
69
|
friendly.find(slug)
|
68
70
|
rescue ActiveRecord::RecordNotFound
|
@@ -107,6 +109,11 @@ module Thredded
|
|
107
109
|
title_changed?
|
108
110
|
end
|
109
111
|
|
112
|
+
# @return [Thredded::PostModerationRecord, nil]
|
113
|
+
def last_moderation_record
|
114
|
+
first_post.try(:last_moderation_record)
|
115
|
+
end
|
116
|
+
|
110
117
|
private
|
111
118
|
|
112
119
|
def slug_candidates
|
@@ -115,5 +122,15 @@ module Thredded
|
|
115
122
|
[:title, '-topic'],
|
116
123
|
]
|
117
124
|
end
|
125
|
+
|
126
|
+
def update_messageboard_last_topic
|
127
|
+
return if messageboard.destroyed?
|
128
|
+
last_topic = if destroyed?
|
129
|
+
messageboard.topics.order_recently_updated_first.select(:id).first
|
130
|
+
else
|
131
|
+
self
|
132
|
+
end
|
133
|
+
messageboard.update!(last_topic_id: last_topic.try(:id))
|
134
|
+
end
|
118
135
|
end
|
119
136
|
end
|
@@ -41,6 +41,13 @@ module Thredded
|
|
41
41
|
opt.has_many :thredded_post_moderation_records, foreign_key: 'post_user_id', inverse_of: :post_user
|
42
42
|
opt.has_many :thredded_post_moderated_records, foreign_key: 'moderator_id', inverse_of: :moderator
|
43
43
|
end
|
44
|
+
|
45
|
+
scope :left_join_thredded_user_details, (lambda do
|
46
|
+
users = arel_table
|
47
|
+
user_details = Thredded::UserDetail.arel_table
|
48
|
+
joins(users.join(user_details, Arel::Nodes::OuterJoin)
|
49
|
+
.on(users[:id].eq(user_details[:user_id])).join_sources)
|
50
|
+
end)
|
44
51
|
end
|
45
52
|
|
46
53
|
def thredded_user_preference
|
@@ -21,17 +21,17 @@ module Thredded
|
|
21
21
|
# @param user [Thredded.user_class]
|
22
22
|
# @param topic [Thredded::Topic]
|
23
23
|
def initialize(user, topic)
|
24
|
-
@user
|
25
|
-
@topic
|
26
|
-
@
|
24
|
+
@user = user
|
25
|
+
@topic = topic
|
26
|
+
@messageboard_policy = MessageboardPolicy.new(user, topic.messageboard)
|
27
27
|
end
|
28
28
|
|
29
29
|
def create?
|
30
|
-
@
|
30
|
+
@messageboard_policy.post?
|
31
31
|
end
|
32
32
|
|
33
33
|
def read?
|
34
|
-
@
|
34
|
+
@messageboard_policy.read? && @topic.moderation_state_visible_to_user?(@user)
|
35
35
|
end
|
36
36
|
|
37
37
|
def update?
|
@@ -43,7 +43,7 @@ module Thredded
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def moderate?
|
46
|
-
@
|
46
|
+
@messageboard_policy.moderate?
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
@@ -11,6 +11,7 @@ module Thredded
|
|
11
11
|
:pending_moderation?,
|
12
12
|
:approved?,
|
13
13
|
:blocked?,
|
14
|
+
:last_moderation_record,
|
14
15
|
to: :@post
|
15
16
|
|
16
17
|
# @param post [Thredded::PostCommon]
|
@@ -28,6 +29,10 @@ module Thredded
|
|
28
29
|
@can_destroy ||= @policy.destroy?
|
29
30
|
end
|
30
31
|
|
32
|
+
def can_moderate?
|
33
|
+
@can_moderate ||= @policy.moderate?
|
34
|
+
end
|
35
|
+
|
31
36
|
def edit_path
|
32
37
|
Thredded::UrlsHelper.edit_post_path(@post)
|
33
38
|
end
|
@@ -36,17 +41,30 @@ module Thredded
|
|
36
41
|
Thredded::UrlsHelper.delete_post_path(@post)
|
37
42
|
end
|
38
43
|
|
44
|
+
def permalink_path
|
45
|
+
Thredded::UrlsHelper.post_permalink_path(@post.id)
|
46
|
+
end
|
47
|
+
|
48
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
39
49
|
def cache_key
|
50
|
+
moderation_state = unless @post.private_topic_post?
|
51
|
+
if @post.pending_moderation? && !Thredded.content_visible_while_pending_moderation
|
52
|
+
'p'
|
53
|
+
elsif @post.blocked?
|
54
|
+
'-'
|
55
|
+
end
|
56
|
+
end
|
40
57
|
[
|
41
58
|
I18n.locale,
|
42
59
|
@post,
|
43
60
|
@post.user,
|
61
|
+
moderation_state || '+',
|
44
62
|
[
|
45
|
-
!@post.private_topic_post? && @post.pending_moderation? && !Thredded.content_visible_while_pending_moderation,
|
46
63
|
can_update?,
|
47
64
|
can_destroy?
|
48
65
|
].map { |p| p ? '+' : '-' } * ''
|
49
66
|
]
|
50
67
|
end
|
68
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
51
69
|
end
|
52
70
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
module Thredded
|
3
3
|
# A view model for Topic.
|
4
4
|
class TopicView < BaseTopicView
|
5
|
-
delegate :categories, :id,
|
5
|
+
delegate :categories, :id, :blocked?, :last_moderation_record,
|
6
6
|
to: :@topic
|
7
7
|
|
8
8
|
# @param topic [TopicCommon]
|
@@ -30,6 +30,10 @@ module Thredded
|
|
30
30
|
].compact
|
31
31
|
end
|
32
32
|
|
33
|
+
def can_moderate?
|
34
|
+
@policy.moderate?
|
35
|
+
end
|
36
|
+
|
33
37
|
def edit_path
|
34
38
|
Thredded::UrlsHelper.edit_messageboard_topic_path(@topic.messageboard, @topic)
|
35
39
|
end
|
@@ -11,11 +11,11 @@
|
|
11
11
|
|
12
12
|
<p class="thredded--messageboard--description"><%= messageboard.description %></p>
|
13
13
|
|
14
|
-
<% if messageboard.
|
14
|
+
<% if messageboard.last_topic %>
|
15
15
|
<p class="thredded--messageboard--byline">
|
16
16
|
<%= t 'thredded.messageboard.last_updated_by_html',
|
17
|
-
time_ago: time_ago(messageboard.
|
18
|
-
user: messageboard.
|
17
|
+
time_ago: time_ago(messageboard.last_topic.updated_at),
|
18
|
+
user: messageboard.last_user %>
|
19
19
|
</p>
|
20
20
|
<% end %>
|
21
21
|
<% end %>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<% content_for :thredded_main_navigation do %>
|
2
|
+
<nav class="thredded--moderation-navigation">
|
3
|
+
<ul class="thredded--moderation-navigation--items">
|
4
|
+
<li class="thredded--moderation-navigation--item thredded--moderation-navigation--pending">
|
5
|
+
<%= link_to t('thredded.nav.moderation_pending'), pending_moderation_path %>
|
6
|
+
</li>
|
7
|
+
<li class="thredded--moderation-navigation--item thredded--moderation-navigation--history">
|
8
|
+
<%= link_to t('thredded.nav.moderation_history'), moderation_history_path %>
|
9
|
+
</li>
|
10
|
+
<li class="thredded--moderation-navigation--item thredded--moderation-navigation--users">
|
11
|
+
<%= link_to t('thredded.nav.moderation_users'), users_moderation_path %>
|
12
|
+
</li>
|
13
|
+
</ul>
|
14
|
+
<%= render 'users_search_form' %>
|
15
|
+
</nav>
|
16
|
+
<% end %>
|
@@ -1,6 +1,13 @@
|
|
1
1
|
<%# @param post [Thredded::PostView] %>
|
2
|
-
<%= content_tag :article, id: dom_id(post), class: 'thredded--post' do %>
|
3
|
-
<%= render 'thredded/posts_common/
|
2
|
+
<%= content_tag :article, id: dom_id(post), class: 'thredded--post thredded--post-moderation' do %>
|
3
|
+
<%= render 'thredded/posts_common/header_with_user_and_topic',
|
4
|
+
post: post,
|
5
|
+
post_user_link: if post.user
|
6
|
+
link_to(post.user, user_moderation_path(post.user.id))
|
7
|
+
else
|
8
|
+
content_tag :em, t('thredded.null_user_name')
|
9
|
+
end
|
10
|
+
%>
|
4
11
|
<%= render 'thredded/posts_common/content', post: post %>
|
5
12
|
<%= render 'thredded/posts_common/actions', post: post %>
|
6
13
|
<%= render 'post_moderation_actions', post: post %>
|
@@ -1,20 +1,24 @@
|
|
1
1
|
<%
|
2
|
-
|
2
|
+
record = post_moderation_record
|
3
|
+
post = record.post
|
4
|
+
if post
|
5
|
+
post_view = Thredded::PostView.new(post, policy(post))
|
6
|
+
end
|
3
7
|
moderation_state_notice_args = {
|
4
|
-
moderator: user_link(
|
5
|
-
time_ago: time_ago(
|
8
|
+
moderator: user_link(record.moderator),
|
9
|
+
time_ago: time_ago(record.created_at)
|
6
10
|
}
|
7
11
|
%>
|
8
|
-
<article class="thredded--post-moderation-record thredded--post-moderation-record-<%=
|
12
|
+
<article class="thredded--post-moderation-record thredded--post-moderation-record-<%= record.moderation_state %>">
|
9
13
|
<header class="thredded--post-moderation-record--header">
|
10
14
|
<p class="thredded--post-moderation-record--moderation-state-notice">
|
11
|
-
<% if
|
15
|
+
<% if record.approved? %>
|
12
16
|
<%= t('thredded.moderation.post_approved_html', moderation_state_notice_args) %>
|
13
|
-
<% elsif
|
17
|
+
<% elsif record.blocked? %>
|
14
18
|
<%= t('thredded.moderation.post_blocked_html', moderation_state_notice_args) %>
|
15
19
|
<% end %>
|
16
20
|
</p>
|
17
|
-
<% if post && post.content !=
|
21
|
+
<% if post && post.content != record.post_content %>
|
18
22
|
<p class="thredded--post-moderation-record--content-changed-notice">
|
19
23
|
<%= t('thredded.moderation.posts_content_changed_since_moderation_html', post_url: post_permalink_path(post)) %>
|
20
24
|
</p>
|
@@ -22,21 +26,20 @@
|
|
22
26
|
<%= t 'thredded.moderation.post_deleted_notice' unless post %>
|
23
27
|
</header>
|
24
28
|
<article class="thredded--post">
|
25
|
-
|
26
|
-
<% if
|
27
|
-
<%=
|
28
|
-
<h2 class="thredded--post--user"><%= user_link post_moderation_record.post_user %></h2>
|
29
|
+
<% post_user_link = capture do %>
|
30
|
+
<% if post.user %>
|
31
|
+
<%= link_to post.user, user_moderation_path(post.user.id) %>
|
29
32
|
<% else %>
|
30
|
-
|
31
|
-
<%= post_moderation_record.post_user_name %>, <em><%= t 'thredded.null_user_name' %></em>
|
32
|
-
</h2>
|
33
|
+
<%= safe_join [record.post_user_name, content_tag(:em, t('thredded.null_user_name'))].compact, ', ' %>
|
33
34
|
<% end %>
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
<% end %>
|
36
|
+
<% if post %>
|
37
|
+
<%= render 'thredded/posts_common/header_with_user_and_topic', post: post_view, post_user_link: post_user_link %>
|
38
|
+
<% else %>
|
39
|
+
<header><h2 class="thredded--post--user"><%= post_user_link %></h2></header>
|
40
|
+
<% end %>
|
38
41
|
<div class="thredded--post--content">
|
39
|
-
<%= Thredded::ContentFormatter.new(self).format_content(
|
42
|
+
<%= Thredded::ContentFormatter.new(self).format_content(record.post_content) %>
|
40
43
|
</div>
|
41
44
|
</article>
|
42
45
|
<%= render 'post_moderation_actions', post: post if post %>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<%# @param post [Thredded::PostView] %>
|
2
|
+
<%= content_tag :article, id: dom_id(post), class: 'thredded--post thredded--post-moderation' do %>
|
3
|
+
<%= render 'thredded/posts_common/header_with_topic', post: post %>
|
4
|
+
<%= render 'thredded/posts_common/content', post: post %>
|
5
|
+
<%= render 'thredded/posts_common/actions', post: post %>
|
6
|
+
<%= render 'post_moderation_actions', post: post %>
|
7
|
+
<% end %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<%= form_tag users_moderation_path, class: 'thredded--form thredded--navigation--search', method: 'get' do %>
|
2
|
+
<%= label_tag :q, t('thredded.moderation.search_users.form_label') %>
|
3
|
+
<%= text_field_tag :q, @query,
|
4
|
+
type: 'search',
|
5
|
+
required: true,
|
6
|
+
# If there are no results the user will likely want to change the query, so auto-focus.
|
7
|
+
autofocus: @query.presence && !@users.presence,
|
8
|
+
placeholder: t('thredded.moderation.search_users.form_placeholder') %>
|
9
|
+
<button type="submit"><%= t 'thredded.search.form.btn_submit' %></button>
|
10
|
+
<% end %>
|
@@ -1,13 +1,7 @@
|
|
1
1
|
<% content_for :thredded_page_title,
|
2
2
|
safe_join([t('thredded.nav.moderation'), t('thredded.nav.moderation_history')], ': ') %>
|
3
|
-
<% content_for :thredded_page_id, 'thredded--
|
4
|
-
|
5
|
-
<ul class="thredded--navigation-breadcrumbs">
|
6
|
-
<li><%= link_to t('thredded.nav.all_messageboards'), messageboards_path %></li>
|
7
|
-
<li><%= link_to t('thredded.nav.moderation'), pending_moderation_path %></li>
|
8
|
-
<li><%= link_to t('thredded.nav.moderation_history'), moderation_history_path %></li>
|
9
|
-
</ul>
|
10
|
-
<% end %>
|
3
|
+
<% content_for :thredded_page_id, 'thredded--moderation-history' %>
|
4
|
+
<%= render 'nav' %>
|
11
5
|
|
12
6
|
<%= thredded_page do %>
|
13
7
|
<%= content_tag :section, class: 'thredded--main-section' do %>
|