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