thredded 0.1.0 → 0.2.2
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.mkdn +202 -0
- data/MIT-LICENSE +20 -0
- data/README.mkdn +391 -0
- data/app/assets/images/thredded/breadcrumb-chevron.svg +1 -0
- data/app/assets/javascripts/thredded/currently_online.es6 +25 -0
- data/app/assets/javascripts/thredded/post_form.es6 +20 -0
- data/app/assets/javascripts/thredded/time_stamps.es6 +8 -0
- data/app/assets/javascripts/thredded/topic_form.es6 +55 -0
- data/app/assets/javascripts/thredded/users_select.es6 +5 -0
- data/app/assets/javascripts/thredded.es6 +10 -0
- data/app/assets/stylesheets/thredded/_base.scss +11 -0
- data/app/assets/stylesheets/thredded/_dependencies.scss +1 -0
- data/app/assets/stylesheets/thredded/_thredded.scss +27 -0
- data/app/assets/stylesheets/thredded/base/_alerts.scss +40 -0
- data/app/assets/stylesheets/thredded/base/_buttons.scss +39 -0
- data/app/assets/stylesheets/thredded/base/_forms.scss +79 -0
- data/app/assets/stylesheets/thredded/base/_grid.scss +19 -0
- data/app/assets/stylesheets/thredded/base/_lists.scss +31 -0
- data/app/assets/stylesheets/thredded/base/_tables.scss +25 -0
- data/app/assets/stylesheets/thredded/base/_typography.scss +36 -0
- data/app/assets/stylesheets/thredded/base/_variables.scss +54 -0
- data/app/assets/stylesheets/thredded/components/_base.scss +13 -0
- data/app/assets/stylesheets/thredded/components/_currently-online.scss +48 -0
- data/app/assets/stylesheets/thredded/components/_empty.scss +11 -0
- data/app/assets/stylesheets/thredded/components/_flash-message.scss +19 -0
- data/app/assets/stylesheets/thredded/components/_form-list.scss +35 -0
- data/app/assets/stylesheets/thredded/components/_main-section.scss +3 -0
- data/app/assets/stylesheets/thredded/components/_messageboard.scss +55 -0
- data/app/assets/stylesheets/thredded/components/_pagination.scss +26 -0
- data/app/assets/stylesheets/thredded/components/_post-form.scss +21 -0
- data/app/assets/stylesheets/thredded/components/_post.scss +66 -0
- data/app/assets/stylesheets/thredded/components/_preferences.scss +6 -0
- data/app/assets/stylesheets/thredded/components/_select2.scss +42 -0
- data/app/assets/stylesheets/thredded/components/_topic-delete.scss +9 -0
- data/app/assets/stylesheets/thredded/components/_topic-header.scss +20 -0
- data/app/assets/stylesheets/thredded/components/_topics.scss +113 -0
- data/app/assets/stylesheets/thredded/layout/_main-container.scss +15 -0
- data/app/assets/stylesheets/thredded/layout/_main-navigation.scss +45 -0
- data/app/assets/stylesheets/thredded/layout/_topic-navigation.scss +53 -0
- data/app/assets/stylesheets/thredded/layout/_user-navigation.scss +87 -0
- data/app/assets/stylesheets/thredded/utilities/_is-compact.scss +26 -0
- data/app/assets/stylesheets/thredded/utilities/_is-expanded.scss +16 -0
- data/app/assets/stylesheets/thredded.scss +3 -0
- data/app/commands/thredded/at_notification_extractor.rb +15 -0
- data/app/commands/thredded/members_marked_notified.rb +18 -0
- data/app/commands/thredded/messageboard_destroyer.rb +60 -0
- data/app/commands/thredded/notify_mentioned_users.rb +68 -0
- data/app/commands/thredded/notify_private_topic_users.rb +51 -0
- data/app/commands/thredded/user_reads_private_topic.rb +22 -0
- data/app/commands/thredded/user_resets_private_topic_to_unread.rb +23 -0
- data/app/controllers/thredded/application_controller.rb +105 -0
- data/app/controllers/thredded/messageboards_controller.rb +58 -0
- data/app/controllers/thredded/posts_controller.rb +78 -0
- data/app/controllers/thredded/preferences_controller.rb +28 -0
- data/app/controllers/thredded/private_topics_controller.rb +65 -0
- data/app/controllers/thredded/setups_controller.rb +53 -0
- data/app/controllers/thredded/theme_previews_controller.rb +59 -0
- data/app/controllers/thredded/topics_controller.rb +153 -0
- data/app/decorators/thredded/base_topic_decorator.rb +14 -0
- data/app/decorators/thredded/base_user_topic_decorator.rb +63 -0
- data/app/decorators/thredded/messageboard_decorator.rb +41 -0
- data/app/decorators/thredded/post_decorator.rb +40 -0
- data/app/decorators/thredded/private_topic_decorator.rb +23 -0
- data/app/decorators/thredded/topic_decorator.rb +25 -0
- data/app/decorators/thredded/topic_email_decorator.rb +24 -0
- data/app/decorators/thredded/user_private_topic_decorator.rb +13 -0
- data/app/decorators/thredded/user_topic_decorator.rb +37 -0
- data/app/forms/thredded/private_topic_form.rb +126 -0
- data/app/forms/thredded/topic_form.rb +94 -0
- data/app/helpers/thredded/application_helper.rb +41 -0
- data/app/jobs/thredded/activity_updater_job.rb +20 -0
- data/app/jobs/thredded/at_notifier_job.rb +11 -0
- data/app/jobs/thredded/notify_private_topic_users_job.rb +11 -0
- data/app/mailers/thredded/base_mailer.rb +4 -0
- data/app/mailers/thredded/post_mailer.rb +15 -0
- data/app/mailers/thredded/private_post_mailer.rb +15 -0
- data/app/mailers/thredded/private_topic_mailer.rb +15 -0
- data/app/models/concerns/thredded/post_common.rb +105 -0
- data/app/models/concerns/thredded/topic_common.rb +48 -0
- data/app/models/thredded/ability.rb +60 -0
- data/app/models/thredded/category.rb +12 -0
- data/app/models/thredded/messageboard.rb +50 -0
- data/app/models/thredded/messageboard_user.rb +12 -0
- data/app/models/thredded/notification_preference.rb +17 -0
- data/app/models/thredded/null_preference.rb +11 -0
- data/app/models/thredded/null_topic.rb +15 -0
- data/app/models/thredded/null_topic_read.rb +19 -0
- data/app/models/thredded/null_user.rb +51 -0
- data/app/models/thredded/post.rb +37 -0
- data/app/models/thredded/post_notification.rb +17 -0
- data/app/models/thredded/private_post.rb +25 -0
- data/app/models/thredded/private_topic.rb +60 -0
- data/app/models/thredded/private_user.rb +6 -0
- data/app/models/thredded/stats.rb +37 -0
- data/app/models/thredded/topic.rb +104 -0
- data/app/models/thredded/topic_category.rb +6 -0
- data/app/models/thredded/user_detail.rb +26 -0
- data/app/models/thredded/user_extender.rb +33 -0
- data/app/models/thredded/user_permissions/admin/if_admin_column_true.rb +12 -0
- data/app/models/thredded/user_permissions/admin/none.rb +12 -0
- data/app/models/thredded/user_permissions/message/readers_of_writeable_boards.rb +13 -0
- data/app/models/thredded/user_permissions/moderate/if_moderator_column_true.rb +25 -0
- data/app/models/thredded/user_permissions/moderate/none.rb +25 -0
- data/app/models/thredded/user_permissions/read/all.rb +25 -0
- data/app/models/thredded/user_permissions/write/all.rb +25 -0
- data/app/models/thredded/user_permissions/write/none.rb +25 -0
- data/app/models/thredded/user_preference.rb +6 -0
- data/app/models/thredded/user_topic_read.rb +10 -0
- data/app/views/layouts/thredded/application.html.erb +15 -0
- data/app/views/thredded/categories/_category.html.erb +1 -0
- data/app/views/thredded/kaminari/_first_page.html.erb +11 -0
- data/app/views/thredded/kaminari/_gap.html.erb +8 -0
- data/app/views/thredded/kaminari/_last_page.html.erb +11 -0
- data/app/views/thredded/kaminari/_next_page.html.erb +11 -0
- data/app/views/thredded/kaminari/_page.html.erb +12 -0
- data/app/views/thredded/kaminari/_paginator.html.erb +23 -0
- data/app/views/thredded/kaminari/_prev_page.html.erb +11 -0
- data/app/views/thredded/messageboards/_messageboard.html.erb +15 -0
- data/app/views/thredded/messageboards/index.html.erb +20 -0
- data/app/views/thredded/messageboards/new.html.erb +18 -0
- data/app/views/thredded/post_mailer/at_notification.html.erb +14 -0
- data/app/views/thredded/post_mailer/at_notification.text.erb +10 -0
- data/app/views/thredded/posts/_content_field.html.erb +4 -0
- data/app/views/thredded/posts/_form.html.erb +1 -0
- data/app/views/thredded/posts/_post.html.erb +1 -0
- data/app/views/thredded/posts/_user.html.erb +3 -0
- data/app/views/thredded/posts/edit.html.erb +13 -0
- data/app/views/thredded/posts_common/_form.html.erb +10 -0
- data/app/views/thredded/posts_common/_post.html.erb +20 -0
- data/app/views/thredded/preferences/_form.html.erb +28 -0
- data/app/views/thredded/preferences/_header.html.erb +1 -0
- data/app/views/thredded/preferences/edit.html.erb +12 -0
- data/app/views/thredded/private_post_mailer/at_notification.html.erb +11 -0
- data/app/views/thredded/private_posts/_form.html.erb +1 -0
- data/app/views/thredded/private_posts/_private_post.html.erb +1 -0
- data/app/views/thredded/private_topic_mailer/message_notification.html.erb +17 -0
- data/app/views/thredded/private_topic_mailer/message_notification.text.erb +13 -0
- data/app/views/thredded/private_topics/_breadcrumbs.html.erb +4 -0
- data/app/views/thredded/private_topics/_form.html.erb +24 -0
- data/app/views/thredded/private_topics/_no_private_topics.html.erb +6 -0
- data/app/views/thredded/private_topics/_private_topic.html.erb +22 -0
- data/app/views/thredded/private_topics/index.html.erb +23 -0
- data/app/views/thredded/private_topics/new.html.erb +13 -0
- data/app/views/thredded/private_topics/show.html.erb +14 -0
- data/app/views/thredded/search/_form.html.erb +7 -0
- data/app/views/thredded/shared/_currently_online.html.erb +16 -0
- data/app/views/thredded/shared/_flash_messages.html.erb +7 -0
- data/app/views/thredded/shared/_header.html.erb +4 -0
- data/app/views/thredded/shared/_messageboard_topics_breadcrumbs.html.erb +6 -0
- data/app/views/thredded/shared/_notification_preferences.html.erb +7 -0
- data/app/views/thredded/shared/_page.html.erb +6 -0
- data/app/views/thredded/shared/_time_ago.html.erb +7 -0
- data/app/views/thredded/shared/_top_nav.html.erb +36 -0
- data/app/views/thredded/shared/_topic_nav.html.erb +22 -0
- data/app/views/thredded/theme_previews/_section_title.html.erb +3 -0
- data/app/views/thredded/theme_previews/show.html.erb +108 -0
- data/app/views/thredded/topics/_form.html.erb +23 -0
- data/app/views/thredded/topics/_recent_topics_by_user.html.erb +8 -0
- data/app/views/thredded/topics/_topic.html.erb +29 -0
- data/app/views/thredded/topics/_topic_form_admin_options.html.erb +12 -0
- data/app/views/thredded/topics/by_category.html.erb +56 -0
- data/app/views/thredded/topics/edit.html.erb +38 -0
- data/app/views/thredded/topics/index.html.erb +18 -0
- data/app/views/thredded/topics/menu/_new_topic.html.erb +3 -0
- data/app/views/thredded/topics/new.html.erb +11 -0
- data/app/views/thredded/topics/search.html.erb +9 -0
- data/app/views/thredded/topics/show.html.erb +31 -0
- data/app/views/thredded/topics_common/_header.html.erb +6 -0
- data/app/views/thredded/users/_link.html.erb +9 -0
- data/config/routes.rb +28 -0
- data/db/migrate/20160329231848_create_thredded.rb +173 -0
- data/lib/generators/thredded/install/USAGE +13 -0
- data/lib/generators/thredded/install/install_generator.rb +23 -0
- data/lib/generators/thredded/install/templates/initializer.rb +51 -0
- data/lib/html/pipeline/at_mention_filter.rb +20 -0
- data/lib/html/pipeline/bbcode_filter.rb +19 -0
- data/lib/tasks/thredded_tasks.rake +18 -0
- data/lib/thredded/at_users.rb +19 -0
- data/lib/thredded/engine.rb +35 -0
- data/lib/thredded/errors.rb +67 -0
- data/lib/thredded/main_app_route_delegator.rb +24 -0
- data/lib/thredded/messageboard_user_permissions.rb +22 -0
- data/lib/thredded/post_sql_builder.rb +12 -0
- data/lib/thredded/post_user_permissions.rb +32 -0
- data/lib/thredded/private_topic_user_permissions.rb +26 -0
- data/lib/thredded/search_parser.rb +45 -0
- data/lib/thredded/search_sql_builder.rb +21 -0
- data/lib/thredded/seed_database.rb +76 -0
- data/lib/thredded/table_sql_builder.rb +41 -0
- data/lib/thredded/topic_sql_builder.rb +11 -0
- data/lib/thredded/topic_user_permissions.rb +32 -0
- data/lib/thredded/version.rb +3 -0
- data/lib/thredded.rb +85 -0
- data/thredded.gemspec +68 -0
- metadata +248 -122
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
class NotifyPrivateTopicUsers
|
|
3
|
+
DELIVER_METHOD = Rails.version < '4.2.0' ? :deliver : :deliver_later
|
|
4
|
+
|
|
5
|
+
def initialize(private_topic)
|
|
6
|
+
@post = private_topic.posts.first || Post.new
|
|
7
|
+
@private_topic = private_topic
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def run
|
|
11
|
+
members = private_topic_recipients
|
|
12
|
+
|
|
13
|
+
return unless members.present?
|
|
14
|
+
user_emails = members.map(&:email)
|
|
15
|
+
PrivateTopicMailer
|
|
16
|
+
.message_notification(private_topic.id, user_emails)
|
|
17
|
+
.send(DELIVER_METHOD)
|
|
18
|
+
mark_notified(members)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def private_topic_recipients
|
|
22
|
+
members = private_topic.users - [private_topic.user]
|
|
23
|
+
members = exclude_those_opting_out_of_message_notifications(members)
|
|
24
|
+
members = exclude_previously_notified(members)
|
|
25
|
+
members
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
attr_reader :post, :private_topic
|
|
31
|
+
|
|
32
|
+
def mark_notified(members)
|
|
33
|
+
members.each do |member|
|
|
34
|
+
post.post_notifications.create(email: member.email)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def exclude_those_opting_out_of_message_notifications(members)
|
|
39
|
+
# TODO: implement global notification preferences for private topics.
|
|
40
|
+
members
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def exclude_previously_notified(members)
|
|
44
|
+
emails_notified = post.post_notifications.map(&:email)
|
|
45
|
+
|
|
46
|
+
members.reject do |member|
|
|
47
|
+
emails_notified.include? member.email
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
class UserReadsPrivateTopic
|
|
3
|
+
def initialize(private_topic, user)
|
|
4
|
+
@private_topic = private_topic
|
|
5
|
+
@user = user
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def run
|
|
9
|
+
private_user = Thredded::PrivateUser
|
|
10
|
+
.find_by(private_topic_id: private_topic.id, user_id: user.id)
|
|
11
|
+
private_user.update_attributes(read: true)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
attr_reader :private_topic, :user
|
|
17
|
+
|
|
18
|
+
def messageboard
|
|
19
|
+
private_topic.messageboard
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
class UserResetsPrivateTopicToUnread
|
|
3
|
+
def initialize(private_topic, user)
|
|
4
|
+
@private_topic = private_topic
|
|
5
|
+
@user = user
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def run
|
|
9
|
+
other_users = Thredded::PrivateUser
|
|
10
|
+
.where(private_topic: private_topic)
|
|
11
|
+
.where.not(user_id: user.id)
|
|
12
|
+
other_users.update_all(read: false)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
attr_reader :private_topic, :user
|
|
18
|
+
|
|
19
|
+
def messageboard
|
|
20
|
+
private_topic.messageboard
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
class ApplicationController < ::ApplicationController
|
|
3
|
+
layout Thredded.layout
|
|
4
|
+
|
|
5
|
+
helper Thredded::Engine.helpers
|
|
6
|
+
helper_method \
|
|
7
|
+
:active_users,
|
|
8
|
+
:messageboard,
|
|
9
|
+
:preferences,
|
|
10
|
+
:unread_private_topics_count,
|
|
11
|
+
:signed_in?
|
|
12
|
+
|
|
13
|
+
rescue_from \
|
|
14
|
+
CanCan::AccessDenied,
|
|
15
|
+
Thredded::Errors::MessageboardNotFound,
|
|
16
|
+
Thredded::Errors::MessageboardReadDenied,
|
|
17
|
+
Thredded::Errors::TopicCreateDenied,
|
|
18
|
+
Thredded::Errors::MessageboardCreateDenied,
|
|
19
|
+
Thredded::Errors::PrivateTopicCreateDenied do |exception|
|
|
20
|
+
redirect_to root_path,
|
|
21
|
+
flash: { alert: exception.message }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
rescue_from \
|
|
25
|
+
Thredded::Errors::EmptySearchResults,
|
|
26
|
+
Thredded::Errors::TopicNotFound do |exception|
|
|
27
|
+
redirect_to messageboard_topics_path(messageboard),
|
|
28
|
+
flash: { error: exception.message }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def signed_in?
|
|
32
|
+
!thredded_current_user.thredded_anonymous?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def unread_private_topics_count
|
|
38
|
+
@unread_private_topics_count ||= Thredded::PrivateTopic
|
|
39
|
+
.joins(:private_users)
|
|
40
|
+
.where(
|
|
41
|
+
thredded_private_users: {
|
|
42
|
+
user_id: thredded_current_user.id,
|
|
43
|
+
read: false
|
|
44
|
+
})
|
|
45
|
+
.count
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def authorize_reading(obj)
|
|
49
|
+
return if current_ability.can? :read, obj
|
|
50
|
+
|
|
51
|
+
class_name = obj.class.to_s
|
|
52
|
+
error = class_name
|
|
53
|
+
.gsub(/Thredded::/, 'Thredded::Errors::') + 'ReadDenied'
|
|
54
|
+
|
|
55
|
+
fail error.constantize
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def authorize_creating(obj)
|
|
59
|
+
obj = obj.new if obj.class == Class
|
|
60
|
+
|
|
61
|
+
return if current_ability.can? :create, obj
|
|
62
|
+
|
|
63
|
+
class_name = obj.class.to_s
|
|
64
|
+
error = class_name
|
|
65
|
+
.gsub(/Thredded::/, 'Thredded::Errors::') + 'CreateDenied'
|
|
66
|
+
|
|
67
|
+
fail error.constantize
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def update_user_activity
|
|
71
|
+
return if messageboard.nil?
|
|
72
|
+
|
|
73
|
+
Thredded::ActivityUpdaterJob.perform_later(
|
|
74
|
+
thredded_current_user.id,
|
|
75
|
+
messageboard.id
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def current_ability
|
|
80
|
+
@current_ability ||= Ability.new(thredded_current_user)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def messageboard
|
|
84
|
+
@messageboard ||= params[:messageboard_id].presence && Messageboard.find_by_slug!(params[:messageboard_id])
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def preferences
|
|
88
|
+
@preferences ||= thredded_current_user.thredded_user_preference
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def thredded_current_user
|
|
92
|
+
current_user || NullUser.new
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def active_users
|
|
96
|
+
users = if messageboard
|
|
97
|
+
messageboard.recently_active_users
|
|
98
|
+
else
|
|
99
|
+
Thredded.user_class.joins(:thredded_user_detail).merge(Thredded::UserDetail.recently_active).to_a
|
|
100
|
+
end.to_a
|
|
101
|
+
users.push(thredded_current_user) unless thredded_current_user.is_a?(NullUser)
|
|
102
|
+
users.uniq
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
class MessageboardsController < Thredded::ApplicationController
|
|
3
|
+
def index
|
|
4
|
+
@messageboards = Messageboard.where(closed: false).decorate
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def new
|
|
8
|
+
authorize_creating Messageboard
|
|
9
|
+
|
|
10
|
+
@messageboard = Messageboard.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def create
|
|
14
|
+
@messageboard = Messageboard.new(messageboard_params)
|
|
15
|
+
|
|
16
|
+
if signed_in? && @messageboard.save
|
|
17
|
+
@topic = Topic.create!(topic_params)
|
|
18
|
+
@post = Post.create!(post_params)
|
|
19
|
+
|
|
20
|
+
redirect_to root_path
|
|
21
|
+
else
|
|
22
|
+
show_sign_in_error unless signed_in?
|
|
23
|
+
render action: :new
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def show_sign_in_error
|
|
30
|
+
flash.now[:error] = 'You are not signed in. Sign in or create an account before creating your messageboard.'
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def messageboard_params
|
|
34
|
+
params
|
|
35
|
+
.require(:messageboard)
|
|
36
|
+
.permit(:description, :name, :posting_permission, :security)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def topic_params
|
|
40
|
+
{
|
|
41
|
+
messageboard: @messageboard,
|
|
42
|
+
user: thredded_current_user,
|
|
43
|
+
last_user: thredded_current_user,
|
|
44
|
+
title: "Welcome to your messageboard's very first thread",
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def post_params
|
|
49
|
+
{
|
|
50
|
+
messageboard: @messageboard,
|
|
51
|
+
postable: @topic,
|
|
52
|
+
content: "There's not a whole lot here for now.",
|
|
53
|
+
ip: request.ip,
|
|
54
|
+
user: thredded_current_user,
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
class PostsController < Thredded::ApplicationController
|
|
3
|
+
include ActionView::RecordIdentifier
|
|
4
|
+
|
|
5
|
+
load_and_authorize_resource only: [:index, :show]
|
|
6
|
+
helper_method :messageboard, :topic
|
|
7
|
+
before_filter :update_user_activity
|
|
8
|
+
|
|
9
|
+
def create
|
|
10
|
+
post = parent_topic.posts.create!(post_params)
|
|
11
|
+
|
|
12
|
+
reset_read_status if for_a_private_topic?
|
|
13
|
+
redirect_to post_path(post)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def edit
|
|
17
|
+
authorize! :edit, post
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def update
|
|
21
|
+
post.update_attributes(post_params.except(:user, :ip))
|
|
22
|
+
|
|
23
|
+
redirect_to post_path(post)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def topic
|
|
27
|
+
post.postable
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def post_path(post)
|
|
33
|
+
if for_a_private_topic?
|
|
34
|
+
private_topic_path(post.postable, anchor: dom_id(post))
|
|
35
|
+
else
|
|
36
|
+
messageboard_topic_path(messageboard, post.postable, anchor: dom_id(post))
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def reset_read_status
|
|
41
|
+
Thredded::UserResetsPrivateTopicToUnread.new(parent_topic, thredded_current_user).run
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def post_params
|
|
45
|
+
params
|
|
46
|
+
.require(:post)
|
|
47
|
+
.permit(:content)
|
|
48
|
+
.merge!(user: thredded_current_user, ip: request.remote_ip)
|
|
49
|
+
.tap { |p| p.merge!(messageboard: messageboard) unless for_a_private_topic? }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def parent_topic
|
|
53
|
+
if for_a_private_topic?
|
|
54
|
+
PrivateTopic
|
|
55
|
+
.includes(:private_users)
|
|
56
|
+
.friendly
|
|
57
|
+
.find(params[:private_topic_id])
|
|
58
|
+
else
|
|
59
|
+
Topic
|
|
60
|
+
.where(messageboard: messageboard)
|
|
61
|
+
.friendly
|
|
62
|
+
.find(params[:topic_id])
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def for_a_private_topic?
|
|
67
|
+
params[:private_topic_id].present?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def post
|
|
71
|
+
@post ||= (for_a_private_topic? ? Thredded::PrivatePost : Thredded::Post).find(params[:id])
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def current_page
|
|
75
|
+
params[:page].nil? ? 1 : params[:page].to_i
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
class PreferencesController < Thredded::ApplicationController
|
|
3
|
+
helper_method :preference
|
|
4
|
+
|
|
5
|
+
def edit
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def update
|
|
9
|
+
preference.update_attributes(preference_params)
|
|
10
|
+
|
|
11
|
+
redirect_to :back, flash: { notice: 'Your settings have been updated.' }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def preference
|
|
15
|
+
@preference ||= NotificationPreference
|
|
16
|
+
.where(messageboard_id: messageboard.id, user_id: thredded_current_user.id)
|
|
17
|
+
.first_or_create!
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def preference_params
|
|
23
|
+
params
|
|
24
|
+
.require(:notification_preference)
|
|
25
|
+
.permit(:notify_on_mention, :notify_on_message, :filter)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
class PrivateTopicsController < Thredded::ApplicationController
|
|
3
|
+
helper_method :private_topic
|
|
4
|
+
|
|
5
|
+
def index
|
|
6
|
+
@new_private_topic = PrivateTopicForm.new(user: thredded_current_user)
|
|
7
|
+
@private_topics = PrivateTopic
|
|
8
|
+
.uniq
|
|
9
|
+
.for_user(thredded_current_user)
|
|
10
|
+
.order('updated_at DESC')
|
|
11
|
+
.on_page(params[:page])
|
|
12
|
+
.load
|
|
13
|
+
@decorated_private_topics = Thredded::UserPrivateTopicDecorator
|
|
14
|
+
.decorate_all(thredded_current_user, @private_topics)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def show
|
|
18
|
+
authorize! :read, private_topic
|
|
19
|
+
UserReadsPrivateTopic.new(private_topic, thredded_current_user).run
|
|
20
|
+
|
|
21
|
+
@posts = private_topic
|
|
22
|
+
.posts
|
|
23
|
+
.includes(:user)
|
|
24
|
+
.order('id ASC')
|
|
25
|
+
|
|
26
|
+
@post = private_topic.posts.build
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def new
|
|
30
|
+
@private_topic = PrivateTopicForm.new(user: thredded_current_user)
|
|
31
|
+
authorize_creating @private_topic.private_topic
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def create
|
|
35
|
+
@private_topic = PrivateTopicForm.new(new_private_topic_params)
|
|
36
|
+
if @private_topic.save
|
|
37
|
+
NotifyPrivateTopicUsersJob
|
|
38
|
+
.perform_later(@private_topic.private_topic.id)
|
|
39
|
+
|
|
40
|
+
UserResetsPrivateTopicToUnread
|
|
41
|
+
.new(@private_topic.private_topic, thredded_current_user)
|
|
42
|
+
.run
|
|
43
|
+
|
|
44
|
+
redirect_to @private_topic.private_topic
|
|
45
|
+
else
|
|
46
|
+
render :new
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def private_topic
|
|
53
|
+
@private_topic ||= Thredded::PrivateTopic.find_by_slug(params[:id])
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def new_private_topic_params
|
|
57
|
+
params
|
|
58
|
+
.require(:private_topic)
|
|
59
|
+
.permit(:title, :locked, :sticky, :content, user_ids: [], category_ids: [])
|
|
60
|
+
.merge(
|
|
61
|
+
user: thredded_current_user,
|
|
62
|
+
ip: request.remote_ip)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
class SetupsController < Thredded::ApplicationController
|
|
3
|
+
def new
|
|
4
|
+
show_sign_in_error unless signed_in?
|
|
5
|
+
@messageboard = Messageboard.new
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def create
|
|
9
|
+
@messageboard = Messageboard.new(messageboard_params)
|
|
10
|
+
|
|
11
|
+
if signed_in? && @messageboard.save
|
|
12
|
+
@topic = Topic.create!(topic_params)
|
|
13
|
+
@post = Post.create!(post_params)
|
|
14
|
+
|
|
15
|
+
redirect_to root_path
|
|
16
|
+
else
|
|
17
|
+
show_sign_in_error unless signed_in?
|
|
18
|
+
render action: :new
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def show_sign_in_error
|
|
25
|
+
flash.now[:error] = 'You are not signed in. Sign in or create an account before creating your messageboard.'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def messageboard_params
|
|
29
|
+
params
|
|
30
|
+
.require(:messageboard)
|
|
31
|
+
.permit(:description, :name, :posting_permission, :security)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def topic_params
|
|
35
|
+
{
|
|
36
|
+
messageboard: @messageboard,
|
|
37
|
+
user: thredded_current_user,
|
|
38
|
+
last_user: thredded_current_user,
|
|
39
|
+
title: "Welcome to your messageboard's very first thread",
|
|
40
|
+
}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def post_params
|
|
44
|
+
{
|
|
45
|
+
messageboard: @messageboard,
|
|
46
|
+
postable: @topic,
|
|
47
|
+
content: "There's not a whole lot here for now.",
|
|
48
|
+
ip: request.ip,
|
|
49
|
+
user: thredded_current_user,
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
class ThemePreviewsController < Thredded::ApplicationController
|
|
3
|
+
before_filter :fail_on_empty_database, if: :no_messageboard?
|
|
4
|
+
|
|
5
|
+
def show
|
|
6
|
+
@messageboard = messageboard
|
|
7
|
+
@messageboards = Messageboard.where(closed: false).decorate
|
|
8
|
+
@topics = messageboard.topics.on_page(current_page).limit(3)
|
|
9
|
+
@decorated_topics = UserTopicDecorator.decorate_all(user, @topics)
|
|
10
|
+
@decorated_private_topics = Thredded::UserPrivateTopicDecorator
|
|
11
|
+
.decorate_all(thredded_current_user, user.thredded_private_topics)
|
|
12
|
+
@topic = @topics.find { |t| t.posts.present? } || @topics.first ||
|
|
13
|
+
@messageboard.topics.build(title: 'Hello', slug: 'hello', user: user)
|
|
14
|
+
@user_topic = UserTopicDecorator.new(user, @topic)
|
|
15
|
+
@posts = @topic.posts.first(3)
|
|
16
|
+
@post = @posts.first || @messageboard.posts.build(id: 1337, postable: @topic, content: 'Hello world', user: user)
|
|
17
|
+
@new_post = @messageboard.posts.build(postable: @topic)
|
|
18
|
+
@new_topic = TopicForm.new(messageboard: messageboard, user: Thredded::NullUser.new)
|
|
19
|
+
@new_private_topic = PrivateTopicForm.new(user: user)
|
|
20
|
+
@private_topic = PrivateTopic.all.first || PrivateTopic.new(id: 1337, title: 'Hello', user: user, last_user: user,
|
|
21
|
+
users: [user])
|
|
22
|
+
@private_post = PrivatePost.first ||
|
|
23
|
+
@private_topic.posts.build(id: 1337, postable: @private_topic, content: 'A private hello world', user: user)
|
|
24
|
+
@preference = preference
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def messageboard
|
|
28
|
+
@messageboard ||= Messageboard.first
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def preference
|
|
32
|
+
@preference ||= NotificationPreference
|
|
33
|
+
.where(messageboard_id: messageboard.id, user_id: user.id)
|
|
34
|
+
.first_or_create!
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def current_page
|
|
38
|
+
1
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def fail_on_empty_database
|
|
44
|
+
fail Thredded::Errors::DatabaseEmpty
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def no_messageboard?
|
|
48
|
+
!Thredded::Messageboard.any?
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def user
|
|
52
|
+
@user ||= if thredded_current_user.thredded_anonymous?
|
|
53
|
+
Thredded.user_class.first_or_create!(slug: 'joe', name: 'joe', email: 'joe@example.com')
|
|
54
|
+
else
|
|
55
|
+
thredded_current_user
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
class TopicsController < Thredded::ApplicationController
|
|
3
|
+
helper_method :current_page, :topic, :user_topic
|
|
4
|
+
before_filter :update_user_activity
|
|
5
|
+
|
|
6
|
+
def index
|
|
7
|
+
authorize_reading messageboard
|
|
8
|
+
|
|
9
|
+
@topics = topics
|
|
10
|
+
@decorated_topics = Thredded::UserTopicDecorator
|
|
11
|
+
.decorate_all(thredded_current_user, @topics)
|
|
12
|
+
initialize_new_topic.tap do |new_topic|
|
|
13
|
+
@new_topic = new_topic if current_ability.can?(:create, new_topic.topic)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def show
|
|
18
|
+
authorize! :read, topic
|
|
19
|
+
|
|
20
|
+
@posts = topic.posts
|
|
21
|
+
.includes(:user, :messageboard, :postable)
|
|
22
|
+
.order('id ASC')
|
|
23
|
+
.page(current_page)
|
|
24
|
+
|
|
25
|
+
@new_post = messageboard.posts.build(
|
|
26
|
+
postable: topic,
|
|
27
|
+
filter: messageboard.filter
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
update_read_status
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def search
|
|
34
|
+
@topics = Topic.search(params[:q], messageboard)
|
|
35
|
+
@decorated_topics = Thredded::UserTopicDecorator
|
|
36
|
+
.decorate_all(thredded_current_user, @topics)
|
|
37
|
+
flash.now[:notice] = "Search Results for '#{params[:q]}'"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def new
|
|
41
|
+
@new_topic = TopicForm.new(messageboard: messageboard, user: thredded_current_user)
|
|
42
|
+
authorize_creating @new_topic.topic
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def category
|
|
46
|
+
@category = messageboard.categories.friendly.find(params[:category_id])
|
|
47
|
+
@topics = @category
|
|
48
|
+
.topics
|
|
49
|
+
.unstuck
|
|
50
|
+
.order_by_updated_time
|
|
51
|
+
.on_page(current_page)
|
|
52
|
+
.load
|
|
53
|
+
@decorated_topics = Thredded::UserTopicDecorator
|
|
54
|
+
.decorate_all(thredded_current_user, @topics)
|
|
55
|
+
|
|
56
|
+
render :index
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def create
|
|
60
|
+
@new_topic = TopicForm.new(new_topic_params)
|
|
61
|
+
authorize_creating @new_topic.topic
|
|
62
|
+
if @new_topic.save
|
|
63
|
+
redirect_to messageboard_topics_path(messageboard)
|
|
64
|
+
else
|
|
65
|
+
render :new
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def edit
|
|
70
|
+
authorize! :update, topic
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def update
|
|
74
|
+
topic.update_attributes!(topic_params.merge(last_user_id: thredded_current_user.id))
|
|
75
|
+
redirect_to messageboard_topic_posts_url(messageboard, topic), flash: { notice: 'Topic updated' }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def destroy
|
|
79
|
+
authorize! :destroy, topic
|
|
80
|
+
topic.destroy!
|
|
81
|
+
redirect_to messageboard_topics_path(messageboard), flash: { notice: 'Topic deleted' }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
def initialize_new_topic
|
|
87
|
+
TopicForm.new(messageboard: messageboard, user: thredded_current_user)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def topic
|
|
91
|
+
@topic ||= messageboard.topics.find_by_slug_with_user_topic_reads!(params[:id])
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def topics
|
|
95
|
+
messageboard
|
|
96
|
+
.topics
|
|
97
|
+
.includes(:user_topic_reads, :categories, :last_user, :user)
|
|
98
|
+
.order_by_stuck_and_updated_time
|
|
99
|
+
.on_page(current_page)
|
|
100
|
+
.load
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def topic_params
|
|
104
|
+
params
|
|
105
|
+
.require(:topic)
|
|
106
|
+
.permit(:title, :locked, :sticky, category_ids: [])
|
|
107
|
+
.merge(user: thredded_current_user)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def new_topic_params
|
|
111
|
+
params
|
|
112
|
+
.require(:topic)
|
|
113
|
+
.permit(:title, :locked, :sticky, :content, category_ids: [])
|
|
114
|
+
.merge(
|
|
115
|
+
messageboard: messageboard,
|
|
116
|
+
user: thredded_current_user,
|
|
117
|
+
ip: request.remote_ip,
|
|
118
|
+
)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def topics_by_category(category_id)
|
|
122
|
+
messageboard.categories.friendly.find(category_id)
|
|
123
|
+
.topics
|
|
124
|
+
.unstuck
|
|
125
|
+
.order_by_updated
|
|
126
|
+
.on_page(current_page)
|
|
127
|
+
.load
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def current_page
|
|
131
|
+
params[:page] || 1
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def user_topic
|
|
135
|
+
@user_topic ||= UserTopicDecorator.new(thredded_current_user, topic)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def update_read_status
|
|
139
|
+
return if thredded_current_user.thredded_anonymous?
|
|
140
|
+
|
|
141
|
+
read_history = UserTopicRead.where(
|
|
142
|
+
user_id: thredded_current_user,
|
|
143
|
+
topic: topic,
|
|
144
|
+
).first_or_initialize
|
|
145
|
+
|
|
146
|
+
read_history.update_attributes(
|
|
147
|
+
farthest_post: @posts.last,
|
|
148
|
+
posts_count: topic.posts_count,
|
|
149
|
+
page: current_page,
|
|
150
|
+
)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|