radiant-forum-extension 2.1.6 → 3.0.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +20 -16
- data/Rakefile +0 -16
- data/app/controllers/forum_base_controller.rb +32 -10
- data/app/controllers/posts_controller.rb +37 -14
- data/app/helpers/forum_helper.rb +23 -16
- data/app/models/forum.rb +11 -7
- data/app/models/post.rb +53 -14
- data/app/models/post_attachment.rb +1 -1
- data/app/models/topic.rb +21 -8
- data/app/views/admin/dashboard/_forum_dashboard.html.haml +51 -0
- data/app/views/admin/forums/_form.html.haml +12 -0
- data/app/views/admin/forums/edit.html.haml +1 -1
- data/app/views/admin/forums/index.html.haml +16 -20
- data/app/views/admin/posts/_form.html.haml +2 -2
- data/app/views/admin/posts/edit.html.haml +1 -1
- data/app/views/admin/posts/index.html.haml +5 -5
- data/app/views/admin/reader_configuration/_edit_forum.html.haml +6 -0
- data/app/views/admin/reader_configuration/_forum.html.haml +5 -1
- data/app/views/admin/topics/_form.html.haml +3 -5
- data/app/views/admin/topics/edit.html.haml +1 -1
- data/app/views/admin/topics/index.html.haml +5 -5
- data/app/views/forums/_forum.html.haml +6 -5
- data/app/views/forums/_latest.html.haml +14 -12
- data/app/views/forums/_statistics.html.haml +4 -4
- data/app/views/forums/index.html.haml +8 -10
- data/app/views/forums/index.rss.builder +2 -2
- data/app/views/forums/show.html.haml +12 -15
- data/app/views/pages/_add_comment.html.haml +9 -8
- data/app/views/pages/_comments.html.haml +3 -3
- data/app/views/posts/_attachments.html.haml +1 -1
- data/app/views/posts/_confirm_delete.html.haml +7 -2
- data/app/views/posts/_context.html.haml +5 -5
- data/app/views/posts/_edit_links.html.haml +4 -4
- data/app/views/posts/_form.html.haml +15 -12
- data/app/views/posts/_ineditable.html.haml +7 -0
- data/app/views/posts/_latest.html.haml +3 -8
- data/app/views/posts/_minimal.html.haml +7 -0
- data/app/views/posts/_post.html.haml +20 -17
- data/app/views/posts/_post.rss.builder +2 -2
- data/app/views/posts/_search_form.html.haml +13 -13
- data/app/views/posts/_search_results.html.haml +15 -0
- data/app/views/posts/_search_summary.html.haml +13 -0
- data/app/views/posts/_uploader.html.haml +1 -1
- data/app/views/posts/edit.html.haml +22 -21
- data/app/views/posts/index.html.haml +12 -19
- data/app/views/posts/index.rss.builder +6 -6
- data/app/views/posts/new.html.haml +19 -22
- data/app/views/posts/remove.html.haml +15 -15
- data/app/views/posts/show.html.haml +16 -10
- data/app/views/readers/_forum_messages.html.haml +9 -6
- data/app/views/readers/_messages_summary.html.haml +1 -1
- data/app/views/shared/_standard_forum_parts.html.haml +41 -0
- data/app/views/topics/_busiest.html.haml +9 -8
- data/app/views/topics/_context.html.haml +11 -8
- data/app/views/topics/_latest.html.haml +2 -2
- data/app/views/topics/_locked.html.haml +1 -1
- data/app/views/topics/_minimal.html.haml +2 -2
- data/app/views/topics/_replies.html.haml +4 -3
- data/app/views/topics/_reply.html.haml +13 -8
- data/app/views/topics/_topic.html.haml +5 -9
- data/app/views/topics/_topic.rss.builder +1 -1
- data/app/views/topics/index.html.haml +14 -10
- data/app/views/topics/index.rss.builder +2 -2
- data/app/views/topics/show.html.haml +20 -19
- data/app/views/topics/show.rss.builder +3 -3
- data/config/initializers/radiant_config.rb +4 -1
- data/config/locales/en.yml +202 -178
- data/db/migrate/002_pages_commentable.rb +1 -2
- data/db/migrate/004_sample_layout.rb +38 -15
- data/db/migrate/20110111080550_detach_observer.rb +4 -4
- data/db/migrate/20110613112823_search_text.rb +9 -0
- data/db/migrate/20110613130230_tidy_up.rb +27 -0
- data/db/migrate/20110630083446_page_replied_at.rb +11 -0
- data/forum_extension.rb +13 -11
- data/lib/commentable_model.rb +13 -9
- data/lib/forum_admin_ui.rb +6 -6
- data/lib/forum_page.rb +5 -3
- data/lib/forum_reader.rb +7 -1
- data/lib/forum_reader_sessions_controller.rb +2 -3
- data/lib/forum_tags.rb +126 -11
- data/lib/radiant-forum-extension.rb +8 -0
- data/public/cleditor/images/buttons.gif +0 -0
- data/public/cleditor/images/icons/1.gif +0 -0
- data/public/cleditor/images/icons/10.gif +0 -0
- data/public/cleditor/images/icons/11.gif +0 -0
- data/public/cleditor/images/icons/12.gif +0 -0
- data/public/cleditor/images/icons/2.gif +0 -0
- data/public/cleditor/images/icons/3.gif +0 -0
- data/public/cleditor/images/icons/4.gif +0 -0
- data/public/cleditor/images/icons/5.gif +0 -0
- data/public/cleditor/images/icons/6.gif +0 -0
- data/public/cleditor/images/icons/7.gif +0 -0
- data/public/cleditor/images/icons/8.gif +0 -0
- data/public/cleditor/images/icons/9.gif +0 -0
- data/public/cleditor/images/icons/icons.gif +0 -0
- data/public/cleditor/images/toolbar.gif +0 -0
- data/public/cleditor/jquery.cleditor.css +24 -0
- data/public/cleditor/jquery.cleditor.icon.js +65 -0
- data/public/cleditor/jquery.cleditor.js +1132 -0
- data/public/cleditor/jquery.cleditor.xhtml.js +230 -0
- data/public/javascripts/forum.js +146 -107
- data/public/stylesheets/sass/forum.sass +94 -58
- data/radiant-forum-extension.gemspec +25 -276
- data/spec/controllers/forums_controller_spec.rb +0 -7
- data/spec/controllers/posts_controller_spec.rb +20 -37
- data/spec/controllers/topics_controller_spec.rb +1 -7
- data/spec/datasets/forums_dataset.rb +38 -40
- data/spec/lib/commentable_model_spec.rb +26 -38
- data/spec/lib/forum_reader_spec.rb +0 -4
- data/spec/models/forum_spec.rb +46 -16
- data/spec/models/post_spec.rb +10 -6
- data/spec/models/topic_spec.rb +26 -17
- data/spec/spec_helper.rb +1 -0
- metadata +66 -99
- data/VERSION +0 -1
- data/app/views/forums/_standard_parts.html.haml +0 -59
- data/lib/sanitize/config/forum.rb +0 -49
- data/public/javascripts/gallery.js +0 -275
- data/public/punymce/blank.htm +0 -1
- data/public/punymce/css/content.css +0 -4
- data/public/punymce/css/editor.css +0 -58
- data/public/punymce/i18n/sv.js +0 -28
- data/public/punymce/img/icons.gif +0 -0
- data/public/punymce/img/icons_uncompressed.png +0 -0
- data/public/punymce/plugins/bbcode.js +0 -1
- data/public/punymce/plugins/bbcode_src.js +0 -50
- data/public/punymce/plugins/editsource/css/editor.css +0 -3
- data/public/punymce/plugins/editsource/editsource.js +0 -1
- data/public/punymce/plugins/editsource/editsource_src.js +0 -81
- data/public/punymce/plugins/editsource/img/icons.gif +0 -0
- data/public/punymce/plugins/emoticons/css/content.css +0 -13
- data/public/punymce/plugins/emoticons/css/editor.css +0 -17
- data/public/punymce/plugins/emoticons/emoticons.js +0 -1
- data/public/punymce/plugins/emoticons/emoticons_src.js +0 -303
- data/public/punymce/plugins/emoticons/img/emoticons.gif +0 -0
- data/public/punymce/plugins/emoticons/img/emoticons.png +0 -0
- data/public/punymce/plugins/emoticons/img/trans.gif +0 -0
- data/public/punymce/plugins/entities.js +0 -1
- data/public/punymce/plugins/entities_src.js +0 -37
- data/public/punymce/plugins/forceblocks.js +0 -1
- data/public/punymce/plugins/forceblocks_src.js +0 -465
- data/public/punymce/plugins/forcenl.js +0 -1
- data/public/punymce/plugins/forcenl_src.js +0 -26
- data/public/punymce/plugins/image/css/editor.css +0 -1
- data/public/punymce/plugins/image/image.js +0 -1
- data/public/punymce/plugins/image/image_src.js +0 -30
- data/public/punymce/plugins/image/img/icons.gif +0 -0
- data/public/punymce/plugins/link/css/editor.css +0 -2
- data/public/punymce/plugins/link/img/icons.gif +0 -0
- data/public/punymce/plugins/link/link.js +0 -1
- data/public/punymce/plugins/link/link_src.js +0 -36
- data/public/punymce/plugins/paste.js +0 -1
- data/public/punymce/plugins/paste_src.js +0 -169
- data/public/punymce/plugins/protect.js +0 -1
- data/public/punymce/plugins/protect_src.js +0 -30
- data/public/punymce/plugins/safari2x.js +0 -1
- data/public/punymce/plugins/safari2x_src.js +0 -284
- data/public/punymce/plugins/tabfocus.js +0 -1
- data/public/punymce/plugins/tabfocus_src.js +0 -45
- data/public/punymce/plugins/textcolor/css/editor.css +0 -7
- data/public/punymce/plugins/textcolor/img/icons.gif +0 -0
- data/public/punymce/plugins/textcolor/textcolor.js +0 -1
- data/public/punymce/plugins/textcolor/textcolor_src.js +0 -73
- data/public/punymce/puny_mce.js +0 -1
- data/public/punymce/puny_mce_full.js +0 -1
- data/public/punymce/puny_mce_src.js +0 -1460
data/README.md
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
This is a tidy but comprehensive forum implementation that plugs into radiant and supports both discussion forums and page comments.
|
4
4
|
|
5
|
-
This new (as I write) version 2 is a complete rewrite with a lot of internal clarification in preparation for rails 3. It's
|
5
|
+
This new (as I write) version 2 is a complete rewrite with a lot of internal clarification in preparation for rails 3. It's only a release candidate at this stage: I'm working on bug fixes, documentation and packaging for public release. There is also a developing demo and documentation site that you can use as a starting point. Code is at [https://github.com/spanner/radiant-forum-demo](https://github.com/spanner/radiant-forum-demo) and the site will be public soon.
|
6
6
|
|
7
|
-
The forum is designed to be pick-and-mixed with other radiant extensions, so it's
|
7
|
+
The forum is designed to be pick-and-mixed with other radiant extensions, so it's focused on being a good forum and doesn't do anything else. I hope you will find it's good at what it does do:
|
8
8
|
|
9
9
|
* forums, topics, posts etc
|
10
10
|
* page comments
|
@@ -17,14 +17,20 @@ The forum is designed to be pick-and-mixed with other radiant extensions, so it'
|
|
17
17
|
|
18
18
|
I've tried to keep it simple and tidy both inside and out. This is helped by the fact that all the user-management is in the reader extension, so you should find this is easy to adapt and extend. The admin interface on the other hand is pretty basic: we expect most administration to happen through the public pages but there does need to be at least a dashboard to give a better overview. That will come soon.
|
19
19
|
|
20
|
-
As far as I know this is the
|
20
|
+
As far as I know this is the only decent forum software available for rails. If I can't find a better alternative, I will spin this off as a separate rails 3 engine that works alongside radiant but does not require it.
|
21
|
+
|
22
|
+
## Demo and documentation
|
23
|
+
|
24
|
+
You can find a standard radiant forum installation at [https://github.com/spanner/radiant-forum-demo](https://github.com/spanner/radiant-forum-demo). It serves many purposes: integration test target, reference platform, documentation and demo site and starting point for larger projects. There is some way to go on the documentation front but it should already serve as a useful starting point.
|
21
25
|
|
22
26
|
## Status
|
23
27
|
|
24
|
-
This code has been surviving in the world for
|
28
|
+
This code has been surviving in the world for five or six years (and more, since some it originally came from Beast), but this version is about 75% new and you know what that means: new bugs. Github issues are always welcome.
|
25
29
|
|
26
30
|
## Latest
|
27
31
|
|
32
|
+
* Tidied up and made compatible with radiant 1
|
33
|
+
* Group-visibility folded in
|
28
34
|
* Inline editing with editable-for-interval setting
|
29
35
|
* Punymce-based wysiwig editing.
|
30
36
|
* Page comments data structure simplified. Migration required.
|
@@ -34,7 +40,7 @@ This code has been surviving in the world for four or five years (and more, sinc
|
|
34
40
|
* Basic admin interface as well as readerland administration
|
35
41
|
* Editable interval for messages
|
36
42
|
|
37
|
-
This version is not
|
43
|
+
This version is not multi-site compatible. It relies heavily on configuration items that are not yet site-scoped. That's next on the list after radiant 1 comes out.
|
38
44
|
|
39
45
|
## Still to do
|
40
46
|
|
@@ -46,13 +52,9 @@ This version is not wholly multi-site compatible at the moment, since it relies
|
|
46
52
|
|
47
53
|
Radiant 0.9.2 (we're using the new configuration interface) with the [reader](http://github.com/spanner/radiant-reader-extension) extension. Reader has a few requirements of its own so it's best to install that one first, make sure it's testing clean and then install the forum.
|
48
54
|
|
49
|
-
We also require [will_paginate](http://github.com/mislav/will_paginate/) and [paperclip](http://github.com/thoughtbot/paperclip/) as gems but you will already have those.
|
50
|
-
|
51
55
|
sudo rake gems:install
|
52
56
|
|
53
57
|
should get everything you need.
|
54
|
-
|
55
|
-
The forum is compatible with multi_site but you should use [sites](https://github.com/spanner/radiant-sites-extension) instead if you want forums and readers site-scoped.
|
56
58
|
|
57
59
|
## Administration
|
58
60
|
|
@@ -62,6 +64,10 @@ The forum is easy to use and almost entirely separate from your page hierarchy.
|
|
62
64
|
|
63
65
|
There is now a configuration panel for the forum and you shouldn't have to do any console-tinkering.
|
64
66
|
|
67
|
+
## Changing forum text
|
68
|
+
|
69
|
+
Every string used in the public-facing forum (and reader) pages comes from the locale file. They are labelled functionally rather than literally, with keys like `forum_extension.no_search_results`. To change the wording, either edit or override the locale.
|
70
|
+
|
65
71
|
## Layouts
|
66
72
|
|
67
73
|
Forum pages have their own controllers but they are presented inside your normal radiant layouts. Use the configuration interface to choose the layout you want to use. Your layout can work in the usual way: all we do is define page parts for you to include with `<r:content part="something" />`. These are the parts available:
|
@@ -93,13 +99,11 @@ Have a look at the included sample layout for a starting point.
|
|
93
99
|
|
94
100
|
## Speed and caching
|
95
101
|
|
96
|
-
|
97
|
-
|
98
|
-
The intention is to make this behaviour configurable but at the moment I'm finding the forum pages too slow if uncached. Most of the wait comes from the shared_layouts/radius template machinery but there are some slow queries too. With optimisation a live forum should be viable.
|
102
|
+
Forum and reader views are not cached, by default, but commented pages are. It is possible to cache the forum if you omit any dynamic content (such as the reply form), but at some cost to ease of use.
|
99
103
|
|
100
104
|
## Private discussion
|
101
105
|
|
102
|
-
|
106
|
+
Group functionality has recently been folded into the reader and forum extensions, so you don't need to install a whole tree of tiny changes any more. The interface hasn't quite settled down, but the functionality is solid: associate a forum with a group, and all of its contents are visible only to members of that group.
|
103
107
|
|
104
108
|
## Searching the forum
|
105
109
|
|
@@ -128,15 +132,15 @@ The forum comes with some jquery-based scripting to handle inline administration
|
|
128
132
|
|
129
133
|
## Smilies
|
130
134
|
|
131
|
-
Included here is a redcloth extension to handle emoticons of the type inserted by the punymce toolbar we're using.
|
135
|
+
Included here is a redcloth extension to handle emoticons of the type inserted by the punymce toolbar we're using. I've customised the set to make accidental emoticons less likely. There will soon be an option to disable them completely.
|
132
136
|
|
133
137
|
## Bugs
|
134
138
|
|
135
|
-
In the short term,
|
139
|
+
In the short term, very likely. [Github issues](http://github.com/spanner/radiant-forum-extension/issues), please, or for little things an email or github message is fine.
|
136
140
|
|
137
141
|
## Author & Copyright
|
138
142
|
|
139
143
|
* William Ross, for spanner. will at spanner.org
|
140
|
-
* Originally based on dear old Beast
|
144
|
+
* Originally based on dear old Beast
|
141
145
|
* Copyright 2007-11 spanner ltd
|
142
146
|
* released under the same terms as Rails and/or Radiant
|
data/Rakefile
CHANGED
@@ -1,19 +1,3 @@
|
|
1
|
-
begin
|
2
|
-
require 'jeweler'
|
3
|
-
Jeweler::Tasks.new do |gem|
|
4
|
-
gem.name = "radiant-forum-extension"
|
5
|
-
gem.summary = %Q{Forum and Comment Extension for Radiant CMS}
|
6
|
-
gem.description = %Q{Nice clean forums and page comments for inclusion in your radiant site. Derived long ago from beast. Requires the reader extension and share_layouts.}
|
7
|
-
gem.email = "will@spanner.org"
|
8
|
-
gem.homepage = "http://github.com/spanner/radiant-forum-extension"
|
9
|
-
gem.authors = ["spanner"]
|
10
|
-
gem.add_dependency "radiant", ">= 0.9.0"
|
11
|
-
gem.add_dependency 'radiant-reader-extension', "~> 1.3.0"
|
12
|
-
end
|
13
|
-
rescue LoadError
|
14
|
-
puts "Jeweler (or a dependency) not available. This is only required if you plan to package forum as a gem."
|
15
|
-
end
|
16
|
-
|
17
1
|
# In rails 1.2, plugins aren't available in the path until they're loaded.
|
18
2
|
# Check to see if the rspec plugin is installed first and require
|
19
3
|
# it if it is. If not, use the gem version.
|
@@ -4,41 +4,64 @@ class ForumBaseController < ReaderActionController
|
|
4
4
|
radiant_layout { |c| Radiant::Config['forum.layout'] || Radiant::Config['reader.layout'] }
|
5
5
|
before_filter :require_login_unless_public
|
6
6
|
before_filter :establish_context
|
7
|
+
before_filter :require_visibility_to_reader
|
7
8
|
helper :forum, :reader
|
8
9
|
|
9
10
|
protected
|
10
11
|
|
12
|
+
def set_cache_header
|
13
|
+
if Radiant.config['forum.cached?']
|
14
|
+
expires_in (Radiant.config['forum.cache_duration'] || 60).to_i.minutes, :public => true
|
15
|
+
else
|
16
|
+
expires_now
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
11
20
|
def require_login_unless_public
|
12
21
|
return false unless Radiant::Config['forum.public?'] || require_reader && require_activated_reader
|
13
22
|
end
|
14
23
|
|
24
|
+
def require_visibility_to_reader
|
25
|
+
if @page && !@page.visible_to?(current_reader)
|
26
|
+
flash[:error] = t("page_not_public")
|
27
|
+
redirect_to reader_permission_denied_url
|
28
|
+
return false
|
29
|
+
end
|
30
|
+
|
31
|
+
if @forum && !@forum.visible_to?(current_reader)
|
32
|
+
flash[:error] = "forum_not_public"
|
33
|
+
redirect_to reader_permission_denied_url
|
34
|
+
return false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
15
38
|
def establish_context
|
16
39
|
@reader = Reader.find(params[:reader_id]) unless params[:reader_id].blank?
|
17
40
|
@topic = Topic.visible_to(current_reader).find(params[:topic_id]) unless params[:topic_id].blank?
|
18
41
|
@forum = Forum.visible_to(current_reader).find(params[:forum_id]) unless params[:forum_id].blank?
|
19
42
|
@page = Page.visible_to(current_reader).find(params[:page_id]) unless params[:page_id].blank?
|
20
43
|
end
|
21
|
-
|
44
|
+
|
22
45
|
def redirect_to_post
|
23
46
|
if (@post.page)
|
24
47
|
redirect_to "#{@post.page.url}?#{WillPaginate::ViewHelpers.pagination_options[:param_name]}=#{@post.page_when_paginated}##{@post.dom_id}"
|
25
48
|
elsif @post.first?
|
26
|
-
redirect_to
|
49
|
+
redirect_to topic_path(@post.topic)
|
27
50
|
else
|
28
51
|
post_location = {WillPaginate::ViewHelpers.pagination_options[:param_name] => @post.page_when_paginated, :anchor => @post.dom_id}
|
29
|
-
redirect_to
|
52
|
+
redirect_to topic_path(@post.topic, post_location)
|
30
53
|
end
|
31
54
|
end
|
32
55
|
|
33
56
|
def redirect_to_topic
|
34
|
-
redirect_to
|
57
|
+
redirect_to topic_path(@topic)
|
35
58
|
end
|
36
59
|
|
37
60
|
def redirect_to_page_or_topic
|
38
61
|
if @page
|
39
62
|
redirect_to @page.url
|
40
63
|
elsif @topic
|
41
|
-
redirect_to
|
64
|
+
redirect_to topic_path(@topic)
|
42
65
|
end
|
43
66
|
end
|
44
67
|
|
@@ -51,15 +74,14 @@ protected
|
|
51
74
|
def render_page_or_feed(template_name = action_name)
|
52
75
|
respond_to do |format|
|
53
76
|
format.html {
|
54
|
-
|
77
|
+
set_cache_header
|
55
78
|
render :action => template_name
|
56
79
|
}
|
57
80
|
format.rss {
|
58
|
-
|
59
|
-
render :action => template_name, :layout => 'feed'
|
81
|
+
render :action => template_name, :layout => 'feed'
|
60
82
|
}
|
61
83
|
format.js {
|
62
|
-
render :action => template_name, :layout => false
|
84
|
+
render :action => template_name, :layout => false
|
63
85
|
}
|
64
86
|
end
|
65
87
|
end
|
@@ -72,7 +94,7 @@ protected
|
|
72
94
|
respond_to do |format|
|
73
95
|
format.html {
|
74
96
|
expires_now
|
75
|
-
flash[:error] = t('topic_locked')
|
97
|
+
flash[:error] = t('forum_extension.topic_locked')
|
76
98
|
redirect_to_page_or_topic
|
77
99
|
}
|
78
100
|
format.js { render :partial => 'topics/locked' }
|
@@ -9,12 +9,16 @@ class PostsController < ForumBaseController
|
|
9
9
|
def index
|
10
10
|
@term = params[:q]
|
11
11
|
posts = Post.visible_to(current_reader)
|
12
|
-
posts = posts.
|
12
|
+
posts = posts.matching(@term) unless @term.blank?
|
13
13
|
posts = posts.from_reader(@reader) if @reader
|
14
14
|
posts = posts.in_forum(@forum) if @forum
|
15
15
|
posts = posts.in_topic(@topic) if @topic
|
16
16
|
@posts = posts.paginate(pagination_parameters)
|
17
|
-
|
17
|
+
respond_to do |format|
|
18
|
+
format.html
|
19
|
+
format.js { render :partial => 'search_results' }
|
20
|
+
format.rss { render :layout => 'feed' }
|
21
|
+
end
|
18
22
|
end
|
19
23
|
|
20
24
|
def show
|
@@ -26,15 +30,24 @@ class PostsController < ForumBaseController
|
|
26
30
|
|
27
31
|
def new
|
28
32
|
unless @post.topic || @post.page
|
29
|
-
@forum ||= Forum.find_by_name(Radiant::Config['forum.default_forum'])
|
30
|
-
|
33
|
+
if @forum ||= Forum.find_by_name(Radiant::Config['forum.default_forum'])
|
34
|
+
@post.topic = @forum.topics.new
|
35
|
+
else
|
36
|
+
@post.topic = Topic.new
|
37
|
+
end
|
31
38
|
end
|
32
39
|
respond_to do |format|
|
33
|
-
format.html {
|
40
|
+
format.html {
|
41
|
+
@inline = false
|
42
|
+
render
|
43
|
+
}
|
34
44
|
format.js {
|
45
|
+
@inline = true
|
35
46
|
if @post.page
|
47
|
+
# page comment form is usually brought in by xhr so that page itself can be cached
|
36
48
|
render :partial => 'pages/add_comment', :layout => false
|
37
49
|
else
|
50
|
+
# this is a much less common case, but you can cache topic pages if you really want to
|
38
51
|
render :partial => 'topics/reply', :layout => false
|
39
52
|
end
|
40
53
|
}
|
@@ -49,33 +62,43 @@ class PostsController < ForumBaseController
|
|
49
62
|
format.js { render :partial => 'post' }
|
50
63
|
end
|
51
64
|
rescue ActiveRecord::RecordInvalid
|
52
|
-
flash[:error] = t("validation_failure")
|
65
|
+
flash[:error] = t("forum_extension.validation_failure")
|
53
66
|
respond_to do |format|
|
54
67
|
format.html { render :action => 'new' }
|
55
|
-
format.js { render :
|
68
|
+
format.js { render :partial => 'form' }
|
56
69
|
end
|
57
70
|
end
|
58
71
|
|
59
72
|
def edit
|
60
73
|
respond_to do |format|
|
61
|
-
format.html {
|
62
|
-
|
74
|
+
format.html {
|
75
|
+
@inline = false
|
76
|
+
render
|
77
|
+
}
|
78
|
+
format.js {
|
79
|
+
@inline = true
|
80
|
+
if current_reader.is_moderator?(@post) || @post.editable_by?(current_reader)
|
81
|
+
render :partial => 'form'
|
82
|
+
else
|
83
|
+
render :partial => 'ineditable'
|
84
|
+
end
|
85
|
+
}
|
63
86
|
end
|
64
87
|
end
|
65
88
|
|
66
89
|
def update
|
67
90
|
@post.attributes = params[:post]
|
68
91
|
@post.save!
|
69
|
-
Radiant::Cache.clear if @post.page
|
92
|
+
Radiant::Cache.clear if @post.page || (@post.topic && Radiant.config['forum.cached?'])
|
70
93
|
respond_to do |format|
|
71
94
|
format.html { redirect_to_post }
|
72
95
|
format.js { render :partial => 'post' }
|
73
96
|
end
|
74
97
|
rescue ActiveRecord::RecordInvalid
|
75
|
-
flash[:error] = t("validation_failure")
|
98
|
+
flash[:error] = t("forum_extension.validation_failure")
|
76
99
|
respond_to do |format|
|
77
100
|
format.html { render :action => 'edit' }
|
78
|
-
format.js { render :
|
101
|
+
format.js { render :partial => 'form' }
|
79
102
|
end
|
80
103
|
end
|
81
104
|
|
@@ -89,13 +112,13 @@ class PostsController < ForumBaseController
|
|
89
112
|
def destroy
|
90
113
|
if @post.first?
|
91
114
|
@post.topic.destroy
|
92
|
-
flash[:notice] = t("topic_removed")
|
115
|
+
flash[:notice] = t("forum_extension.topic_removed")
|
93
116
|
redirect_to_forum
|
94
117
|
else
|
95
118
|
@post.destroy
|
96
119
|
respond_to do |format|
|
97
120
|
format.html {
|
98
|
-
flash[:notice] = t("post_removed")
|
121
|
+
flash[:notice] = t("forum_extension.post_removed")
|
99
122
|
redirect_to_page_or_topic
|
100
123
|
}
|
101
124
|
format.js { render :partial => 'post' }
|
data/app/helpers/forum_helper.rb
CHANGED
@@ -1,19 +1,15 @@
|
|
1
|
-
require 'sanitize'
|
2
|
-
require "sanitize/config/forum"
|
3
|
-
|
4
1
|
module ForumHelper
|
2
|
+
include ReaderHelper
|
3
|
+
mattr_accessor :forums_found
|
5
4
|
|
6
|
-
def
|
7
|
-
|
5
|
+
def using_forums?
|
6
|
+
@forums_found = Forum.count > 1 unless defined? @forums_found
|
7
|
+
@forums_found
|
8
8
|
end
|
9
|
-
|
10
|
-
def
|
11
|
-
if
|
12
|
-
""
|
13
|
-
else
|
14
|
-
textilized = RedCloth.new(text, [ :hard_breaks ])
|
15
|
-
textilized.hard_breaks = true if textilized.respond_to?("hard_breaks=")
|
16
|
-
Sanitize.clean(textilized.to_html(:textile, :smilies), Sanitize::Config::FORUM)
|
9
|
+
|
10
|
+
def feed_link(url)
|
11
|
+
if Radiant.config['forum.offer_rss?']
|
12
|
+
link_to image_tag('/images/furniture/feed_14.png', :alt => t('forum_extension.rss_feed')), url, :class => "rssfeed"
|
17
13
|
end
|
18
14
|
end
|
19
15
|
|
@@ -28,16 +24,27 @@ module ForumHelper
|
|
28
24
|
end
|
29
25
|
end
|
30
26
|
|
27
|
+
def link_to_forum(forum, options={})
|
28
|
+
title = options.delete(:title) || forum.title
|
29
|
+
link_to title, forum_url(forum), options
|
30
|
+
end
|
31
|
+
|
32
|
+
def link_to_topic(topic, options={})
|
33
|
+
title = options.delete(:title) || topic.title
|
34
|
+
link_to title, topic_url(topic), options
|
35
|
+
end
|
36
|
+
|
31
37
|
def link_to_post(post, options={})
|
32
|
-
|
38
|
+
title = options.delete(:title) || post.holder.title
|
39
|
+
link_to title, paginated_post_url(post), options
|
33
40
|
end
|
34
41
|
|
35
42
|
def edit_link(post)
|
36
|
-
link_to t('edit'), edit_topic_post_url(post.topic, post), :class => 'edit_post', :id => "edit_post_#{post.id}", :title => t("edit_post")
|
43
|
+
link_to t('forum_extension.edit'), edit_topic_post_url(post.topic, post), :class => 'edit_post', :id => "edit_post_#{post.id}", :title => t("forum_extension.edit_post")
|
37
44
|
end
|
38
45
|
|
39
46
|
def remove_link(post)
|
40
|
-
link_to t('delete'), topic_post_url(post.topic, post), :method => 'delete', :class => 'delete_post', :id => "delete_post_#{post.id}", :title => t("remove_post"), :confirm => t('really_remove_post')
|
47
|
+
link_to t('forum_extension.delete'), topic_post_url(post.topic, post), :method => 'delete', :class => 'delete_post', :id => "delete_post_#{post.id}", :title => t("remove_post"), :confirm => t('forum_extension.really_remove_post')
|
41
48
|
end
|
42
49
|
|
43
50
|
def friendly_date(datetime)
|
data/app/models/forum.rb
CHANGED
@@ -1,22 +1,26 @@
|
|
1
1
|
class Forum < ActiveRecord::Base
|
2
2
|
has_site if respond_to? :has_site
|
3
|
+
has_groups
|
4
|
+
|
3
5
|
has_many :topics, :dependent => :destroy
|
4
6
|
|
5
7
|
default_scope :order => 'name ASC'
|
6
8
|
named_scope :imported, :conditions => "old_id IS NOT NULL"
|
7
9
|
validates_presence_of :name
|
8
10
|
|
9
|
-
# other extensions can attach chains here to limit access
|
10
|
-
def self.visible_to(reader)
|
11
|
-
self.scoped
|
12
|
-
end
|
13
|
-
|
14
11
|
def dom_id
|
15
12
|
"forum_#{self.id}"
|
16
13
|
end
|
17
14
|
|
18
|
-
|
19
|
-
|
15
|
+
# chains the visible_to? method created during the has_groups call.
|
16
|
+
def visible_to_with_configuration?(reader=nil)
|
17
|
+
Rails.logger.warn "Forum#visible_to_with_configuration?"
|
18
|
+
return true if (reader || visible_by_default?) && visible_to_without_configuration?(reader)
|
19
|
+
end
|
20
|
+
alias_method_chain :visible_to?, :configuration
|
21
|
+
|
22
|
+
def visible_by_default?
|
23
|
+
!!Radiant.config['forum.public?']
|
20
24
|
end
|
21
25
|
|
22
26
|
end
|
data/app/models/post.rb
CHANGED
@@ -11,11 +11,11 @@ class Post < ActiveRecord::Base
|
|
11
11
|
accepts_nested_attributes_for :attachments, :allow_destroy => true
|
12
12
|
validates_presence_of :reader, :body
|
13
13
|
|
14
|
+
before_save :update_search_text
|
14
15
|
after_create :notify_holder_of_creation
|
15
16
|
after_destroy :notify_holder_of_destruction
|
16
|
-
|
17
|
+
|
17
18
|
default_scope :order => "posts.created_at DESC"
|
18
|
-
|
19
19
|
named_scope :comments, :conditions => "page_id IS NOT NULL"
|
20
20
|
named_scope :non_comments, :conditions => "page_id IS NULL"
|
21
21
|
named_scope :imported, :conditions => "old_id IS NOT NULL"
|
@@ -32,18 +32,26 @@ class Post < ActiveRecord::Base
|
|
32
32
|
self.length # replacing a SQL shortcut that omits the distinct clause
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
# adapted from the usual scope defined in has_groups, since here visibility is set at the forum level
|
36
|
+
named_scope :visible_to, lambda { |reader|
|
37
|
+
conditions = "topics.id IS NULL OR forums.id IS NULL OR pp.group_id IS NULL"
|
38
|
+
if reader && reader.group_ids.any?
|
39
|
+
ids = reader.group_ids
|
40
|
+
conditions = ["#{conditions} OR pp.group_id IN(#{ids.map{"?"}.join(',')})", *ids]
|
41
|
+
end
|
42
|
+
{
|
43
|
+
:joins => "INNER JOIN topics on posts.topic_id = topics.id LEFT OUTER JOIN forums on topics.forum_id = forums.id LEFT OUTER JOIN permissions as pp on pp.permitted_id = forums.id AND pp.permitted_type = 'Forum'",
|
44
|
+
:conditions => conditions,
|
45
|
+
:group => column_names.map { |n| self.table_name + '.' + n }.join(','),
|
46
|
+
:readonly => false
|
47
|
+
}
|
48
|
+
}
|
49
|
+
named_scope :matching, lambda { |term|
|
50
|
+
{
|
51
|
+
:conditions => ["posts.search_text LIKE ?", "%#{stopped(term)}%"]
|
39
52
|
}
|
40
53
|
}
|
41
54
|
|
42
|
-
# other extensions can attach chains here to limit access
|
43
|
-
def self.visible_to(reader)
|
44
|
-
self.scoped
|
45
|
-
end
|
46
|
-
|
47
55
|
def self.in_forum(forum)
|
48
56
|
in_topics(forum.topics)
|
49
57
|
end
|
@@ -51,11 +59,19 @@ class Post < ActiveRecord::Base
|
|
51
59
|
def holder
|
52
60
|
page || topic
|
53
61
|
end
|
62
|
+
|
63
|
+
def title
|
64
|
+
holder.title if holder
|
65
|
+
end
|
54
66
|
|
55
67
|
def comment?
|
56
68
|
!!page
|
57
69
|
end
|
58
70
|
|
71
|
+
def reply?
|
72
|
+
!comment? && !first?
|
73
|
+
end
|
74
|
+
|
59
75
|
def page_when_paginated
|
60
76
|
holder.page_for(self)
|
61
77
|
end
|
@@ -94,13 +110,21 @@ class Post < ActiveRecord::Base
|
|
94
110
|
|
95
111
|
def editable_by?(reader=nil)
|
96
112
|
return false unless reader
|
97
|
-
still_editable? && reader
|
113
|
+
still_editable? && reader.id == reader_id
|
98
114
|
end
|
99
115
|
|
100
116
|
def visible_to?(reader=nil)
|
101
|
-
|
117
|
+
if topic && !topic.visible_to?(reader)
|
118
|
+
false
|
119
|
+
elsif page && !page.visible_to?(reader)
|
120
|
+
false
|
121
|
+
elsif !reader && !Radiant::Config['forum.public?']
|
122
|
+
false
|
123
|
+
else
|
124
|
+
true
|
125
|
+
end
|
102
126
|
end
|
103
|
-
|
127
|
+
|
104
128
|
# so that page comments can be rendered from a radius tag
|
105
129
|
def body_html
|
106
130
|
if body
|
@@ -131,4 +155,19 @@ class Post < ActiveRecord::Base
|
|
131
155
|
"post_#{self.id}"
|
132
156
|
end
|
133
157
|
|
158
|
+
private
|
159
|
+
|
160
|
+
# this is rather crude, but it's database-agnostic, doesn't require
|
161
|
+
# any external indexing, and works well enough for most purposes.
|
162
|
+
# for a more satisfactory search, tell sphinx to index the search_text field.
|
163
|
+
|
164
|
+
def update_search_text
|
165
|
+
self.search_text = self.class.stopped("#{self.title} #{self.body}")
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.stopped(text="")
|
169
|
+
stops = I18n.t('forum_extension.stopwords').split.join('|')
|
170
|
+
text.downcase.gsub(/\b(#{stops})\b/, '').gsub(/(\W+)/, ' ')
|
171
|
+
end
|
172
|
+
|
134
173
|
end
|
@@ -40,7 +40,7 @@ class PostAttachment < ActiveRecord::Base
|
|
40
40
|
:path => ":rails_root/:class/:id/:basename:no_original_style.:extension" # attachments can only be accessed through the PostAttachments controller, in case file security is required
|
41
41
|
|
42
42
|
attr_protected :file_file_name, :file_content_type, :file_file_size
|
43
|
-
validates_attachment_presence :file, :message => t('error.no_file')
|
43
|
+
validates_attachment_presence :file, :message => t('forum_extension.error.no_file')
|
44
44
|
validates_attachment_content_type :file, :content_type => Radiant::Config["forum.attachment.content_types"].split(', ') if Radiant::Config.table_exists? && !Radiant::Config["forum.attachment.content_types"].blank?
|
45
45
|
validates_attachment_size :file, :less_than => Radiant::Config["forum.attachment.max_size"].to_i.megabytes if Radiant::Config.table_exists? && Radiant::Config["forum.attachment.max_size"]
|
46
46
|
|
data/app/models/topic.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
class Topic < ActiveRecord::Base
|
2
2
|
has_site if respond_to? :has_site
|
3
3
|
has_comments
|
4
|
-
|
5
4
|
belongs_to :forum
|
6
|
-
belongs_to :replied_by, :class_name => 'Reader'
|
7
5
|
|
8
6
|
validates_presence_of :name
|
9
7
|
validates_uniqueness_of :old_id, :allow_nil => true
|
@@ -14,18 +12,33 @@ class Topic < ActiveRecord::Base
|
|
14
12
|
named_scope :latest, lambda { |count|
|
15
13
|
{ :order => 'replied_at DESC', :limit => count }
|
16
14
|
}
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
# adapted from the usual scope defined in has_groups, since here visibility is set at the forum level
|
16
|
+
named_scope :visible_to, lambda { |reader|
|
17
|
+
conditions = "forums.id IS NULL OR pp.group_id IS NULL"
|
18
|
+
if reader && reader.group_ids.any?
|
19
|
+
ids = reader.group_ids
|
20
|
+
conditions = ["#{conditions} OR pp.group_id IN(#{ids.map{"?"}.join(',')})", *ids]
|
21
|
+
end
|
22
|
+
{
|
23
|
+
:joins => "LEFT OUTER JOIN forums on topics.forum_id = forums.id LEFT OUTER JOIN permissions as pp on pp.permitted_id = forums.id AND pp.permitted_type = 'Forum'",
|
24
|
+
:conditions => conditions,
|
25
|
+
:group => column_names.map { |n| self.table_name + '.' + n }.join(','),
|
26
|
+
:readonly => false
|
27
|
+
}
|
28
|
+
}
|
22
29
|
|
23
30
|
def dom_id
|
24
31
|
"topic_#{self.id}"
|
25
32
|
end
|
26
33
|
|
27
34
|
def visible_to?(reader=nil)
|
28
|
-
|
35
|
+
if forum && !forum.visible_to?(reader)
|
36
|
+
false
|
37
|
+
elsif !reader && !Radiant::Config['forum.public?']
|
38
|
+
false
|
39
|
+
else
|
40
|
+
true
|
41
|
+
end
|
29
42
|
end
|
30
43
|
|
31
44
|
def reader
|
@@ -0,0 +1,51 @@
|
|
1
|
+
- include_stylesheet 'admin/forum_dashboard'
|
2
|
+
|
3
|
+
#recent_comments.dashboard_module
|
4
|
+
.header
|
5
|
+
%h2
|
6
|
+
= t('forum_extension.pages_with_latest_comments')
|
7
|
+
.blockcontent
|
8
|
+
- latest = Page.last_commented(6)
|
9
|
+
- if latest.any?
|
10
|
+
- latest.each do |page|
|
11
|
+
.page
|
12
|
+
%h3
|
13
|
+
= link_to("#{icon} #{node_title}", edit_admin_page_url(page), :title => page.url, :class => 'page')
|
14
|
+
= link_to("→", page.path, :class => 'public')
|
15
|
+
%p.minor
|
16
|
+
=t('forum_extension.comment_count_from', :count => page.posts.count)
|
17
|
+
= link_to topic.replied_by.name, reader_url(topic.replied_by)
|
18
|
+
= friendly_date(topic.replied_at)
|
19
|
+
- else
|
20
|
+
%p.minor
|
21
|
+
=t('dashboard_extension.no_show')
|
22
|
+
|
23
|
+
#recent_topics.dashboard_module
|
24
|
+
.header
|
25
|
+
%h2
|
26
|
+
= t('forum_extension.latest_forum_activity')
|
27
|
+
.blockcontent
|
28
|
+
- latest = Topic.latest(4)
|
29
|
+
- if latest.any?
|
30
|
+
- latest.each do |topic|
|
31
|
+
- post = topic.posts.last
|
32
|
+
%h3
|
33
|
+
= link_to_post(post, :class => 'topic')
|
34
|
+
%span.context
|
35
|
+
- if topic.has_replies?
|
36
|
+
= t('forum_extension.new_reply_from')
|
37
|
+
= link_to topic.replied_by.name, reader_url(topic.replied_by)
|
38
|
+
= friendly_date(topic.replied_at)
|
39
|
+
- else
|
40
|
+
= t('forum_extension.started_by')
|
41
|
+
= link_to topic.reader.name, reader_url(topic.reader)
|
42
|
+
= friendly_date(topic.created_at)
|
43
|
+
%p.excerpt
|
44
|
+
= truncate_words(scrub_html(post.body), 16)
|
45
|
+
%p.minor
|
46
|
+
=t('forum_extension.administer_by_browsing')
|
47
|
+
- else
|
48
|
+
%p.minor
|
49
|
+
=t('dashboard_extension.no_show')
|
50
|
+
|
51
|
+
|