thredded 0.10.0 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|