thredded 0.6.2 → 0.6.3
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.md +15 -0
- data/README.md +1 -1
- data/app/assets/stylesheets/thredded/base/_buttons.scss +17 -0
- data/app/assets/stylesheets/thredded/base/_variables.scss +8 -1
- data/app/commands/thredded/mark_all_read.rb +21 -0
- data/app/controllers/thredded/messageboard_groups_controller.rb +1 -1
- data/app/controllers/thredded/moderation_controller.rb +1 -1
- data/app/controllers/thredded/read_states_controller.rb +12 -0
- data/app/forms/thredded/topic_form.rb +0 -1
- data/app/helpers/thredded/urls_helper.rb +1 -1
- data/app/models/concerns/thredded/post_common.rb +14 -2
- data/app/models/concerns/thredded/topic_common.rb +9 -1
- data/app/models/thredded/messageboard.rb +7 -0
- data/app/models/thredded/post.rb +11 -18
- data/app/models/thredded/private_post.rb +1 -5
- data/app/models/thredded/private_topic.rb +0 -4
- data/app/models/thredded/topic.rb +26 -12
- data/app/view_models/thredded/topic_view.rb +1 -0
- data/app/view_models/thredded/topics_page_view.rb +3 -2
- data/app/views/thredded/preferences/_form.html.erb +1 -1
- data/app/views/thredded/private_topic_mailer/message_notification.html.erb +1 -1
- data/app/views/thredded/private_topic_mailer/message_notification.text.erb +1 -1
- data/app/views/thredded/private_topics/index.html.erb +14 -6
- data/config/locales/en.yml +2 -1
- data/config/locales/pt-BR.yml +9 -10
- data/config/routes.rb +2 -1
- data/db/seeds.rb +1 -118
- data/heroku.gemfile +1 -2
- data/heroku.gemfile.lock +60 -64
- data/lib/thredded/database_seeder.rb +269 -0
- data/lib/thredded/main_app_route_delegator.rb +1 -1
- data/lib/thredded/version.rb +1 -1
- data/thredded.gemspec +3 -3
- metadata +12 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a1acf1b52acfeb414676b3d0b4c60cf9ea347af
|
4
|
+
data.tar.gz: cc19fecffc62460f24b8781ab0f4dc27bcf2db95
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4085dd28328ce761c890fdf976d199cc3b6ac2aab5ca7da0ec32ab866ee95f8c8ae465f9f74c387dfdc13b4dbe201dca503820060c02e636472e35bd3548c4e6
|
7
|
+
data.tar.gz: 917c71e13f4b5bfd94d8567ff146c871f39201ed9727e0e1fe77b88bfdd19304cf3dbd25a5935015e03ae37982986828fbb100b5b88960afef9b5c3c6ae2f252
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
# v0.6.3
|
2
|
+
|
3
|
+
This is a minor bugfix release.
|
4
|
+
|
5
|
+
## Fixed
|
6
|
+
|
7
|
+
* Last topic post and last messageboard topic is kept in sync correctly with regards to moderation state changes.
|
8
|
+
[#384](https://github.com/thredded/thredded/issues/384) [#387](https://github.com/thredded/thredded/issues/387)
|
9
|
+
* Posts and private posts are now ordered by created at and not by ID, to avoid ordering issues in cases such as
|
10
|
+
imported content. [#360](https://github.com/thredded/thredded/issues/360)
|
11
|
+
* The global preferences URL now works when the Thredde URL helpers are included into another engine.
|
12
|
+
[#355](https://github.com/thredded/thredded/pull/355)
|
13
|
+
|
14
|
+
See the full list of changes here: https://github.com/thredded/thredded/compare/v0.6.2...v0.6.3.
|
15
|
+
|
1
16
|
# v0.6.2
|
2
17
|
|
3
18
|
This is a minor bugfix release.
|
data/README.md
CHANGED
@@ -39,6 +39,23 @@
|
|
39
39
|
}
|
40
40
|
}
|
41
41
|
|
42
|
+
.thredded--button-light {
|
43
|
+
background-color: $thredded-button-light-background;
|
44
|
+
color: $thredded-button-light-color;
|
45
|
+
|
46
|
+
&:hover,
|
47
|
+
&:active,
|
48
|
+
&:focus {
|
49
|
+
background-color: $thredded-button-light-hover-background;
|
50
|
+
color: $thredded-button-light-hover-color;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
.thredded--button-wide {
|
55
|
+
width: 100%;
|
56
|
+
text-align: center;
|
57
|
+
}
|
58
|
+
|
42
59
|
%thredded--buttons-list {
|
43
60
|
text-align: center;
|
44
61
|
a, .button_to {
|
@@ -63,8 +63,15 @@ $thredded-form-color: $thredded-text-color !default;
|
|
63
63
|
// Buttons
|
64
64
|
$thredded-button-background: $thredded-action-color !default;
|
65
65
|
$thredded-button-color: #fff !default;
|
66
|
-
$thredded-button-hover-color: $thredded-button-color !default;
|
67
66
|
$thredded-button-hover-background: darken($thredded-button-background, 15%) !default;
|
67
|
+
$thredded-button-hover-color: $thredded-button-color !default;
|
68
|
+
|
69
|
+
$thredded-button-light-background: lighten($thredded-button-background, 35%) !default;
|
70
|
+
$thredded-button-light-color: darken($thredded-button-background, 15%) !default;
|
71
|
+
$thredded-button-light-hover-background: darken($thredded-button-light-background, 15%) !default;
|
72
|
+
$thredded-button-light-hover-color: darken($thredded-button-light-color, 15%) !default;
|
73
|
+
|
74
|
+
|
68
75
|
$thredded-button-border-radius: 3px !default;
|
69
76
|
$thredded-button-font-family: $thredded-base-font-family !default;
|
70
77
|
$thredded-button-font-size: $thredded-font-size-small !default;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Thredded
|
3
|
+
class MarkAllRead
|
4
|
+
def self.run(user)
|
5
|
+
unread_topics = Thredded::PrivateTopic.unread(user)
|
6
|
+
return if unread_topics.empty?
|
7
|
+
|
8
|
+
unread_topics.each do |topic|
|
9
|
+
last_post = topic.posts.order_oldest_first.last
|
10
|
+
total_pages = topic.posts.page(1).total_pages
|
11
|
+
|
12
|
+
UserPrivateTopicReadState.touch!(
|
13
|
+
user.id,
|
14
|
+
topic.id,
|
15
|
+
last_post,
|
16
|
+
total_pages
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Thredded
|
3
|
+
class ReadStatesController < Thredded::ApplicationController
|
4
|
+
before_action :thredded_require_login!
|
5
|
+
|
6
|
+
def update
|
7
|
+
MarkAllRead.run(thredded_current_user) if signed_in?
|
8
|
+
|
9
|
+
redirect_to request.referer
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -13,18 +13,30 @@ module Thredded
|
|
13
13
|
|
14
14
|
validates :content, presence: true
|
15
15
|
|
16
|
-
scope :order_oldest_first, -> { order(id: :asc) }
|
17
|
-
scope :order_newest_first, -> { order(id: :desc) }
|
16
|
+
scope :order_oldest_first, -> { order(created_at: :asc, id: :asc) }
|
17
|
+
scope :order_newest_first, -> { order(created_at: :desc, id: :desc) }
|
18
|
+
|
19
|
+
before_validation :ensure_user_detail, on: :create
|
18
20
|
end
|
19
21
|
|
20
22
|
def avatar_url
|
21
23
|
Thredded.avatar_url.call(user)
|
22
24
|
end
|
23
25
|
|
26
|
+
def calculate_page(postable_posts, per_page)
|
27
|
+
1 + postable_posts.where(postable_posts.arel_table[:created_at].lt(created_at)).count / per_page
|
28
|
+
end
|
29
|
+
|
24
30
|
# @param view_context [Object] the context of the rendering view.
|
25
31
|
# @return [String] formatted and sanitized html-safe post content.
|
26
32
|
def filtered_content(view_context, users_provider: -> (names) { readers_from_user_names(names) })
|
27
33
|
Thredded::ContentFormatter.new(view_context, users_provider: users_provider).format_content(content)
|
28
34
|
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def ensure_user_detail
|
39
|
+
build_user_detail if user && !user_detail
|
40
|
+
end
|
29
41
|
end
|
30
42
|
end
|
@@ -10,7 +10,7 @@ module Thredded
|
|
10
10
|
foreign_key: 'last_user_id'
|
11
11
|
|
12
12
|
scope :order_recently_updated_first, -> { order(updated_at: :desc, id: :desc) }
|
13
|
-
scope :on_page, -> (page_num) { page(page_num)
|
13
|
+
scope :on_page, -> (page_num) { page(page_num) }
|
14
14
|
|
15
15
|
validates :hash_id, presence: true, uniqueness: true
|
16
16
|
validates :posts_count, numericality: true
|
@@ -20,6 +20,8 @@ module Thredded
|
|
20
20
|
end
|
21
21
|
|
22
22
|
delegate :name, :name=, :email, :email=, to: :user, prefix: true
|
23
|
+
|
24
|
+
before_validation :ensure_user_detail, on: :create
|
23
25
|
end
|
24
26
|
|
25
27
|
def user
|
@@ -34,6 +36,12 @@ module Thredded
|
|
34
36
|
!public?
|
35
37
|
end
|
36
38
|
|
39
|
+
private
|
40
|
+
|
41
|
+
def ensure_user_detail
|
42
|
+
build_user_detail if user && !user_detail
|
43
|
+
end
|
44
|
+
|
37
45
|
module ClassMethods
|
38
46
|
# @param user [Thredded.user_class]
|
39
47
|
# @return [ActiveRecord::Relation]
|
@@ -64,5 +64,12 @@ module Thredded
|
|
64
64
|
[:name, '-board']
|
65
65
|
]
|
66
66
|
end
|
67
|
+
|
68
|
+
def update_last_topic!
|
69
|
+
return if destroyed?
|
70
|
+
update_column(
|
71
|
+
:last_topic_id, topics.order_recently_updated_first.moderation_state_visible_to_all.select(:id).first.try(:id)
|
72
|
+
)
|
73
|
+
end
|
67
74
|
end
|
68
75
|
end
|
data/app/models/thredded/post.rb
CHANGED
@@ -26,24 +26,22 @@ module Thredded
|
|
26
26
|
|
27
27
|
validates :messageboard_id, presence: true
|
28
28
|
|
29
|
-
after_commit :
|
29
|
+
after_commit :update_parent_last_user_and_time_from_last_post, on: [:create, :destroy]
|
30
|
+
after_commit :update_parent_last_user_and_time_from_last_post_if_moderation_state_changed, on: :update
|
31
|
+
|
30
32
|
after_commit :auto_follow_and_notify, on: [:create, :update]
|
31
33
|
|
32
34
|
# @param [Integer] per_page
|
33
35
|
# @param [Thredded.user_class] user
|
34
36
|
def page(per_page: self.class.default_per_page, user:)
|
35
37
|
readable_posts = PostPolicy::Scope.new(user, postable.posts).resolve
|
36
|
-
|
38
|
+
calculate_page(readable_posts, per_page)
|
37
39
|
end
|
38
40
|
|
39
41
|
def private_topic_post?
|
40
42
|
false
|
41
43
|
end
|
42
44
|
|
43
|
-
def user_detail
|
44
|
-
super || build_user_detail
|
45
|
-
end
|
46
|
-
|
47
45
|
# @return [ActiveRecord::Relation<Thredded.user_class>] users from the list of user names that can read this post.
|
48
46
|
def readers_from_user_names(user_names)
|
49
47
|
DbTextSearch::CaseInsensitive
|
@@ -61,18 +59,13 @@ module Thredded
|
|
61
59
|
AutoFollowAndNotifyJob.perform_later(id)
|
62
60
|
end
|
63
61
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
if last_post
|
72
|
-
postable.update_columns(last_user_id: last_post.user_id, updated_at: last_post.updated_at)
|
73
|
-
else
|
74
|
-
postable.update_columns(last_user_id: nil, updated_at: postable.created_at)
|
75
|
-
end
|
62
|
+
def update_parent_last_user_and_time_from_last_post
|
63
|
+
postable.update_last_user_and_time_from_last_post!
|
64
|
+
messageboard.update_last_topic!
|
65
|
+
end
|
66
|
+
|
67
|
+
def update_parent_last_user_and_time_from_last_post_if_moderation_state_changed
|
68
|
+
update_parent_last_user_and_time_from_last_post if previous_changes.include?('moderation_state')
|
76
69
|
end
|
77
70
|
end
|
78
71
|
end
|
@@ -20,17 +20,13 @@ module Thredded
|
|
20
20
|
|
21
21
|
# @param [Integer] per_page
|
22
22
|
def page(per_page: self.class.default_per_page)
|
23
|
-
|
23
|
+
calculate_page(postable.posts, per_page)
|
24
24
|
end
|
25
25
|
|
26
26
|
def private_topic_post?
|
27
27
|
true
|
28
28
|
end
|
29
29
|
|
30
|
-
def user_detail
|
31
|
-
super || build_user_detail
|
32
|
-
end
|
33
|
-
|
34
30
|
# @return [ActiveRecord::Relation<Thredded.user_class>] users from the list of user names that can read this post.
|
35
31
|
def readers_from_user_names(user_names)
|
36
32
|
DbTextSearch::CaseInsensitive
|
@@ -15,6 +15,12 @@ module Thredded
|
|
15
15
|
|
16
16
|
scope :order_sticky_first, -> { order(sticky: :desc) }
|
17
17
|
|
18
|
+
scope :followed_by, lambda { |user|
|
19
|
+
joins(:user_follows)
|
20
|
+
.where(thredded_user_topic_follows: { user_id: user.id })
|
21
|
+
}
|
22
|
+
scope :unread_followed_by, ->(user) { followed_by(user).unread(user) }
|
23
|
+
|
18
24
|
extend FriendlyId
|
19
25
|
friendly_id :slug_candidates,
|
20
26
|
use: [:history, :reserved, :scoped],
|
@@ -46,6 +52,9 @@ module Thredded
|
|
46
52
|
has_one :first_post, -> { order_oldest_first },
|
47
53
|
class_name: 'Thredded::Post',
|
48
54
|
foreign_key: :postable_id
|
55
|
+
has_one :last_post, -> { order_newest_first },
|
56
|
+
class_name: 'Thredded::Post',
|
57
|
+
foreign_key: :postable_id
|
49
58
|
|
50
59
|
has_many :topic_categories, dependent: :destroy
|
51
60
|
has_many :categories, through: :topic_categories
|
@@ -63,7 +72,8 @@ module Thredded
|
|
63
72
|
source: :user,
|
64
73
|
through: :user_follows
|
65
74
|
|
66
|
-
after_commit :update_messageboard_last_topic, on:
|
75
|
+
after_commit :update_messageboard_last_topic, on: :update, if: -> { previous_changes.include?('moderation_state') }
|
76
|
+
after_update :update_last_user_and_time_from_last_post!, if: -> { previous_changes.include?('moderation_state') }
|
67
77
|
|
68
78
|
def self.find_by_slug!(slug)
|
69
79
|
friendly.find(slug)
|
@@ -101,10 +111,6 @@ module Thredded
|
|
101
111
|
true
|
102
112
|
end
|
103
113
|
|
104
|
-
def user_detail
|
105
|
-
super || build_user_detail
|
106
|
-
end
|
107
|
-
|
108
114
|
def should_generate_new_friendly_id?
|
109
115
|
title_changed?
|
110
116
|
end
|
@@ -114,6 +120,20 @@ module Thredded
|
|
114
120
|
first_post.try(:last_moderation_record)
|
115
121
|
end
|
116
122
|
|
123
|
+
def update_last_user_and_time_from_last_post!
|
124
|
+
return if destroyed?
|
125
|
+
scope = posts.order_newest_first
|
126
|
+
scope = scope.moderation_state_visible_to_all if moderation_state_visible_to_all?
|
127
|
+
last_post = scope.select(:user_id, :created_at).first
|
128
|
+
if last_post
|
129
|
+
update_columns(last_user_id: last_post.user_id, updated_at: last_post.created_at)
|
130
|
+
else
|
131
|
+
# Either a visible topic is left with no visible posts, or an invisible topic is left with no posts at all.
|
132
|
+
# This shouldn't happen in stock Thredded.
|
133
|
+
update_columns(last_user_id: nil, updated_at: created_at)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
117
137
|
private
|
118
138
|
|
119
139
|
def slug_candidates
|
@@ -124,13 +144,7 @@ module Thredded
|
|
124
144
|
end
|
125
145
|
|
126
146
|
def update_messageboard_last_topic
|
127
|
-
|
128
|
-
last_topic = if destroyed? || !moderation_state_visible_to_all?
|
129
|
-
messageboard.topics.order_recently_updated_first.moderation_state_visible_to_all.select(:id).first
|
130
|
-
else
|
131
|
-
self
|
132
|
-
end
|
133
|
-
messageboard.update_columns(last_topic_id: last_topic.try(:id))
|
147
|
+
messageboard.update_last_topic!
|
134
148
|
end
|
135
149
|
end
|
136
150
|
end
|
@@ -14,10 +14,11 @@ module Thredded
|
|
14
14
|
|
15
15
|
# @param user [Thredded.user_class] the user who is viewing the posts page
|
16
16
|
# @param topics_page_scope [ActiveRecord::Relation<Thredded::Topic>]
|
17
|
-
|
17
|
+
# @param topic_view_class [Class] view_model for topic instances
|
18
|
+
def initialize(user, topics_page_scope, topic_view_class: TopicView)
|
18
19
|
@topics_page_scope = topics_page_scope
|
19
20
|
@topic_views = @topics_page_scope.with_read_and_follow_states(user).map do |(topic, read_state, follow)|
|
20
|
-
|
21
|
+
topic_view_class.new(topic, read_state, follow, Pundit.policy!(user, topic))
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<%= form_for(
|
2
2
|
preferences,
|
3
3
|
method: :patch,
|
4
|
-
url: (preferences.messageboard ? messageboard_preferences_path(preferences.messageboard) :
|
4
|
+
url: (preferences.messageboard ? messageboard_preferences_path(preferences.messageboard) : global_preferences_path),
|
5
5
|
html: {
|
6
6
|
class: 'thredded--form thredded--notification-preferences-form',
|
7
7
|
'data-thredded-user-preferences-form' => true
|