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
@@ -0,0 +1,269 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'factory_girl_rails'
|
3
|
+
|
4
|
+
# rubocop:disable HandleExceptions
|
5
|
+
begin
|
6
|
+
if FactoryGirl.factories.instance_variable_get(:@items).none?
|
7
|
+
require_relative '../../spec/factories'
|
8
|
+
end
|
9
|
+
rescue NameError
|
10
|
+
end
|
11
|
+
# rubocop:enable HandleExceptions
|
12
|
+
module Thredded
|
13
|
+
class DatabaseSeeder
|
14
|
+
SKIP_CALLBACKS = [
|
15
|
+
[Thredded::Post, :commit, :after, :auto_follow_and_notify],
|
16
|
+
[Thredded::PrivatePost, :commit, :after, :notify_users],
|
17
|
+
].freeze
|
18
|
+
|
19
|
+
def self.run(users: 200, topics: 55, posts: (1..60))
|
20
|
+
STDERR.puts 'Seeding the database...'
|
21
|
+
# Disable callbacks to avoid creating notifications and performing unnecessary updates
|
22
|
+
SKIP_CALLBACKS.each { |(klass, *args)| klass.skip_callback(*args) }
|
23
|
+
s = new
|
24
|
+
Messageboard.transaction do
|
25
|
+
s.seed(users: users, topics: topics, posts: posts)
|
26
|
+
s.log 'Running after_commit callbacks'
|
27
|
+
end
|
28
|
+
ensure
|
29
|
+
# Re-enable callbacks
|
30
|
+
SKIP_CALLBACKS.each { |(klass, *args)| klass.set_callback(*args) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def seed(users: 200, topics: 55, posts: (1..60))
|
34
|
+
users(count: users)
|
35
|
+
first_messageboard
|
36
|
+
topics(count: topics)
|
37
|
+
private_topics(count: topics)
|
38
|
+
posts(count: posts)
|
39
|
+
private_posts(count: posts)
|
40
|
+
create_additional_messageboards
|
41
|
+
follow_some_topics
|
42
|
+
read_some_topics
|
43
|
+
end
|
44
|
+
|
45
|
+
def log(message)
|
46
|
+
STDERR.puts "- #{message}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def first_user
|
50
|
+
@first_user ||= FirstUser.new(self).find_or_create
|
51
|
+
end
|
52
|
+
|
53
|
+
def users(count: 1)
|
54
|
+
@users ||= Users.new(self).find_or_create(count: count)
|
55
|
+
end
|
56
|
+
|
57
|
+
def first_messageboard
|
58
|
+
@first_messageboard ||= FirstMessageboard.new(self).find_or_create
|
59
|
+
end
|
60
|
+
|
61
|
+
def create_additional_messageboards
|
62
|
+
meta_group_id = MessageboardGroup.create!(name: 'Meta').id
|
63
|
+
additional_messageboards = [
|
64
|
+
['Off-Topic', "Talk about whatever here, it's all good."],
|
65
|
+
['Help, Bugs, and Suggestions',
|
66
|
+
'Need help using the forum? Want to report a bug or make a suggestion? This is the place.', meta_group_id],
|
67
|
+
['Praise', 'Want to tell us how great we are? This is the place.', meta_group_id]
|
68
|
+
]
|
69
|
+
log "Creating #{additional_messageboards.length} additional messageboards..."
|
70
|
+
additional_messageboards.each do |(name, description, group_id)|
|
71
|
+
messageboard = Messageboard.create!(name: name, description: description, messageboard_group_id: group_id)
|
72
|
+
FactoryGirl.create_list(:topic, 1 + rand(3), messageboard: messageboard, with_posts: 1)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def topics(count: 1)
|
77
|
+
@topics ||= Topics.new(self).find_or_create(count: count)
|
78
|
+
end
|
79
|
+
|
80
|
+
def private_topics(count: 1)
|
81
|
+
@private_topics ||= PrivateTopics.new(self).find_or_create(count: count)
|
82
|
+
end
|
83
|
+
|
84
|
+
def posts(count: (1..1))
|
85
|
+
@posts ||= Posts.new(self).find_or_create(count: count)
|
86
|
+
end
|
87
|
+
|
88
|
+
def private_posts(count: (1..1))
|
89
|
+
@private_posts ||= PrivatePosts.new(self).find_or_create(count: count)
|
90
|
+
end
|
91
|
+
|
92
|
+
def follow_some_topics(count: (5..10), count_users: (1..5))
|
93
|
+
log 'Following some topics...'
|
94
|
+
posts.each do |post|
|
95
|
+
Thredded::UserTopicFollow.create_unless_exists(post.user_id, post.postable_id, :posted) if post.user_id
|
96
|
+
end
|
97
|
+
follow_some_topics_by_user(first_user, count: count)
|
98
|
+
users.sample(count_users.min + rand(count_users.max - count_users.min + 2)).each do |user|
|
99
|
+
follow_some_topics_by_user(user, count: count)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def follow_some_topics_by_user(user, count: (1..10))
|
104
|
+
topics.sample(count.min + rand(count.max - count.min + 2)).each do |topic|
|
105
|
+
Thredded::UserTopicFollow.create_unless_exists(user.id, topic.id)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def read_some_topics(count: (5..10), count_users: (1..5))
|
110
|
+
log 'Reading some topics...'
|
111
|
+
topics.each do |topic|
|
112
|
+
read_topic(topic, topic.last_user_id) if topic.last_user_id
|
113
|
+
end
|
114
|
+
read_some_topics_by_user(first_user, count: count)
|
115
|
+
@users.sample(count_users.min + rand(count_users.max - count_users.min + 2)).each do |user|
|
116
|
+
read_some_topics_by_user(user, count: count)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def read_some_topics_by_user(user, count: (1..10))
|
121
|
+
topics.sample(count.min + rand(count.max - count.min + 2)).each do |topic|
|
122
|
+
read_topic(topic, user.id)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def read_topic(topic, user_id)
|
127
|
+
Thredded::UserTopicReadState.find_or_initialize_by(user_id: user_id, postable_id: topic.id)
|
128
|
+
.update!(read_at: topic.updated_at, page: 1)
|
129
|
+
end
|
130
|
+
|
131
|
+
class BaseSeedData
|
132
|
+
attr_reader :seeder
|
133
|
+
|
134
|
+
def initialize(seed_database)
|
135
|
+
@seeder = seed_database
|
136
|
+
end
|
137
|
+
|
138
|
+
delegate :log, to: :seeder
|
139
|
+
|
140
|
+
def find_or_create(*args)
|
141
|
+
return @stored if @stored
|
142
|
+
@stored = (find || create(*args))
|
143
|
+
end
|
144
|
+
|
145
|
+
protected
|
146
|
+
|
147
|
+
def model_class
|
148
|
+
self.class::MODEL_CLASS
|
149
|
+
end
|
150
|
+
|
151
|
+
# @abstract
|
152
|
+
def create(*_args)
|
153
|
+
fail 'Unimplemented'
|
154
|
+
end
|
155
|
+
|
156
|
+
# @abstract
|
157
|
+
def find
|
158
|
+
fail 'Unimplemented'
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
class FirstSeedData < BaseSeedData
|
163
|
+
def find
|
164
|
+
model_class.first
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class CollectionSeedData < BaseSeedData
|
169
|
+
def find
|
170
|
+
return nil unless model_class.exists?
|
171
|
+
model_class.all.to_a
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
class FirstUser < FirstSeedData
|
176
|
+
MODEL_CLASS = User
|
177
|
+
|
178
|
+
def create
|
179
|
+
log 'Creating first user...'
|
180
|
+
FactoryGirl.create(:user, :approved, :admin, name: 'Joe', email: 'joe@example.com')
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
class Users < CollectionSeedData
|
185
|
+
MODEL_CLASS = User
|
186
|
+
|
187
|
+
def create(count: 1)
|
188
|
+
log "Creating #{count} users..."
|
189
|
+
approved_users_count = (count * 0.97).round
|
190
|
+
[seeder.first_user] +
|
191
|
+
FactoryGirl.create_list(:user, approved_users_count, :approved) +
|
192
|
+
FactoryGirl.create_list(:user, count - approved_users_count)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
class FirstMessageboard < FirstSeedData
|
197
|
+
MODEL_CLASS = Messageboard
|
198
|
+
|
199
|
+
def create
|
200
|
+
log 'Creating a messageboard...'
|
201
|
+
@first_messageboard = FactoryGirl.create(
|
202
|
+
:messageboard,
|
203
|
+
name: 'Main Board',
|
204
|
+
slug: 'main-board',
|
205
|
+
description: 'A board is not a board without some posts'
|
206
|
+
)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
class Topics < CollectionSeedData
|
211
|
+
MODEL_CLASS = Topic
|
212
|
+
|
213
|
+
def create(count: 1, messageboard: seeder.first_messageboard)
|
214
|
+
log "Creating #{count} topics in #{messageboard.name}..."
|
215
|
+
FactoryGirl.create_list(
|
216
|
+
:topic, count,
|
217
|
+
messageboard: messageboard,
|
218
|
+
user: seeder.users.sample,
|
219
|
+
last_user: seeder.users.sample
|
220
|
+
)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
class PrivateTopics < CollectionSeedData
|
225
|
+
MODEL_CLASS = PrivateTopic
|
226
|
+
|
227
|
+
def create(count: 1)
|
228
|
+
FactoryGirl.create_list(
|
229
|
+
:private_topic, count,
|
230
|
+
user: seeder.users[1..-1].sample,
|
231
|
+
last_user: seeder.users.sample,
|
232
|
+
users: [seeder.first_user]
|
233
|
+
)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
class Posts < CollectionSeedData
|
238
|
+
MODEL_CLASS = Post
|
239
|
+
|
240
|
+
def create(count: (1..1))
|
241
|
+
log "Creating #{count} additional posts in each topic..."
|
242
|
+
seeder.topics.flat_map do |topic|
|
243
|
+
written = (1 + rand(5)).days.ago
|
244
|
+
posts = Array.new((count.min + rand(count.max + 1))) do
|
245
|
+
written += (1 + rand(60)).minutes
|
246
|
+
FactoryGirl.create(:post, postable: topic, messageboard: seeder.first_messageboard,
|
247
|
+
user: seeder.users.sample, created_at: written, updated_at: written)
|
248
|
+
end
|
249
|
+
topic.update!(last_user_id: posts.last.user.id, updated_at: written)
|
250
|
+
posts
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
class PrivatePosts < CollectionSeedData
|
256
|
+
MODEL_CLASS = PrivatePost
|
257
|
+
|
258
|
+
def create(count: (1..1))
|
259
|
+
log "Creating #{count} additional posts in each private topic..."
|
260
|
+
seeder.private_topics.flat_map do |topic|
|
261
|
+
(count.min + rand(count.max + 1)).times do
|
262
|
+
FactoryGirl.create(:private_post, postable: topic, user: seeder.users.sample)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
# rubocop:enable Metrics/ClassLength
|
data/lib/thredded/version.rb
CHANGED
data/thredded.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.version = Thredded::VERSION
|
10
10
|
s.authors = ['Joel Oliveira', 'Gleb Mazovetskiy']
|
11
11
|
s.email = ['joel@thredded.com', 'glex.spb@gmail.com']
|
12
|
-
s.homepage = 'https://
|
12
|
+
s.homepage = 'https://thredded.org'
|
13
13
|
s.summary = 'The best Rails forums engine ever.'
|
14
14
|
s.license = 'MIT'
|
15
15
|
s.description = 'The best Rails 4.2+ forums engine ever. Its goal is to be as simple and feature rich as possible.
|
@@ -56,8 +56,8 @@ Thredded works with SQLite, MySQL (v5.6.4+), and PostgreSQL. See the demo at htt
|
|
56
56
|
s.add_development_dependency 'factory_girl_rails'
|
57
57
|
s.add_development_dependency 'faker', '>= 1.6.2'
|
58
58
|
s.add_development_dependency 'launchy'
|
59
|
-
s.add_development_dependency 'rspec-rails'
|
60
|
-
s.add_development_dependency 'rubocop', '
|
59
|
+
s.add_development_dependency 'rspec-rails', '>= 3.5.0'
|
60
|
+
s.add_development_dependency 'rubocop', '= 0.42.0'
|
61
61
|
s.add_development_dependency 'test-unit'
|
62
62
|
|
63
63
|
# dummy app dependencies
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thredded
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Oliveira
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-08-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bbcoder
|
@@ -423,28 +423,28 @@ dependencies:
|
|
423
423
|
requirements:
|
424
424
|
- - ">="
|
425
425
|
- !ruby/object:Gem::Version
|
426
|
-
version:
|
426
|
+
version: 3.5.0
|
427
427
|
type: :development
|
428
428
|
prerelease: false
|
429
429
|
version_requirements: !ruby/object:Gem::Requirement
|
430
430
|
requirements:
|
431
431
|
- - ">="
|
432
432
|
- !ruby/object:Gem::Version
|
433
|
-
version:
|
433
|
+
version: 3.5.0
|
434
434
|
- !ruby/object:Gem::Dependency
|
435
435
|
name: rubocop
|
436
436
|
requirement: !ruby/object:Gem::Requirement
|
437
437
|
requirements:
|
438
|
-
- -
|
438
|
+
- - '='
|
439
439
|
- !ruby/object:Gem::Version
|
440
|
-
version:
|
440
|
+
version: 0.42.0
|
441
441
|
type: :development
|
442
442
|
prerelease: false
|
443
443
|
version_requirements: !ruby/object:Gem::Requirement
|
444
444
|
requirements:
|
445
|
-
- -
|
445
|
+
- - '='
|
446
446
|
- !ruby/object:Gem::Version
|
447
|
-
version:
|
447
|
+
version: 0.42.0
|
448
448
|
- !ruby/object:Gem::Dependency
|
449
449
|
name: test-unit
|
450
450
|
requirement: !ruby/object:Gem::Requirement
|
@@ -668,6 +668,7 @@ files:
|
|
668
668
|
- app/assets/stylesheets/thredded/utilities/_is-expanded.scss
|
669
669
|
- app/commands/thredded/at_notification_extractor.rb
|
670
670
|
- app/commands/thredded/autofollow_mentioned_users.rb
|
671
|
+
- app/commands/thredded/mark_all_read.rb
|
671
672
|
- app/commands/thredded/members_marked_notified.rb
|
672
673
|
- app/commands/thredded/messageboard_destroyer.rb
|
673
674
|
- app/commands/thredded/moderate_post.rb
|
@@ -683,6 +684,7 @@ files:
|
|
683
684
|
- app/controllers/thredded/preferences_controller.rb
|
684
685
|
- app/controllers/thredded/private_post_permalinks_controller.rb
|
685
686
|
- app/controllers/thredded/private_topics_controller.rb
|
687
|
+
- app/controllers/thredded/read_states_controller.rb
|
686
688
|
- app/controllers/thredded/theme_previews_controller.rb
|
687
689
|
- app/controllers/thredded/topics_controller.rb
|
688
690
|
- app/forms/thredded/private_topic_form.rb
|
@@ -861,6 +863,7 @@ files:
|
|
861
863
|
- lib/tasks/thredded_tasks.rake
|
862
864
|
- lib/thredded.rb
|
863
865
|
- lib/thredded/content_formatter.rb
|
866
|
+
- lib/thredded/database_seeder.rb
|
864
867
|
- lib/thredded/engine.rb
|
865
868
|
- lib/thredded/errors.rb
|
866
869
|
- lib/thredded/main_app_route_delegator.rb
|
@@ -868,7 +871,7 @@ files:
|
|
868
871
|
- lib/thredded/topics_search.rb
|
869
872
|
- lib/thredded/version.rb
|
870
873
|
- thredded.gemspec
|
871
|
-
homepage: https://
|
874
|
+
homepage: https://thredded.org
|
872
875
|
licenses:
|
873
876
|
- MIT
|
874
877
|
metadata: {}
|