dm_forum 4.2.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +23 -0
- data/README.md +33 -0
- data/Rakefile +30 -0
- data/app/assets/javascripts/dm_forum/admin.js +20 -0
- data/app/assets/javascripts/dm_forum/application.js +16 -0
- data/app/assets/javascripts/dm_forum/dm_forum.js +3 -0
- data/app/assets/stylesheets/dm_forum/admin.css +2 -0
- data/app/assets/stylesheets/dm_forum/application.css +12 -0
- data/app/controllers/dm_forum/admin/admin_controller.rb +13 -0
- data/app/controllers/dm_forum/admin/dashboard_controller.rb +12 -0
- data/app/controllers/dm_forum/admin/forum_categories_controller.rb +80 -0
- data/app/controllers/dm_forum/admin/forum_sites_controller.rb +40 -0
- data/app/controllers/dm_forum/admin/forums_controller.rb +113 -0
- data/app/controllers/dm_forum/application_controller.rb +25 -0
- data/app/controllers/dm_forum/forum_comments_controller.rb +88 -0
- data/app/controllers/dm_forum/forum_topics_controller.rb +93 -0
- data/app/controllers/dm_forum/forums_controller.rb +45 -0
- data/app/datatables/forum_user_datatable.rb +79 -0
- data/app/helpers/dm_forum/application_helper.rb +5 -0
- data/app/helpers/dm_forum/forum_helper.rb +109 -0
- data/app/mailers/forum_notification_mailer.rb +27 -0
- data/app/models/dm_forum/concerns/ability.rb +50 -0
- data/app/models/dm_forum/concerns/user.rb +37 -0
- data/app/models/dm_forum/permitted_params.rb +38 -0
- data/app/models/forum.rb +74 -0
- data/app/models/forum_category.rb +14 -0
- data/app/models/forum_comment.rb +93 -0
- data/app/models/forum_site.rb +27 -0
- data/app/models/forum_topic.rb +146 -0
- data/app/presenters/forum_comment_presenter.rb +8 -0
- data/app/presenters/forum_common_presenter.rb +31 -0
- data/app/presenters/forum_presenter.rb +14 -0
- data/app/views/dm_forum/admin/dashboard/_widget_forum_comments.html.erb +38 -0
- data/app/views/dm_forum/admin/dashboard/widget_forum_comments.js.erb +1 -0
- data/app/views/dm_forum/admin/forum_categories/_content_toolbar.html.erb +5 -0
- data/app/views/dm_forum/admin/forum_categories/_form.html.erb +18 -0
- data/app/views/dm_forum/admin/forum_categories/edit.html.erb +3 -0
- data/app/views/dm_forum/admin/forum_categories/index.html.erb +25 -0
- data/app/views/dm_forum/admin/forum_categories/new.html.erb +3 -0
- data/app/views/dm_forum/admin/forum_categories/show.html.erb +41 -0
- data/app/views/dm_forum/admin/forum_sites/_form.html.erb +18 -0
- data/app/views/dm_forum/admin/forum_sites/edit.html.erb +2 -0
- data/app/views/dm_forum/admin/forum_sites/show.html.erb +12 -0
- data/app/views/dm_forum/admin/forums/_content_toolbar.html.erb +5 -0
- data/app/views/dm_forum/admin/forums/_form.html.erb +24 -0
- data/app/views/dm_forum/admin/forums/edit.html.erb +2 -0
- data/app/views/dm_forum/admin/forums/new.html.erb +2 -0
- data/app/views/dm_forum/admin/forums/show.html.erb +68 -0
- data/app/views/dm_forum/forum_comments/_formatting.html.erb +12 -0
- data/app/views/dm_forum/forum_comments/edit.html.erb +15 -0
- data/app/views/dm_forum/forum_topics/_comment_item.html.erb +26 -0
- data/app/views/dm_forum/forum_topics/_comments_list.html.erb +63 -0
- data/app/views/dm_forum/forum_topics/_follow_button.html.erb +3 -0
- data/app/views/dm_forum/forum_topics/_form.html.erb +24 -0
- data/app/views/dm_forum/forum_topics/edit.html.erb +13 -0
- data/app/views/dm_forum/forum_topics/new.html.erb +13 -0
- data/app/views/dm_forum/forum_topics/show.html.erb +49 -0
- data/app/views/dm_forum/forum_topics/toggle_follow.js.coffee +5 -0
- data/app/views/dm_forum/forums/_category_side_list.html.erb +28 -0
- data/app/views/dm_forum/forums/_forum_header.html.erb +14 -0
- data/app/views/dm_forum/forums/_no_forums.html.erb +1 -0
- data/app/views/dm_forum/forums/_topics_list.html.erb +86 -0
- data/app/views/dm_forum/forums/categories.html.erb +32 -0
- data/app/views/dm_forum/forums/list.html.erb +10 -0
- data/app/views/dm_forum/forums/show.html.erb +39 -0
- data/app/views/layouts/email_templates/forum_notification.html.erb +15 -0
- data/app/views/layouts/email_templates/forum_notification.text.erb +16 -0
- data/config/initializers/dm_forum.rb +0 -0
- data/config/locales/fms.cs.yml +104 -0
- data/config/locales/fms.de.yml +104 -0
- data/config/locales/fms.en.yml +104 -0
- data/config/locales/fms.fi.yml +104 -0
- data/config/locales/fms.ja.yml +104 -0
- data/config/routes.rb +43 -0
- data/db/migrate/20130103151149_create_forums.rb +72 -0
- data/db/migrate/20130424125513_add_public_forum.rb +13 -0
- data/db/migrate/20130430084925_add_forum_category.rb +7 -0
- data/db/migrate/20140201112134_delete_monitorships.rb +17 -0
- data/db/migrate/20140303121325_add_requires_subscription_forum.rb +5 -0
- data/db/migrate/20140423113420_add_forum_owner.rb +6 -0
- data/db/migrate/20160821150125_index_foreign_keys_in_fms_forum_sites.rb +5 -0
- data/db/migrate/20160821150126_index_foreign_keys_in_fms_forum_topics.rb +9 -0
- data/db/migrate/20160821150127_index_foreign_keys_in_fms_forums.rb +7 -0
- data/lib/dm_forum/engine.rb +9 -0
- data/lib/dm_forum/version.rb +3 -0
- data/lib/dm_forum.rb +4 -0
- data/lib/tasks/dm_forum_tasks.rake +4 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/ability.rb +12 -0
- data/spec/dummy/app/models/user.rb +6 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +26 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +82 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/assets.rb +8 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +17 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20141114170927_add_globalize_countries.dm_core.rb +50 -0
- data/spec/dummy/db/migrate/20141114170928_devise_create_users.dm_core.rb +46 -0
- data/spec/dummy/db/migrate/20141114170929_add_user_fields.dm_core.rb +14 -0
- data/spec/dummy/db/migrate/20141114170930_rolify_create_roles.dm_core.rb +20 -0
- data/spec/dummy/db/migrate/20141114170931_add_last_access.dm_core.rb +10 -0
- data/spec/dummy/db/migrate/20141114170932_create_versions.dm_core.rb +19 -0
- data/spec/dummy/db/migrate/20141114170933_add_object_changes_column_to_versions.dm_core.rb +12 -0
- data/spec/dummy/db/migrate/20141114170934_create_dm_core_accounts.dm_core.rb +13 -0
- data/spec/dummy/db/migrate/20141114170935_add_account_to_users.dm_core.rb +9 -0
- data/spec/dummy/db/migrate/20141114170936_create_preferences.dm_core.rb +13 -0
- data/spec/dummy/db/migrate/20141114170937_create_comments.dm_core.rb +22 -0
- data/spec/dummy/db/migrate/20141114170938_add_activity.dm_core.rb +21 -0
- data/spec/dummy/db/migrate/20141114170939_add_type_to_comments.dm_core.rb +9 -0
- data/spec/dummy/db/migrate/20141114170940_add_category.dm_core.rb +28 -0
- data/spec/dummy/db/migrate/20141114170941_create_email_table.dm_core.rb +26 -0
- data/spec/dummy/db/migrate/20141114170942_add_user_profile.dm_core.rb +46 -0
- data/spec/dummy/db/migrate/20141114170943_add_profile_email.dm_core.rb +14 -0
- data/spec/dummy/db/migrate/20141114170944_create_payment_history.dm_core.rb +37 -0
- data/spec/dummy/db/migrate/20141114170945_change_anchor_field.dm_core.rb +10 -0
- data/spec/dummy/db/migrate/20141114170946_create_user_site_profile.dm_core.rb +27 -0
- data/spec/dummy/db/migrate/20141114170947_add_avatar.dm_core.rb +12 -0
- data/spec/dummy/db/migrate/20141114170948_add_notify_to_payment_history.dm_core.rb +8 -0
- data/spec/dummy/db/migrate/20141114170949_acts_as_votable_migration.dm_core.rb +28 -0
- data/spec/dummy/db/migrate/20141114170950_add_user_site_profile_uuid.dm_core.rb +19 -0
- data/spec/dummy/db/migrate/20141114170951_add_invoice_id.dm_core.rb +7 -0
- data/spec/dummy/db/migrate/20141114170952_acts_as_follower_migration.dm_core.rb +18 -0
- data/spec/dummy/db/migrate/20141114170953_rename_invoice_id.dm_core.rb +12 -0
- data/spec/dummy/db/migrate/20141114170954_add_core_addresses.dm_core.rb +18 -0
- data/spec/dummy/db/migrate/20141114170955_papertrail_increase_column.dm_core.rb +9 -0
- data/spec/dummy/db/migrate/20141114170956_acts_as_taggable_on_migration.dm_core.rb +32 -0
- data/spec/dummy/db/migrate/20141114170957_add_missing_unique_indices.dm_core.rb +23 -0
- data/spec/dummy/db/migrate/20141114170958_add_taggings_counter_cache_to_tags.dm_core.rb +16 -0
- data/spec/dummy/db/migrate/20141114170959_create_custom_fields.dm_core.rb +40 -0
- data/spec/dummy/db/migrate/20141114170960_add_missing_taggable_index.dm_core.rb +11 -0
- data/spec/dummy/db/migrate/20141119112030_create_cms.dm_cms.rb +92 -0
- data/spec/dummy/db/migrate/20141119112031_add_account_to_cms.dm_cms.rb +11 -0
- data/spec/dummy/db/migrate/20141119112032_create_blog.dm_cms.rb +62 -0
- data/spec/dummy/db/migrate/20141119112033_add_notification_sent.dm_cms.rb +6 -0
- data/spec/dummy/db/migrate/20141119112034_add_blog_comment.dm_cms.rb +8 -0
- data/spec/dummy/db/migrate/20141119112035_add_blog_image.dm_cms.rb +6 -0
- data/spec/dummy/db/migrate/20141119112036_rename_snippet_slug.dm_cms.rb +14 -0
- data/spec/dummy/db/migrate/20141119112037_add_requires_subscription_blog.dm_cms.rb +8 -0
- data/spec/dummy/db/migrate/20141119112038_add_pages_ranked_model.dm_cms.rb +23 -0
- data/spec/dummy/db/migrate/20141119112039_add_blog_owner.dm_cms.rb +7 -0
- data/spec/dummy/db/migrate/20141119112040_create_media_files.dm_cms.rb +30 -0
- data/spec/dummy/db/migrate/20141119112041_add_cmspage_summary.dm_cms.rb +7 -0
- data/spec/dummy/db/migrate/20141119112042_add_blog_image_email_header.dm_cms.rb +6 -0
- data/spec/dummy/db/migrate/20141119112043_add_header_image.dm_cms.rb +10 -0
- data/spec/dummy/db/migrate/20160128144312_add_favored_locale.dm_core.rb +17 -0
- data/spec/dummy/db/migrate/20160128144313_update_papertrail_v4.dm_core.rb +41 -0
- data/spec/dummy/db/schema.rb +628 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/accounts.rb +9 -0
- data/spec/factories/user_profiles.rb +10 -0
- data/spec/factories/users.rb +19 -0
- data/spec/models/forum_spec.rb +9 -0
- data/spec/rails_helper.rb +70 -0
- data/spec/spec_helper.rb +85 -0
- data/spec/support/accounts.rb +17 -0
- data/spec/support/devise.rb +44 -0
- data/spec/support/fix_locale.rb +57 -0
- metadata +337 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
class ForumUserDatatable
|
2
|
+
include ActionView::Helpers::TagHelper
|
3
|
+
|
4
|
+
delegate :params, :link_to, :image_tag, :number_to_currency, :time_ago_in_words, to: :@view
|
5
|
+
delegate :url_helpers, to: 'DmForum::Engine.routes'
|
6
|
+
|
7
|
+
#------------------------------------------------------------------------------
|
8
|
+
def initialize(view, forum)
|
9
|
+
@view = view
|
10
|
+
@forum = forum
|
11
|
+
end
|
12
|
+
|
13
|
+
#------------------------------------------------------------------------------
|
14
|
+
def as_json(options = {})
|
15
|
+
{
|
16
|
+
sEcho: params[:sEcho].to_i,
|
17
|
+
iTotalRecords: User.count,
|
18
|
+
iTotalDisplayRecords: users.total_entries,
|
19
|
+
aaData: data
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
#------------------------------------------------------------------------------
|
26
|
+
def data
|
27
|
+
users.map do |user|
|
28
|
+
[
|
29
|
+
action(user),
|
30
|
+
user.country.nil? ? 'n/a' : user.country.english_name,
|
31
|
+
]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
#------------------------------------------------------------------------------
|
36
|
+
def users
|
37
|
+
@users ||= fetch_users
|
38
|
+
end
|
39
|
+
|
40
|
+
#------------------------------------------------------------------------------
|
41
|
+
def fetch_users
|
42
|
+
users = User.includes(:user_profile => [ :country ] ).references(:user_profile).order("#{sort_column} #{sort_direction}")
|
43
|
+
users = users.page(page).per_page(per_page)
|
44
|
+
if params[:sSearch].present?
|
45
|
+
users = users.where("LOWER(user_profiles.first_name) like :search OR LOWER(user_profiles.last_name) like :search OR LOWER(users.email) like :search", search: "%#{params[:sSearch]}%".downcase)
|
46
|
+
end
|
47
|
+
users
|
48
|
+
end
|
49
|
+
|
50
|
+
#------------------------------------------------------------------------------
|
51
|
+
def page
|
52
|
+
params[:iDisplayStart].to_i/per_page + 1
|
53
|
+
end
|
54
|
+
|
55
|
+
#------------------------------------------------------------------------------
|
56
|
+
def per_page
|
57
|
+
params[:iDisplayLength].to_i > 0 ? params[:iDisplayLength].to_i : 50
|
58
|
+
end
|
59
|
+
|
60
|
+
#------------------------------------------------------------------------------
|
61
|
+
def sort_column
|
62
|
+
columns = ["LOWER(user_profiles.first_name) #{sort_direction}, LOWER(user_profiles.last_name)", 'globalize_countries.english_name']
|
63
|
+
columns[params[:iSortCol_0].to_i]
|
64
|
+
end
|
65
|
+
|
66
|
+
#------------------------------------------------------------------------------
|
67
|
+
def sort_direction
|
68
|
+
params[:sSortDir_0] == "desc" ? "desc" : "asc"
|
69
|
+
end
|
70
|
+
|
71
|
+
#------------------------------------------------------------------------------
|
72
|
+
def action(user)
|
73
|
+
if @forum.member? user
|
74
|
+
icons(:checkmark) + " ".html_safe + user.full_name
|
75
|
+
else
|
76
|
+
link_to(icons(:add), url_helpers.forum_add_member_admin_forum_path(@forum, :locale => DmCore::Language.locale, :user_id => user.id), :title => 'Add Access') + " ".html_safe + user.full_name
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module DmForum
|
2
|
+
module ForumHelper
|
3
|
+
|
4
|
+
#------------------------------------------------------------------------------
|
5
|
+
def topic_title_link(topic, options)
|
6
|
+
if topic.title =~ /^\[([^\]]{1,15})\]((\s+)\w+.*)/
|
7
|
+
"<span class='flag'>#{$1}</span>" +
|
8
|
+
link_to($2.strip, forum_forum_topic_path(@forum, topic), options)
|
9
|
+
else
|
10
|
+
link_to(topic.title, forum_forum_topic_path(@forum, topic), options)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
#------------------------------------------------------------------------------
|
15
|
+
def modify_history(function, name, path, params_hash=nil)
|
16
|
+
state = "null"
|
17
|
+
query_string = "?"
|
18
|
+
if params_hash
|
19
|
+
state = params_hash.to_json
|
20
|
+
params_hash.each { |k,v| query_string << "#{k}=#{v}&" }
|
21
|
+
end
|
22
|
+
query_string = query_string.chop
|
23
|
+
%{history.#{function}(#{state}, '#{j(name)}', '#{j(path+query_string)}');}.html_safe
|
24
|
+
end
|
25
|
+
|
26
|
+
#------------------------------------------------------------------------------
|
27
|
+
def edited_on_tag(post)
|
28
|
+
if (post.updated_at - post.created_at > 5.minutes)
|
29
|
+
%{<span class='date'>#{I18n.t 'fms.post_edited', :when => time_ago_in_words(post.updated_at)}</span>}.html_safe
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# used to know if a topic has changed since we read it last
|
34
|
+
#------------------------------------------------------------------------------
|
35
|
+
def recent_topic_activity(topic)
|
36
|
+
return false unless user_signed_in?
|
37
|
+
return topic.last_updated_at > ((session[:forum_topics] ||= {})[topic.id] || last_active)
|
38
|
+
end
|
39
|
+
|
40
|
+
# used to know if a forum has changed since we read it last
|
41
|
+
#------------------------------------------------------------------------------
|
42
|
+
def recent_forum_activity(forum)
|
43
|
+
return false unless user_signed_in? && forum.recent_topic
|
44
|
+
return forum.recent_topic.last_updated_at > ((session[:forums] ||= {})[forum.id] || last_active)
|
45
|
+
end
|
46
|
+
|
47
|
+
#------------------------------------------------------------------------------
|
48
|
+
def last_active
|
49
|
+
session[:last_active] ||= Time.now.utc
|
50
|
+
end
|
51
|
+
|
52
|
+
# Ripe for optimization
|
53
|
+
#------------------------------------------------------------------------------
|
54
|
+
def voice_count
|
55
|
+
pluralize ForumSite.site.forum_topics.to_a.sum { |t| t.voice_count }, 'voice'
|
56
|
+
end
|
57
|
+
|
58
|
+
#------------------------------------------------------------------------------
|
59
|
+
def feed_icon_tag(title, url)
|
60
|
+
# (@feed_icons ||= []) << { :url => url, :title => title }
|
61
|
+
# link_to image_tag('feed-icon.png', :size => '14x14', :alt => "Subscribe to #{title}"), url
|
62
|
+
end
|
63
|
+
|
64
|
+
#------------------------------------------------------------------------------
|
65
|
+
def forum_crumbs(forum = nil)
|
66
|
+
seperator = "<span class='arrow'><i class='icon-angle-right'></i></span>".html_safe
|
67
|
+
out = "".html_safe
|
68
|
+
out += link_to(I18n.t('fms.forums'), forum_root_path) + seperator
|
69
|
+
if forum
|
70
|
+
out += link_to(forum.name, forum_path(forum))
|
71
|
+
page = session[:forum_page] ? session[:forum_page][forum.id] : nil
|
72
|
+
if page and page != 1
|
73
|
+
out += "<small style='color:#ccc'>(".html_safe
|
74
|
+
out += link_to(I18n.t('fms.page_nr'), forum_path(:id => forum, :page => page))
|
75
|
+
out += ")</small>".html_safe
|
76
|
+
end
|
77
|
+
out += seperator
|
78
|
+
end
|
79
|
+
return out
|
80
|
+
end
|
81
|
+
|
82
|
+
#------------------------------------------------------------------------------
|
83
|
+
def forum_topic_icon(forum_topic)
|
84
|
+
if recent_topic_activity(forum_topic)
|
85
|
+
style = "style='color:green'"
|
86
|
+
recent_txt = I18n.t('fms.views_forums.recent_activity')
|
87
|
+
else
|
88
|
+
stlye = ''
|
89
|
+
recent_txt = I18n.t('fms.views_forums.no_recent_activity')
|
90
|
+
end
|
91
|
+
if forum_topic.locked?
|
92
|
+
"<i class='icon-lock icon-large' #{style} title='#{I18n.t('fms.views_forums.comma_locked_topic')}'></i>".html_safe
|
93
|
+
else
|
94
|
+
"<i class='icon-comments icon-large' #{style} title='#{recent_txt}'></i>".html_safe
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
#------------------------------------------------------------------------------
|
99
|
+
def forum_comment_user_state(forum_comment)
|
100
|
+
if forum_comment.user.is_admin?
|
101
|
+
I18n.t 'fms.user_is_administrator', :default => 'Administator'
|
102
|
+
elsif can?(:moderate, forum_comment.forum_topic.forum)
|
103
|
+
I18n.t 'fms.user_is_moderator', :default => 'Moderator'
|
104
|
+
elsif forum_comment.user.suspended?
|
105
|
+
forum_comment.user.state
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class ForumNotificationMailer < DmCore::SiteMailer
|
2
|
+
|
3
|
+
helper DmCore::LiquidHelper
|
4
|
+
helper DmCore::UrlHelper
|
5
|
+
helper DmCore::AccountHelper
|
6
|
+
|
7
|
+
#------------------------------------------------------------------------------
|
8
|
+
def follower_notification(user, topic, comment_list)
|
9
|
+
account = topic.account
|
10
|
+
@subject = "Commets: #{topic.title}"
|
11
|
+
@recipients = user.email
|
12
|
+
@topic = topic
|
13
|
+
@comment_list = comment_list
|
14
|
+
@topic_link = dm_forum.forum_forum_topic_url(topic.forum.slug, topic.slug, locale: I18n.locale)
|
15
|
+
@forum_link = dm_forum.forum_show_url(topic.forum.slug, locale: I18n.locale)
|
16
|
+
|
17
|
+
headers = { "Return-Path" => account.preferred_smtp_from_email }
|
18
|
+
mail( from: account.preferred_smtp_from_email,
|
19
|
+
reply_to: account.preferred_smtp_from_email,
|
20
|
+
to: @recipients, subject: @subject,
|
21
|
+
theme: account.account_prefix) do |format|
|
22
|
+
format.text { render "layouts/email_templates/forum_notification.text.erb" }
|
23
|
+
format.html { render "layouts/email_templates/forum_notification.html.erb" }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Wrap forum specific CanCan rules. Should be included in the main app's
|
2
|
+
# Ability class.
|
3
|
+
# NOTE: When checking abilities, don't check for Class level abilities,
|
4
|
+
# unless you don't care about the instance level. For example, don't
|
5
|
+
# use both styles
|
6
|
+
# can? :moderate, Forum
|
7
|
+
# can? :moderate, @forum
|
8
|
+
# In this case, if you need to check the class level, then use specific
|
9
|
+
# current_user.has_role? :moderator, Forum
|
10
|
+
#------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
module DmForum
|
13
|
+
module Concerns
|
14
|
+
module Ability
|
15
|
+
def dm_forum_abilities(user)
|
16
|
+
if user
|
17
|
+
#--- Admin
|
18
|
+
if user.has_role?(:forum_manager)
|
19
|
+
can :manage_forums, :all
|
20
|
+
can :access_admin, :all
|
21
|
+
end
|
22
|
+
|
23
|
+
#--- Forum
|
24
|
+
can(:read, Forum) { |forum| forum.can_be_read_by?(user) }
|
25
|
+
can(:reply, Forum) { |forum| forum.can_be_replied_by?(user) }
|
26
|
+
can :moderate, Forum, :id => Forum.published.with_role(:moderator, user).map(&:id)
|
27
|
+
|
28
|
+
#--- Comment
|
29
|
+
can :edit, ForumComment, :user_id => user.id
|
30
|
+
else
|
31
|
+
#--- can only read/see public forums when not logged in
|
32
|
+
can(:read, Forum) { |forum| forum.can_be_read_by?(user) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
#------------------------------------------------------------------------------
|
40
|
+
# The abilities get basically compiled. So if you use
|
41
|
+
#
|
42
|
+
# can :moderate, Forum, :id => Forum.with_role(:moderator, user).map(&:id)
|
43
|
+
#
|
44
|
+
# this will execute the Forum.with_role query once during Ability.new. However
|
45
|
+
#
|
46
|
+
# can :moderate, Forum do |forum|
|
47
|
+
# user.has_role? :moderator, forum
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# this will execute the has_role? block on each call to can?
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# Extends the User model with hooks for the Forum
|
2
|
+
#------------------------------------------------------------------------------
|
3
|
+
module DmForum
|
4
|
+
module Concerns
|
5
|
+
module User
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
# 'included do' causes the included code to be evaluated in the
|
9
|
+
# conext where it is included (post.rb), rather than be
|
10
|
+
# executed in the module's context (blorgh/concerns/models/post).
|
11
|
+
#------------------------------------------------------------------------------
|
12
|
+
included do
|
13
|
+
|
14
|
+
has_many :forum_comments, {:as => :commentable, :dependent => :delete_all}
|
15
|
+
has_many :forum_topics, -> { order("#{ForumTopic.table_name}.created_at desc") }
|
16
|
+
|
17
|
+
#------------------------------------------------------------------------------
|
18
|
+
def available_forums
|
19
|
+
@available_forums ||= site.ordered_forums - forums
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
#------------------------------------------------------------------------------
|
24
|
+
module ClassMethods
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# {todo} non-working attempts to include this automatically if the forum engine is being used,
|
32
|
+
# so that it doesn't have to be added to the application's user.rb file by hand
|
33
|
+
#------------------------------------------------------------------------------
|
34
|
+
# class User
|
35
|
+
# include DmForum::Concerns::User
|
36
|
+
# end
|
37
|
+
# User.send :include, DmForum::Concerns::User
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module DmForum
|
2
|
+
module PermittedParams
|
3
|
+
|
4
|
+
#------------------------------------------------------------------------------
|
5
|
+
def forum_site_params
|
6
|
+
params.require(:forum_site).permit! if can? :manage_forums, :all
|
7
|
+
end
|
8
|
+
|
9
|
+
#------------------------------------------------------------------------------
|
10
|
+
def forum_category_params
|
11
|
+
params.require(:forum_category).permit! if can? :manage_forums, :all
|
12
|
+
end
|
13
|
+
|
14
|
+
#------------------------------------------------------------------------------
|
15
|
+
def forum_params
|
16
|
+
params.require(:forum).permit! if can? :manage_forums, :all
|
17
|
+
end
|
18
|
+
|
19
|
+
#------------------------------------------------------------------------------
|
20
|
+
def forum_topic_params
|
21
|
+
if can? :manage_forums, :all
|
22
|
+
params.require(:forum_topic).permit!
|
23
|
+
else
|
24
|
+
params.require(:forum_topic).permit(:title, :body)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
#------------------------------------------------------------------------------
|
29
|
+
def forum_comment_params
|
30
|
+
if can? :manage_forums, :all
|
31
|
+
params.require(:forum_comment).permit!
|
32
|
+
else
|
33
|
+
params.require(:forum_comment).permit(:title, :body)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/app/models/forum.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
class Forum < ActiveRecord::Base
|
2
|
+
include DmCore::Concerns::PublicPrivate
|
3
|
+
|
4
|
+
self.table_name = 'fms_forums'
|
5
|
+
|
6
|
+
# --- FriendlyId
|
7
|
+
extend FriendlyId
|
8
|
+
friendly_id :name, use: :scoped, scope: :account_id
|
9
|
+
validates_presence_of :slug
|
10
|
+
before_save :normalize_slug
|
11
|
+
|
12
|
+
resourcify
|
13
|
+
|
14
|
+
include RankedModel
|
15
|
+
ranks :row_order, :with_same => :forum_category_id
|
16
|
+
|
17
|
+
belongs_to :forum_site
|
18
|
+
belongs_to :forum_category, :class_name => 'ForumCategory'
|
19
|
+
has_many :forum_topics, -> { order('sticky desc, last_updated_at desc') }, :dependent => :destroy
|
20
|
+
belongs_to :owner, :polymorphic => true
|
21
|
+
|
22
|
+
# this is used to see if a forum is "fresh"... we can't use topics because it puts
|
23
|
+
# stickies first even if they are not the most recently modified
|
24
|
+
has_many :recent_topics, -> { includes(:user).order('last_updated_at DESC') }, :class_name => 'ForumTopic'
|
25
|
+
has_one :recent_topic, -> { order('last_updated_at DESC') }, :class_name => 'ForumTopic'
|
26
|
+
|
27
|
+
default_scope { where(account_id: Account.current.id).order(:row_order) }
|
28
|
+
scope :published, -> { where(:published => true) }
|
29
|
+
|
30
|
+
# --- validations
|
31
|
+
validates_presence_of :name
|
32
|
+
|
33
|
+
# If user set slug sepcifically, we need to make sure it's been normalized
|
34
|
+
#------------------------------------------------------------------------------
|
35
|
+
def normalize_slug
|
36
|
+
self.slug = normalize_friendly_id(self.slug)
|
37
|
+
end
|
38
|
+
|
39
|
+
# regenerate slug if it's blank
|
40
|
+
#------------------------------------------------------------------------------
|
41
|
+
def should_generate_new_friendly_id?
|
42
|
+
self.slug.blank?
|
43
|
+
end
|
44
|
+
|
45
|
+
# use babosa gem (to_slug) to allow better handling of multi-language slugs
|
46
|
+
#------------------------------------------------------------------------------
|
47
|
+
def normalize_friendly_id(text)
|
48
|
+
text.to_s.to_slug.normalize.to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
#------------------------------------------------------------------------------
|
52
|
+
def followed_topics(user)
|
53
|
+
user.following.following_by_type('ForumTopic').where(forum_id: self.id)
|
54
|
+
end
|
55
|
+
|
56
|
+
#------------------------------------------------------------------------------
|
57
|
+
def to_s
|
58
|
+
name
|
59
|
+
end
|
60
|
+
|
61
|
+
# Send comment notifications to any followers
|
62
|
+
#------------------------------------------------------------------------------
|
63
|
+
def self.notify_followers(start_time, end_time = Time.now)
|
64
|
+
comments = Comment.where(commentable_type: 'ForumTopic', created_at: start_time..end_time)
|
65
|
+
comments_by_topic = comments.group_by {|i| i.commentable_id }
|
66
|
+
comments_by_topic.each do |topic_id, topic_comments|
|
67
|
+
forum_topic = ForumTopic.find(topic_id)
|
68
|
+
followers = forum_topic.followers
|
69
|
+
followers.each do |follower|
|
70
|
+
email = ForumNotificationMailer.follower_notification(follower.user, forum_topic, topic_comments).deliver_now
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class ForumCategory < Category
|
2
|
+
|
3
|
+
has_many :forums, :dependent => :destroy
|
4
|
+
|
5
|
+
# Are any of the forums readable by this user? One positive is all need...
|
6
|
+
#------------------------------------------------------------------------------
|
7
|
+
def any_readable_forums?(user)
|
8
|
+
if user && user.is_admin?
|
9
|
+
true
|
10
|
+
else
|
11
|
+
forums.any? { |f| f.can_be_read_by?(user) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
class ForumComment < Comment
|
2
|
+
|
3
|
+
#--- counter cache is set in the Comment model
|
4
|
+
belongs_to :forum_topic, :polymorphic => true, :foreign_key => :commentable_id, :foreign_type => :commentable_type
|
5
|
+
|
6
|
+
#--- update counter cache in forum
|
7
|
+
after_create :increment_forum_counter_cache
|
8
|
+
after_destroy :decrement_forum_counter_cache
|
9
|
+
|
10
|
+
default_scope { where(account_id: Account.current.id) }
|
11
|
+
|
12
|
+
validates_presence_of :user_id, :body
|
13
|
+
validate :topic_is_not_locked
|
14
|
+
|
15
|
+
after_create :update_cached_fields
|
16
|
+
after_update :update_cached_fields
|
17
|
+
after_destroy :update_cached_fields
|
18
|
+
|
19
|
+
self.per_page = 10
|
20
|
+
|
21
|
+
# For a forum topic, we have one root comment, which is the body of the topic.
|
22
|
+
# All other comments are either children or siblings
|
23
|
+
#------------------------------------------------------------------------------
|
24
|
+
def self.create_comment(forum_topic, body, user, parent_comment = nil)
|
25
|
+
unless parent_comment
|
26
|
+
#--- if it's the first comment, make it the root, otherwise it's a child
|
27
|
+
parent_comment = (forum_topic.forum_comments.empty? ? nil : forum_topic.forum_comments[0].root)
|
28
|
+
end
|
29
|
+
forum_topic.forum_comments.build(:body => body).tap do |comment|
|
30
|
+
comment.user = user
|
31
|
+
comment.parent = parent_comment
|
32
|
+
comment.save
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
#------------------------------------------------------------------------------
|
37
|
+
def self.search(query, options = {})
|
38
|
+
#--- (Beast) had to change the other join string since it conflicts when we bring parents in
|
39
|
+
options[:conditions] ||= ["LOWER(#{ForumComment.table_name}.body) LIKE ?", "%#{query}%"] unless query.blank?
|
40
|
+
options[:select] ||= "#{ForumComment.table_name}.*, #{ForumTopic.table_name}.title as topic_title, f.name as forum_name"
|
41
|
+
options[:joins] ||= "inner join #{ForumTopic.table_name} on #{ForumComment.table_name}.topic_id = #{ForumTopic.table_name}.id " +
|
42
|
+
"inner join #{Forum.table_name} as f on #{ForumTopic.table_name}.forum_id = f.id"
|
43
|
+
options[:order] ||= "#{ForumComment.table_name}.created_at DESC"
|
44
|
+
options[:count] ||= {:select => "#{ForumComment.table_name}.id"}
|
45
|
+
paginate options
|
46
|
+
end
|
47
|
+
|
48
|
+
#------------------------------------------------------------------------------
|
49
|
+
def self.search_monitored(user_id, query, options = {})
|
50
|
+
#--- (Beast) Same as above, but select only posts in topics monitored by the given user
|
51
|
+
# [todo]
|
52
|
+
# options[:conditions] ||= ["LOWER(#{ForumComment.table_name}.body) LIKE ?", "%#{query}%"] unless query.blank?
|
53
|
+
# options[:select] ||= "#{ForumComment.table_name}.*, #{ForumTopic.table_name}.title as topic_title, f.name as forum_name"
|
54
|
+
# options[:joins] ||= "inner join #{ForumTopic.table_name} on #{ForumComment.table_name}.topic_id = #{ForumTopic.table_name}.id " +
|
55
|
+
# "inner join #{Forum.table_name} as f on #{ForumTopic.table_name}.forum_id = f.id " +
|
56
|
+
# "inner join #{Monitorship.table_name} as m on #{ForumComment.table_name}.topic_id = m.topic_id AND " +
|
57
|
+
# "m.user_id = #{user_id} AND m.active != 0"
|
58
|
+
# options[:order] ||= "#{ForumComment.table_name}.created_at DESC"
|
59
|
+
# options[:count] ||= {:select => "#{ForumComment.table_name}.id"}
|
60
|
+
# paginate options
|
61
|
+
end
|
62
|
+
|
63
|
+
#------------------------------------------------------------------------------
|
64
|
+
def forum_name
|
65
|
+
forum_topic.forum.name
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
|
70
|
+
#------------------------------------------------------------------------------
|
71
|
+
def update_cached_fields
|
72
|
+
forum_topic.update_cached_comment_fields(self) unless forum_topic.nil?
|
73
|
+
end
|
74
|
+
|
75
|
+
#------------------------------------------------------------------------------
|
76
|
+
def topic_is_not_locked
|
77
|
+
errors.add(:base, "Topic is locked") if forum_topic && forum_topic.locked? && forum_topic.comments_count > 0
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# Since we can't have a belongs_to to the specific forum, update the comment
|
83
|
+
# counter cache by hand
|
84
|
+
#------------------------------------------------------------------------------
|
85
|
+
def increment_forum_counter_cache
|
86
|
+
Forum.increment_counter( 'comments_count', self.forum_topic.forum.id )
|
87
|
+
end
|
88
|
+
|
89
|
+
def decrement_forum_counter_cache
|
90
|
+
Forum.decrement_counter( 'comments_count', self.forum_topic.forum.id ) unless self.forum_topic.nil?
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class ForumSite < ActiveRecord::Base
|
2
|
+
class UndefinedError < StandardError; end
|
3
|
+
|
4
|
+
self.table_name = 'fms_forum_sites'
|
5
|
+
|
6
|
+
has_many :forums, -> { where(is_public: true) }
|
7
|
+
has_many :all_forums, :class_name => 'Forum'
|
8
|
+
has_many :forum_topics, :through => :forums
|
9
|
+
has_many :forum_comments, :through => :forums
|
10
|
+
|
11
|
+
default_scope { where(account_id: Account.current.id) }
|
12
|
+
|
13
|
+
attr_readonly :comments_count, :forum_topics_count, :users_online
|
14
|
+
|
15
|
+
|
16
|
+
# There is only one forum site per account
|
17
|
+
#------------------------------------------------------------------------------
|
18
|
+
def self.site
|
19
|
+
ForumSite.first
|
20
|
+
end
|
21
|
+
|
22
|
+
#------------------------------------------------------------------------------
|
23
|
+
def ordered_forums
|
24
|
+
forums
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|