dm_forum 4.2.1.5
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 +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
|