thredded 0.10.0 → 0.10.1
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/README.md +4 -17
- data/app/assets/images/thredded/three-dot-menu.svg +3 -0
- data/app/assets/stylesheets/thredded/base/_tables.scss +1 -0
- data/app/assets/stylesheets/thredded/base/_variables.scss +24 -1
- data/app/assets/stylesheets/thredded/components/_currently-online.scss +1 -0
- data/app/assets/stylesheets/thredded/components/_messageboard.scss +18 -10
- data/app/assets/stylesheets/thredded/components/_post.scss +84 -13
- data/app/assets/stylesheets/thredded/components/_topics.scss +7 -1
- data/app/assets/stylesheets/thredded/layout/_main-container.scss +1 -0
- data/app/assets/stylesheets/thredded/layout/_search-navigation.scss +15 -6
- data/app/controllers/thredded/application_controller.rb +6 -3
- data/app/controllers/thredded/moderation_controller.rb +1 -1
- data/app/controllers/thredded/posts_controller.rb +19 -22
- data/app/controllers/thredded/preferences_controller.rb +1 -2
- data/app/controllers/thredded/private_posts_controller.rb +77 -0
- data/app/controllers/thredded/private_topics_controller.rb +1 -1
- data/app/controllers/thredded/read_states_controller.rb +1 -1
- data/app/controllers/thredded/topics_controller.rb +1 -1
- data/app/forms/thredded/private_topic_form.rb +3 -3
- data/app/forms/thredded/topic_form.rb +1 -1
- data/app/helpers/thredded/application_helper.rb +12 -1
- data/app/helpers/thredded/render_helper.rb +14 -0
- data/app/helpers/thredded/urls_helper.rb +8 -0
- data/app/models/concerns/thredded/post_common.rb +20 -0
- data/app/models/concerns/thredded/user_topic_read_state_common.rb +6 -0
- data/app/models/thredded/null_user_topic_read_state.rb +4 -0
- data/app/policies/thredded/post_policy.rb +4 -0
- data/app/policies/thredded/private_post_policy.rb +4 -0
- data/app/view_hooks/thredded/all_view_hooks.rb +15 -0
- data/app/view_models/thredded/base_topic_view.rb +1 -1
- data/app/view_models/thredded/post_view.rb +23 -21
- data/app/view_models/thredded/posts_page_view.rb +4 -2
- data/app/view_models/thredded/topic_posts_page_view.rb +1 -1
- data/app/view_models/thredded/topic_view.rb +1 -1
- data/app/view_models/thredded/topics_page_view.rb +1 -0
- data/app/views/thredded/moderation/_post.html.erb +2 -2
- data/app/views/thredded/moderation/_user_post.html.erb +2 -2
- data/app/views/thredded/moderation/activity.html.erb +3 -1
- data/app/views/thredded/moderation/pending.html.erb +3 -1
- data/app/views/thredded/moderation/user.html.erb +3 -1
- data/app/views/thredded/posts/_content.html.erb +1 -0
- data/app/views/thredded/posts/_post.html.erb +11 -12
- data/app/views/thredded/posts/edit.html.erb +3 -4
- data/app/views/thredded/posts_common/_actions.html.erb +21 -8
- data/app/views/thredded/posts_common/actions/_delete.html.erb +4 -0
- data/app/views/thredded/posts_common/actions/_edit.html.erb +2 -0
- data/app/views/thredded/posts_common/actions/_mark_as_unread.html.erb +2 -0
- data/app/views/thredded/private_posts/_content.html.erb +1 -0
- data/app/views/thredded/private_posts/_private_post.html.erb +5 -6
- data/app/views/thredded/private_posts/edit.html.erb +18 -0
- data/app/views/thredded/private_topics/show.html.erb +3 -1
- data/app/views/thredded/shared/_nav.html.erb +1 -1
- data/app/views/thredded/shared/nav/_standalone.html.erb +1 -1
- data/app/views/thredded/topics/_sticky_topics_divider.html.erb +1 -0
- data/app/views/thredded/topics/_topic.html.erb +4 -0
- data/app/views/thredded/topics/index.html.erb +1 -1
- data/app/views/thredded/topics/show.html.erb +1 -1
- data/app/views/thredded/users/_post.html.erb +2 -2
- data/app/views/thredded/users/_posts.html.erb +1 -1
- data/config/locales/en.yml +1 -0
- data/config/locales/es.yml +1 -0
- data/config/locales/pl.yml +1 -0
- data/config/locales/pt-BR.yml +1 -0
- data/config/routes.rb +9 -4
- data/lib/generators/thredded/install/templates/initializer.rb +7 -0
- data/lib/thredded.rb +4 -0
- data/lib/thredded/collection_to_strings_with_cache_renderer.rb +62 -0
- data/lib/thredded/version.rb +1 -1
- metadata +15 -4
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Thredded
|
3
|
+
# A controller for managing {PrivatePost}s.
|
4
|
+
class PrivatePostsController < Thredded::ApplicationController
|
5
|
+
include ActionView::RecordIdentifier
|
6
|
+
|
7
|
+
helper_method :topic
|
8
|
+
after_action :update_user_activity
|
9
|
+
|
10
|
+
after_action :verify_authorized
|
11
|
+
|
12
|
+
def create
|
13
|
+
post = parent_topic.posts.build(post_params)
|
14
|
+
authorize_creating post
|
15
|
+
post.save!
|
16
|
+
|
17
|
+
redirect_to post_path(post, user: thredded_current_user)
|
18
|
+
end
|
19
|
+
|
20
|
+
def edit
|
21
|
+
authorize post, :update?
|
22
|
+
end
|
23
|
+
|
24
|
+
def update
|
25
|
+
authorize post, :update?
|
26
|
+
post.update_attributes(post_params.except(:user, :ip))
|
27
|
+
|
28
|
+
redirect_to post_path(post, user: thredded_current_user)
|
29
|
+
end
|
30
|
+
|
31
|
+
def destroy
|
32
|
+
authorize post, :destroy?
|
33
|
+
post.destroy!
|
34
|
+
|
35
|
+
redirect_back fallback_location: topic_url(topic),
|
36
|
+
notice: I18n.t('thredded.posts.deleted_notice')
|
37
|
+
end
|
38
|
+
|
39
|
+
def mark_as_unread
|
40
|
+
authorize post, :read?
|
41
|
+
page = post.page
|
42
|
+
post.mark_as_unread(thredded_current_user, page)
|
43
|
+
after_mark_as_unread # customization hook
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def after_mark_as_unread
|
49
|
+
redirect_to private_topics_path
|
50
|
+
end
|
51
|
+
|
52
|
+
def topic
|
53
|
+
post.postable
|
54
|
+
end
|
55
|
+
|
56
|
+
def post_params
|
57
|
+
params.require(:post)
|
58
|
+
.permit(:content)
|
59
|
+
.merge(user: thredded_current_user, ip: request.remote_ip)
|
60
|
+
end
|
61
|
+
|
62
|
+
def parent_topic
|
63
|
+
PrivateTopic
|
64
|
+
.includes(:private_users)
|
65
|
+
.friendly
|
66
|
+
.find(params[:private_topic_id])
|
67
|
+
end
|
68
|
+
|
69
|
+
def post
|
70
|
+
@post ||= Thredded::PrivatePost.find(params[:id])
|
71
|
+
end
|
72
|
+
|
73
|
+
def current_page
|
74
|
+
params[:page].nil? ? 1 : params[:page].to_i
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -30,7 +30,7 @@ module Thredded
|
|
30
30
|
.page(current_page)
|
31
31
|
@posts = Thredded::TopicPostsPageView.new(thredded_current_user, private_topic, page_scope)
|
32
32
|
|
33
|
-
if
|
33
|
+
if thredded_signed_in?
|
34
34
|
Thredded::UserPrivateTopicReadState.touch!(
|
35
35
|
thredded_current_user.id, private_topic.id, page_scope.last, current_page
|
36
36
|
)
|
@@ -32,7 +32,7 @@ module Thredded
|
|
32
32
|
.page(current_page)
|
33
33
|
@posts = Thredded::TopicPostsPageView.new(thredded_current_user, topic, page_scope)
|
34
34
|
|
35
|
-
if
|
35
|
+
if thredded_signed_in?
|
36
36
|
Thredded::UserTopicReadState.touch!(
|
37
37
|
thredded_current_user.id, topic.id, page_scope.last, current_page
|
38
38
|
)
|
@@ -64,7 +64,7 @@ module Thredded
|
|
64
64
|
|
65
65
|
def topic_categories
|
66
66
|
if category_ids
|
67
|
-
ids = category_ids.reject(&:empty?)
|
67
|
+
ids = category_ids.reject(&:empty?)
|
68
68
|
Category.where(id: ids)
|
69
69
|
else
|
70
70
|
[]
|
@@ -82,8 +82,8 @@ module Thredded
|
|
82
82
|
def normalized_user_ids
|
83
83
|
user_ids
|
84
84
|
.reject(&:empty?)
|
85
|
-
.map(&:
|
86
|
-
.push(user.id)
|
85
|
+
.map(&:to_s)
|
86
|
+
.push(user.id.to_s)
|
87
87
|
.uniq
|
88
88
|
end
|
89
89
|
|
@@ -3,6 +3,7 @@ module Thredded
|
|
3
3
|
module ApplicationHelper
|
4
4
|
include ::Thredded::UrlsHelper
|
5
5
|
include ::Thredded::NavHelper
|
6
|
+
include ::Thredded::RenderHelper
|
6
7
|
|
7
8
|
# @return [AllViewHooks] View hooks configuration.
|
8
9
|
def view_hooks
|
@@ -68,6 +69,16 @@ module Thredded
|
|
68
69
|
end
|
69
70
|
end
|
70
71
|
|
72
|
+
# @param posts [Thredded::PostsPageView, Array<Thredded::PostView>]
|
73
|
+
# @param partial [String]
|
74
|
+
# @param content_partial [String]
|
75
|
+
def render_posts(posts, partial: 'thredded/posts/post', content_partial: 'thredded/posts/content')
|
76
|
+
posts_with_contents = render_collection_to_strings_with_cache(
|
77
|
+
partial: content_partial, collection: posts, as: :post, expires_in: 1.week
|
78
|
+
)
|
79
|
+
render partial: partial, collection: posts_with_contents, as: :post_and_content
|
80
|
+
end
|
81
|
+
|
71
82
|
def paginate(collection, args = {})
|
72
83
|
super(collection, args.reverse_merge(views_prefix: 'thredded'))
|
73
84
|
end
|
@@ -96,7 +107,7 @@ module Thredded
|
|
96
107
|
|
97
108
|
def unread_private_topics_count
|
98
109
|
@unread_private_topics_count ||=
|
99
|
-
if
|
110
|
+
if thredded_signed_in?
|
100
111
|
Thredded::PrivateTopic
|
101
112
|
.for_user(thredded_current_user)
|
102
113
|
.unread(thredded_current_user)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Thredded
|
3
|
+
module RenderHelper
|
4
|
+
# @param collection [Array<T>]
|
5
|
+
# @param partial [String]
|
6
|
+
# @param expires_in [ActiveSupport::Duration]
|
7
|
+
# @return Array<[T, String]>
|
8
|
+
def render_collection_to_strings_with_cache(collection:, partial:, expires_in:, **opts)
|
9
|
+
CollectionToStringsWithCacheRenderer.new(lookup_context).render_collection_to_strings_with_cache(
|
10
|
+
self, collection: collection, partial: partial, expires_in: expires_in, **opts
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -103,5 +103,13 @@ module Thredded
|
|
103
103
|
messageboards_search_path
|
104
104
|
end
|
105
105
|
end
|
106
|
+
|
107
|
+
def mark_unread_path(post, _params = {})
|
108
|
+
if post.private_topic_post?
|
109
|
+
mark_as_unread_private_topic_private_post_path(post.postable, post)
|
110
|
+
else
|
111
|
+
mark_as_unread_messageboard_topic_post_path(post.messageboard, post.postable, post)
|
112
|
+
end
|
113
|
+
end
|
106
114
|
end
|
107
115
|
end
|
@@ -48,6 +48,26 @@ module Thredded
|
|
48
48
|
.in(user_names)
|
49
49
|
end
|
50
50
|
|
51
|
+
# Marks all the posts from the given one as unread for the given user
|
52
|
+
# @param user [Thredded.user_class]
|
53
|
+
# @param page [Integer]
|
54
|
+
def mark_as_unread(user, page)
|
55
|
+
if previous_post.nil?
|
56
|
+
read_state = postable.user_read_states.find_by(user_id: user.id)
|
57
|
+
read_state.destroy if read_state
|
58
|
+
else
|
59
|
+
read_state = postable.user_read_states.create_with(
|
60
|
+
read_at: previous_post.created_at,
|
61
|
+
page: page
|
62
|
+
).find_or_create_by(user_id: user.id)
|
63
|
+
read_state.update_columns(read_at: previous_post.created_at, page: page)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def previous_post
|
68
|
+
@previous_post ||= postable.posts.order_newest_first.find_by('created_at < ?', created_at)
|
69
|
+
end
|
70
|
+
|
51
71
|
private
|
52
72
|
|
53
73
|
def ensure_user_detail
|
@@ -12,6 +12,12 @@ module Thredded
|
|
12
12
|
postable.last_post_at <= read_at
|
13
13
|
end
|
14
14
|
|
15
|
+
# @param post [Post or PrivatePost]
|
16
|
+
# @return [Boolean]
|
17
|
+
def post_read?(post)
|
18
|
+
post.created_at <= read_at
|
19
|
+
end
|
20
|
+
|
15
21
|
module ClassMethods
|
16
22
|
# @param user_id [Integer]
|
17
23
|
# @param topic_id [Integer]
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module Thredded
|
3
3
|
class AllViewHooks
|
4
|
+
# @return [PostCommon]
|
5
|
+
attr_reader :post_common
|
4
6
|
# @return [PostsCommon]
|
5
7
|
attr_reader :posts_common
|
6
8
|
# @return [PostForm]
|
@@ -23,6 +25,7 @@ module Thredded
|
|
23
25
|
end
|
24
26
|
|
25
27
|
def initialize
|
28
|
+
@post_common = PostCommon.new
|
26
29
|
@posts_common = PostsCommon.new
|
27
30
|
@post_form = PostForm.new
|
28
31
|
@moderation_user_page = ModerationUserPage.new
|
@@ -42,6 +45,18 @@ module Thredded
|
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
48
|
+
class PostCommon
|
49
|
+
# @return [Thredded::AllViewHooks::ViewHook]
|
50
|
+
attr_reader :actions
|
51
|
+
# @return [Thredded::AllViewHooks::ViewHook]
|
52
|
+
attr_reader :mark_as_unread
|
53
|
+
|
54
|
+
def initialize
|
55
|
+
@actions = ViewHook.new
|
56
|
+
@mark_as_unread = ViewHook.new
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
45
60
|
class PostForm
|
46
61
|
# @return [Thredded::AllViewHooks::ViewHook]
|
47
62
|
attr_reader :content_text_area
|
@@ -15,9 +15,11 @@ module Thredded
|
|
15
15
|
|
16
16
|
# @param post [Thredded::PostCommon]
|
17
17
|
# @param policy [#update? #destroy?]
|
18
|
-
|
18
|
+
# @param policy [Thredded::TopicView]
|
19
|
+
def initialize(post, policy, topic_view: nil)
|
19
20
|
@post = post
|
20
21
|
@policy = policy
|
22
|
+
@topic_view = topic_view
|
21
23
|
end
|
22
24
|
|
23
25
|
def can_update?
|
@@ -36,6 +38,10 @@ module Thredded
|
|
36
38
|
Thredded::UrlsHelper.edit_post_path(@post)
|
37
39
|
end
|
38
40
|
|
41
|
+
def mark_unread_path
|
42
|
+
Thredded::UrlsHelper.mark_unread_path(@post)
|
43
|
+
end
|
44
|
+
|
39
45
|
def destroy_path
|
40
46
|
Thredded::UrlsHelper.delete_post_path(@post)
|
41
47
|
end
|
@@ -44,27 +50,23 @@ module Thredded
|
|
44
50
|
Thredded::UrlsHelper.post_permalink_path(@post.id)
|
45
51
|
end
|
46
52
|
|
47
|
-
#
|
53
|
+
# This cache key is used only for caching the content.
|
48
54
|
def cache_key
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
can_destroy?
|
65
|
-
].map { |p| p ? '+' : '-' } * ''
|
66
|
-
].compact.join('/')
|
55
|
+
@post.cache_key
|
56
|
+
end
|
57
|
+
|
58
|
+
POST_IS_READ = :read
|
59
|
+
POST_IS_UNREAD = :unread
|
60
|
+
|
61
|
+
# returns nil if read state is not appropriate to the view (i.e. viewing posts outside a topic)
|
62
|
+
def read_state
|
63
|
+
if @topic_view.nil? || @policy.anonymous?
|
64
|
+
nil
|
65
|
+
elsif @topic_view.post_read?(@post)
|
66
|
+
POST_IS_READ
|
67
|
+
else
|
68
|
+
POST_IS_UNREAD
|
69
|
+
end
|
67
70
|
end
|
68
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
69
71
|
end
|
70
72
|
end
|
@@ -16,9 +16,11 @@ module Thredded
|
|
16
16
|
|
17
17
|
# @param user [Thredded.user_class] the user who is viewing the posts page
|
18
18
|
# @param paginated_scope [ActiveRecord::Relation<Thredded::PostCommon>]
|
19
|
-
def initialize(user, paginated_scope)
|
19
|
+
def initialize(user, paginated_scope, topic_view: nil)
|
20
20
|
@paginated_scope = paginated_scope
|
21
|
-
@post_views = paginated_scope.map
|
21
|
+
@post_views = paginated_scope.map do |post|
|
22
|
+
Thredded::PostView.new(post, Pundit.policy!(user, post), topic_view: topic_view)
|
23
|
+
end
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
@@ -9,8 +9,8 @@ module Thredded
|
|
9
9
|
# @param topic [Thredded::TopicCommon]
|
10
10
|
# @param paginated_scope [ActiveRecord::Relation<Thredded::PostCommon>]
|
11
11
|
def initialize(user, topic, paginated_scope)
|
12
|
-
super(user, paginated_scope)
|
13
12
|
@topic = "#{paginated_scope.reflect_on_association(:postable).klass}View".constantize.from_user(topic, user)
|
13
|
+
super(user, paginated_scope, topic_view: @topic)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
module Thredded
|
3
3
|
# A view model for Topic.
|
4
4
|
class TopicView < Thredded::BaseTopicView
|
5
|
-
delegate :categories, :id, :blocked?, :last_moderation_record, :followers,
|
5
|
+
delegate :sticky?, :locked?, :categories, :id, :blocked?, :last_moderation_record, :followers,
|
6
6
|
:last_post, :messageboard_id, :messageboard_name,
|
7
7
|
to: :@topic
|
8
8
|
|