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,104 @@
|
|
|
1
|
+
require 'thredded/search_sql_builder'
|
|
2
|
+
|
|
3
|
+
module Thredded
|
|
4
|
+
class Topic < ActiveRecord::Base
|
|
5
|
+
include TopicCommon
|
|
6
|
+
|
|
7
|
+
scope :for_messageboard, -> messageboard { where(messageboard_id: messageboard.id) }
|
|
8
|
+
|
|
9
|
+
extend FriendlyId
|
|
10
|
+
friendly_id :title, use: [:history, :scoped], scope: :messageboard
|
|
11
|
+
|
|
12
|
+
belongs_to :messageboard,
|
|
13
|
+
counter_cache: true,
|
|
14
|
+
touch: true
|
|
15
|
+
validates_presence_of :messageboard_id
|
|
16
|
+
|
|
17
|
+
belongs_to :user_detail,
|
|
18
|
+
primary_key: :user_id,
|
|
19
|
+
foreign_key: :user_id,
|
|
20
|
+
inverse_of: :topics,
|
|
21
|
+
counter_cache: :topics_count
|
|
22
|
+
|
|
23
|
+
has_many :posts,
|
|
24
|
+
class_name: 'Thredded::Post',
|
|
25
|
+
foreign_key: :postable_id,
|
|
26
|
+
inverse_of: :postable,
|
|
27
|
+
dependent: :destroy
|
|
28
|
+
has_many :topic_categories, dependent: :destroy
|
|
29
|
+
has_many :categories, through: :topic_categories
|
|
30
|
+
has_many :user_topic_reads, dependent: :destroy
|
|
31
|
+
|
|
32
|
+
def self.stuck
|
|
33
|
+
where(sticky: true)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.unstuck
|
|
37
|
+
where(sticky: false)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.order_by_updated_time
|
|
41
|
+
order('thredded_topics.updated_at DESC')
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.order_by_stuck_and_updated_time
|
|
45
|
+
order('thredded_topics.sticky DESC, thredded_topics.updated_at DESC')
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.search(query, messageboard)
|
|
49
|
+
results = find_by_sql(SearchSqlBuilder.new(query, messageboard).build)
|
|
50
|
+
fail(Thredded::Errors::EmptySearchResults, query) if results.empty?
|
|
51
|
+
results
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def self.find_by_slug_with_user_topic_reads!(slug)
|
|
55
|
+
includes(:user_topic_reads).friendly.find(slug)
|
|
56
|
+
rescue ActiveRecord::RecordNotFound
|
|
57
|
+
raise Thredded::Errors::TopicNotFound
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def decorate
|
|
61
|
+
TopicDecorator.new(self)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def public?
|
|
65
|
+
true
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# rubocop:disable all
|
|
69
|
+
def self.inherited(child)
|
|
70
|
+
child.instance_eval do
|
|
71
|
+
def model_name
|
|
72
|
+
Topic.model_name
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
super
|
|
77
|
+
end
|
|
78
|
+
# rubocop:enable all
|
|
79
|
+
|
|
80
|
+
def self.select_options
|
|
81
|
+
subclasses.map(&:to_s).sort
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def self.recent
|
|
85
|
+
limit(10)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def updating?
|
|
89
|
+
id.present?
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def categories_to_sentence
|
|
93
|
+
categories.map(&:name).to_sentence if categories.any?
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def users_to_sentence
|
|
97
|
+
[]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def should_generate_new_friendly_id?
|
|
101
|
+
title_changed?
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
class UserDetail < ActiveRecord::Base
|
|
3
|
+
belongs_to :user, class_name: Thredded.user_class
|
|
4
|
+
validates :user_id, presence: true
|
|
5
|
+
|
|
6
|
+
has_many :topics, class_name: 'Thredded::Topic', foreign_key: :user_id, primary_key: :user_id
|
|
7
|
+
has_many :posts, class_name: 'Thredded::Post', foreign_key: :user_id, primary_key: :user_id
|
|
8
|
+
has_many :private_posts, class_name: 'Thredded::PrivatePost', foreign_key: :user_id, primary_key: :user_id
|
|
9
|
+
|
|
10
|
+
scope :recently_active, -> { where(arel_table[:last_seen_at].gt(Thredded.active_user_threshold.ago)) }
|
|
11
|
+
|
|
12
|
+
# Find or create and return a {UserDetail} for a given user.
|
|
13
|
+
# @param user [Thredded.user_class]
|
|
14
|
+
# @return [Thredded::UserDetail] a persisted UserDetail.
|
|
15
|
+
def self.for_user(user)
|
|
16
|
+
for_user_id(user.id)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Find or create and return a {UserDetail} for a given user ID.
|
|
20
|
+
# @param user_id [Fixnum, String]
|
|
21
|
+
# @return [Thredded::UserDetail] a persisted UserDetail.
|
|
22
|
+
def self.for_user_id(user_id)
|
|
23
|
+
where(user_id: user_id).first_or_create!
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require_relative './user_permissions/read/all'
|
|
2
|
+
require_relative './user_permissions/write/all'
|
|
3
|
+
require_relative './user_permissions/message/readers_of_writeable_boards'
|
|
4
|
+
require_relative './user_permissions/moderate/if_moderator_column_true'
|
|
5
|
+
require_relative './user_permissions/admin/if_admin_column_true'
|
|
6
|
+
|
|
7
|
+
module Thredded
|
|
8
|
+
module UserExtender
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
11
|
+
include ::Thredded::UserPermissions::Read::All
|
|
12
|
+
include ::Thredded::UserPermissions::Write::All
|
|
13
|
+
include ::Thredded::UserPermissions::Message::ReadersOfWriteableBoards
|
|
14
|
+
include ::Thredded::UserPermissions::Moderate::IfModeratorColumnTrue
|
|
15
|
+
include ::Thredded::UserPermissions::Admin::IfAdminColumnTrue
|
|
16
|
+
|
|
17
|
+
included do
|
|
18
|
+
has_many :thredded_notification_preferences, class_name: 'Thredded::NotificationPreference', foreign_key: 'user_id'
|
|
19
|
+
has_many :thredded_posts, class_name: 'Thredded::Post', foreign_key: 'user_id'
|
|
20
|
+
has_many :thredded_private_topics, through: :thredded_private_users, class_name: 'Thredded::PrivateTopic', source: :private_topic
|
|
21
|
+
has_many :thredded_private_users, class_name: 'Thredded::PrivateUser', foreign_key: 'user_id'
|
|
22
|
+
has_many :thredded_topics, class_name: 'Thredded::Topic', foreign_key: 'user_id'
|
|
23
|
+
has_many :thredded_read_topics, class_name: 'Thredded::UserTopicRead', foreign_key: 'user_id'
|
|
24
|
+
|
|
25
|
+
has_one :thredded_user_detail, class_name: 'Thredded::UserDetail', foreign_key: 'user_id'
|
|
26
|
+
has_one :thredded_user_preference, class_name: 'Thredded::UserPreference', foreign_key: 'user_id'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def thredded_anonymous?
|
|
30
|
+
false
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
module UserPermissions
|
|
3
|
+
module Message
|
|
4
|
+
module ReadersOfWriteableBoards
|
|
5
|
+
# @return [ActiveRecord::Relation<Thredded.user_class>] the users this user can include in a private topic
|
|
6
|
+
def thredded_can_message_users
|
|
7
|
+
# By default, return everyone who can read the messageboards this user can post in
|
|
8
|
+
Thredded.user_class.thredded_messageboards_readers(thredded_can_write_messageboards)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
module UserPermissions
|
|
3
|
+
module Moderate
|
|
4
|
+
module IfModeratorColumnTrue
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
included { extend ClassMethods }
|
|
7
|
+
|
|
8
|
+
# @return [ActiveRecord::Relation<Thredded::Messageboard>] messageboards that the user can moderate
|
|
9
|
+
def thredded_can_moderate_messageboards
|
|
10
|
+
send(Thredded.moderator_column) ? Thredded::Messageboard.all : Thredded::Messageboard.none
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module ClassMethods
|
|
14
|
+
# Users that can moderate the given messageboards.
|
|
15
|
+
#
|
|
16
|
+
# @param _messageboards [Array<Thredded::Messageboard>]
|
|
17
|
+
# @return [ActiveRecord::Relation<Thredded.user_class>] users that can moderate the given messageboards
|
|
18
|
+
def thredded_messageboards_moderators(_messageboards)
|
|
19
|
+
where(Thredded.moderator_column => true)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
module UserPermissions
|
|
3
|
+
module Moderate
|
|
4
|
+
module None
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
included { extend ClassMethods }
|
|
7
|
+
|
|
8
|
+
# @return [ActiveRecord::Relation<Thredded::Messageboard>] messageboards that the user can moderate
|
|
9
|
+
def thredded_can_moderate_messageboards
|
|
10
|
+
Thredded::Messageboard.none
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module ClassMethods
|
|
14
|
+
# Users that can moderate the given messageboards.
|
|
15
|
+
#
|
|
16
|
+
# @param _messageboards [Array<Thredded::Messageboard>]
|
|
17
|
+
# @return [ActiveRecord::Relation<Thredded.user_class>] users that can moderate the given messageboards
|
|
18
|
+
def thredded_messageboards_moderators(_messageboards)
|
|
19
|
+
none
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
module UserPermissions
|
|
3
|
+
module Read
|
|
4
|
+
module All
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
included { extend ClassMethods }
|
|
7
|
+
|
|
8
|
+
# @return [ActiveRecord::Relation<Thredded::Messageboard>] messageboards that the user can read
|
|
9
|
+
def thredded_can_read_messageboards
|
|
10
|
+
Thredded::Messageboard.all
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module ClassMethods
|
|
14
|
+
# Users that can read the given messageboards.
|
|
15
|
+
#
|
|
16
|
+
# @param _messageboards [Array<Thredded::Messageboard>]
|
|
17
|
+
# @return [ActiveRecord::Relation<Thredded.user_class>] users that can read the given messageboards
|
|
18
|
+
def thredded_messageboards_readers(_messageboards)
|
|
19
|
+
all
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
module UserPermissions
|
|
3
|
+
module Write
|
|
4
|
+
module All
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
included { extend ClassMethods }
|
|
7
|
+
|
|
8
|
+
# @return [ActiveRecord::Relation<Thredded::Messageboard>] messageboards that the user can post in
|
|
9
|
+
def thredded_can_write_messageboards
|
|
10
|
+
Thredded::Messageboard.all
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module ClassMethods
|
|
14
|
+
# Users that can post to the given messageboards.
|
|
15
|
+
#
|
|
16
|
+
# @param _messageboards [Array<Thredded::Messageboard>]
|
|
17
|
+
# @return [ActiveRecord::Relation<Thredded.user_class>] users that can post to the given messageboards
|
|
18
|
+
def thredded_messageboards_writers(_messageboards)
|
|
19
|
+
all
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
module UserPermissions
|
|
3
|
+
module Write
|
|
4
|
+
module None
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
included { extend ClassMethods }
|
|
7
|
+
|
|
8
|
+
# @return [ActiveRecord::Relation<Thredded::Messageboard>] messageboards that the user can post in
|
|
9
|
+
def thredded_can_write_messageboards
|
|
10
|
+
Thredded::Messageboard.none
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module ClassMethods
|
|
14
|
+
# Users that can post to the given messageboards.
|
|
15
|
+
#
|
|
16
|
+
# @param _messageboards [Array<Thredded::Messageboard>]
|
|
17
|
+
# @return [ActiveRecord::Relation<Thredded.user_class>] users that can post to the given messageboards
|
|
18
|
+
def thredded_messageboards_writers(_messageboards)
|
|
19
|
+
none
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module Thredded
|
|
2
|
+
class UserTopicRead < ActiveRecord::Base
|
|
3
|
+
belongs_to :topic
|
|
4
|
+
belongs_to :user, class_name: Thredded.user_class
|
|
5
|
+
belongs_to :farthest_post,
|
|
6
|
+
class_name: 'Thredded::Post', foreign_key: 'post_id'
|
|
7
|
+
validates :user_id, uniqueness: { scope: :topic }
|
|
8
|
+
belongs_to :post
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Thredded | <%= yield :thredded_page_title %></title>
|
|
5
|
+
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
|
|
6
|
+
<%= stylesheet_link_tag 'thredded' %>
|
|
7
|
+
<%= csrf_meta_tag %>
|
|
8
|
+
<%= javascript_include_tag 'thredded' %>
|
|
9
|
+
<%== Gravatar.prefetch_dns %>
|
|
10
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<%= yield %>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<li class="<%= category.name.underscore %>"><%= category.name %></li>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<%# Link to the "First" page
|
|
2
|
+
- available local variables
|
|
3
|
+
url: url to the first page
|
|
4
|
+
current_page: a page object for the currently displayed page
|
|
5
|
+
total_pages: total number of pages
|
|
6
|
+
per_page: number of items to fetch per page
|
|
7
|
+
remote: data-remote
|
|
8
|
+
-%>
|
|
9
|
+
<span class="first">
|
|
10
|
+
<%= link_to_unless current_page.first?, t('views.pagination.first').html_safe, url, :remote => remote %>
|
|
11
|
+
</span>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<%# Non-link tag that stands for skipped pages...
|
|
2
|
+
- available local variables
|
|
3
|
+
current_page: a page object for the currently displayed page
|
|
4
|
+
total_pages: total number of pages
|
|
5
|
+
per_page: number of items to fetch per page
|
|
6
|
+
remote: data-remote
|
|
7
|
+
-%>
|
|
8
|
+
<span class="page gap"><%= t('views.pagination.truncate').html_safe %></span>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<%# Link to the "Last" page
|
|
2
|
+
- available local variables
|
|
3
|
+
url: url to the last page
|
|
4
|
+
current_page: a page object for the currently displayed page
|
|
5
|
+
total_pages: total number of pages
|
|
6
|
+
per_page: number of items to fetch per page
|
|
7
|
+
remote: data-remote
|
|
8
|
+
-%>
|
|
9
|
+
<span class="last">
|
|
10
|
+
<%= link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, :remote => remote %>
|
|
11
|
+
</span>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<%# Link to the "Next" page
|
|
2
|
+
- available local variables
|
|
3
|
+
url: url to the next page
|
|
4
|
+
current_page: a page object for the currently displayed page
|
|
5
|
+
total_pages: total number of pages
|
|
6
|
+
per_page: number of items to fetch per page
|
|
7
|
+
remote: data-remote
|
|
8
|
+
-%>
|
|
9
|
+
<span class="next">
|
|
10
|
+
<%= link_to_unless current_page.last?, t('views.pagination.next').html_safe, url, :rel => 'next', :remote => remote %>
|
|
11
|
+
</span>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<%# Link showing page number
|
|
2
|
+
- available local variables
|
|
3
|
+
page: a page object for "this" page
|
|
4
|
+
url: url to this page
|
|
5
|
+
current_page: a page object for the currently displayed page
|
|
6
|
+
total_pages: total number of pages
|
|
7
|
+
per_page: number of items to fetch per page
|
|
8
|
+
remote: data-remote
|
|
9
|
+
-%>
|
|
10
|
+
<span class="page<%= ' current' if page.current? %>">
|
|
11
|
+
<%= link_to_unless page.current?, page, url, {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil} %>
|
|
12
|
+
</span>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<%# The container tag
|
|
2
|
+
- available local variables
|
|
3
|
+
current_page: a page object for the currently displayed page
|
|
4
|
+
total_pages: total number of pages
|
|
5
|
+
per_page: number of items to fetch per page
|
|
6
|
+
remote: data-remote
|
|
7
|
+
paginator: the paginator that renders the pagination tags inside
|
|
8
|
+
-%>
|
|
9
|
+
<%= paginator.render do -%>
|
|
10
|
+
<nav class="pagination thredded--pagination">
|
|
11
|
+
<%= first_page_tag unless current_page.first? %>
|
|
12
|
+
<%= prev_page_tag unless current_page.first? %>
|
|
13
|
+
<% each_page do |page| -%>
|
|
14
|
+
<% if page.left_outer? || page.right_outer? || page.inside_window? -%>
|
|
15
|
+
<%= page_tag page %>
|
|
16
|
+
<% elsif !page.was_truncated? -%>
|
|
17
|
+
<%= gap_tag %>
|
|
18
|
+
<% end -%>
|
|
19
|
+
<% end -%>
|
|
20
|
+
<%= next_page_tag unless current_page.last? %>
|
|
21
|
+
<%= last_page_tag unless current_page.last? %>
|
|
22
|
+
</nav>
|
|
23
|
+
<% end -%>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<%# Link to the "Previous" page
|
|
2
|
+
- available local variables
|
|
3
|
+
url: url to the previous page
|
|
4
|
+
current_page: a page object for the currently displayed page
|
|
5
|
+
total_pages: total number of pages
|
|
6
|
+
per_page: number of items to fetch per page
|
|
7
|
+
remote: data-remote
|
|
8
|
+
-%>
|
|
9
|
+
<span class="prev">
|
|
10
|
+
<%= link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, :rel => 'prev', :remote => remote %>
|
|
11
|
+
</span>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<% if current_ability.can? :read, messageboard.original %>
|
|
2
|
+
<%= link_to messageboard_topics_path(messageboard), class: 'thredded--messageboard' do %>
|
|
3
|
+
<header>
|
|
4
|
+
<h2 class="thredded--messageboard--title"><%= messageboard.name %></h2>
|
|
5
|
+
<h3 class="thredded--messageboard--meta"><%= messageboard.meta %></h3>
|
|
6
|
+
</header>
|
|
7
|
+
|
|
8
|
+
<p class="thredded--messageboard--description"><%= messageboard.description %></p>
|
|
9
|
+
|
|
10
|
+
<p class="thredded--messageboard--byline">
|
|
11
|
+
Updated <%= time_ago messageboard.latest_topic.updated_at %>
|
|
12
|
+
<cite>by <%= messageboard.latest_user %></cite>
|
|
13
|
+
</p>
|
|
14
|
+
<% end %>
|
|
15
|
+
<% end %>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<% content_for :thredded_page_title, 'Messageboards' %>
|
|
2
|
+
<% content_for :thredded_page_id, 'thredded--messageboards-index' %>
|
|
3
|
+
<% content_for :thredded_breadcrumbs do %>
|
|
4
|
+
<ul class="thredded--navigation-breadcrumbs">
|
|
5
|
+
<li>
|
|
6
|
+
<%= link_to 'All Message Boards', messageboards_path %>
|
|
7
|
+
</li>
|
|
8
|
+
</ul>
|
|
9
|
+
<% end %>
|
|
10
|
+
<%= thredded_page do %>
|
|
11
|
+
<section class="thredded--main-section thredded--messageboards">
|
|
12
|
+
<%= render @messageboards %>
|
|
13
|
+
</section>
|
|
14
|
+
|
|
15
|
+
<% if current_ability.can? :create, Thredded::Messageboard %>
|
|
16
|
+
<div class="thredded--messageboard--create">
|
|
17
|
+
<a class="thredded--button" href="<%= new_messageboard_path %>">Create a New Messageboard</a>
|
|
18
|
+
</div>
|
|
19
|
+
<% end %>
|
|
20
|
+
<% end %>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<% content_for :thredded_page_title, 'Create a New Messageboard' %>
|
|
2
|
+
<% content_for :thredded_page_id, 'thredded--messageboards-new' %>
|
|
3
|
+
<%= thredded_page do %>
|
|
4
|
+
<%= form_for @messageboard, class: 'thredded--form' do |f| %>
|
|
5
|
+
<ul class="thredded--form-list">
|
|
6
|
+
<li>
|
|
7
|
+
<%= f.label :name %>
|
|
8
|
+
<%= f.text_field :name %>
|
|
9
|
+
</li>
|
|
10
|
+
<li>
|
|
11
|
+
<%= f.label :description %>
|
|
12
|
+
<%= f.text_field :description %>
|
|
13
|
+
</li>
|
|
14
|
+
|
|
15
|
+
<li><%= f.submit 'Create New Messageboard', class: 'thredded--form--submit' %></li>
|
|
16
|
+
</ul>
|
|
17
|
+
<% end %>
|
|
18
|
+
<% end %>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<%= @post.filtered_content(self) %>
|
|
2
|
+
|
|
3
|
+
<hr />
|
|
4
|
+
|
|
5
|
+
<p>
|
|
6
|
+
This email was sent to you because <%= @post.user %> mentioned you in
|
|
7
|
+
"<%= link_to @post.postable.title, messageboard_topic_posts_url(@post.messageboard, @post.postable, anchor: "post_#{@post.id}") %>".
|
|
8
|
+
<%= link_to 'View the conversation here.', messageboard_topic_posts_url(@post.messageboard, @post.postable) %>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p>
|
|
12
|
+
To unsubscribe from these emails, update your
|
|
13
|
+
<%= link_to 'preferences', edit_messageboard_preferences_url(@post.messageboard) %>.
|
|
14
|
+
</p>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<%= @post.content %>
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
This email was sent to you because <%= @post.user %> mentioned you in
|
|
6
|
+
"<%= @post.postable.title %>". Go here to view the conversation:
|
|
7
|
+
<%= messageboard_topic_posts_url @post.messageboard, @post.postable, anchor: "post_#{@post.id}" %>
|
|
8
|
+
|
|
9
|
+
To unsubscribe from these emails, update your preferences here:
|
|
10
|
+
<%= edit_messageboard_preferences_url @post.messageboard %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= render 'thredded/posts_common/form', topic: topic, post: post, button_text: button_text %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= render 'thredded/posts_common/post', post: post %>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<% content_for :thredded_page_title, 'Edit Post' %>
|
|
2
|
+
<% content_for :thredded_page_id, 'thredded--edit-post' %>
|
|
3
|
+
<%= thredded_page do %>
|
|
4
|
+
<section class="thredded--main-section">
|
|
5
|
+
<h3 class="thredded--post-form--title">Edit Post</h3>
|
|
6
|
+
|
|
7
|
+
<%= render 'thredded/posts/form',
|
|
8
|
+
messageboard: messageboard,
|
|
9
|
+
topic: topic,
|
|
10
|
+
post: @post,
|
|
11
|
+
button_text: 'Update Post' %>
|
|
12
|
+
</section>
|
|
13
|
+
<% end %>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<%= form_for (post.private_topic_post? ? [topic, post] : [messageboard, topic, post]), as: :post,
|
|
2
|
+
html: { class: 'thredded--form thredded--post-form', 'data-thredded-post-form' => true } do |form| %>
|
|
3
|
+
<ul class="thredded--form-list">
|
|
4
|
+
<%= render 'thredded/posts/content_field', form: form %>
|
|
5
|
+
|
|
6
|
+
<li>
|
|
7
|
+
<%= form.submit button_text, class: 'thredded--form--submit' %>
|
|
8
|
+
</li>
|
|
9
|
+
</ul>
|
|
10
|
+
<% end %>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<% post = Thredded::PostDecorator.new(post) %>
|
|
2
|
+
|
|
3
|
+
<%= content_tag_for :article, post, class: 'thredded--post' do %>
|
|
4
|
+
<header>
|
|
5
|
+
<%= image_tag post.avatar_url, class: 'thredded--post--avatar' unless post.user_anonymous? %>
|
|
6
|
+
<h2 class="thredded--post--user"><%= user_link post.user %></h2>
|
|
7
|
+
<p class="thredded--post--created-at"><%= time_ago post.created_at %></p>
|
|
8
|
+
|
|
9
|
+
</header>
|
|
10
|
+
|
|
11
|
+
<div class="thredded--post--content">
|
|
12
|
+
<% cache [post, 'content'] do %>
|
|
13
|
+
<%= post.filtered_content(self) %>
|
|
14
|
+
<% end %>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<% if current_ability.can? :edit, post.original %>
|
|
18
|
+
<%= link_to 'Edit Post', edit_post_path(post.original), class: 'thredded--post--edit' %>
|
|
19
|
+
<% end %>
|
|
20
|
+
<% end %>
|