thredded 0.0.10 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.mkdn +25 -0
  3. data/app/controllers/thredded/application_controller.rb +31 -13
  4. data/app/controllers/thredded/posts_controller.rb +9 -7
  5. data/app/controllers/thredded/topics_controller.rb +14 -33
  6. data/app/decorators/thredded/post_decorator.rb +10 -1
  7. data/app/decorators/thredded/topic_decorator.rb +2 -2
  8. data/app/decorators/thredded/user_topic_decorator.rb +2 -3
  9. data/app/helpers/thredded/application_helper.rb +0 -5
  10. data/app/models/thredded/ability.rb +10 -2
  11. data/app/models/thredded/attachment.rb +1 -1
  12. data/app/models/thredded/messageboard.rb +1 -0
  13. data/app/models/thredded/post.rb +63 -13
  14. data/app/models/thredded/topic.rb +10 -8
  15. data/app/uploaders/thredded/attachment_uploader.rb +1 -1
  16. data/app/uploaders/thredded/image_uploader.rb +1 -2
  17. data/app/views/thredded/messageboards/index.html.erb +3 -0
  18. data/app/views/thredded/post_mailer/at_notification.html.erb +1 -1
  19. data/app/views/thredded/posts/_post.html.erb +15 -15
  20. data/app/views/thredded/posts/edit.html.erb +3 -0
  21. data/app/views/thredded/posts/index.html.erb +3 -0
  22. data/app/views/thredded/preferences/edit.html.erb +3 -0
  23. data/app/views/thredded/private_topics/index.html.erb +3 -0
  24. data/app/views/thredded/private_topics/new.html.erb +3 -0
  25. data/app/views/thredded/setups/new.html.erb +2 -1
  26. data/app/views/thredded/topic_mailer/message_notification.html.erb +1 -1
  27. data/app/views/thredded/topics/_topic_form.html.erb +1 -1
  28. data/app/views/thredded/topics/by_category.html.erb +3 -0
  29. data/app/views/thredded/topics/edit.html.erb +3 -0
  30. data/app/views/thredded/topics/index.html.erb +3 -0
  31. data/app/views/thredded/topics/new.html.erb +3 -0
  32. data/app/views/thredded/topics/search.html.erb +3 -0
  33. data/lib/html/pipeline/at_mention_filter.rb +19 -0
  34. data/lib/{thredded/filter/attachment.rb → html/pipeline/attached_image_filter.rb} +18 -10
  35. data/lib/html/pipeline/bbcode_filter.rb +19 -0
  36. data/lib/thredded.rb +15 -7
  37. data/lib/thredded/errors.rb +22 -0
  38. data/lib/thredded/topic_user_permissions.rb +6 -2
  39. data/lib/thredded/version.rb +1 -1
  40. metadata +54 -17
  41. data/lib/thredded/filter.rb +0 -4
  42. data/lib/thredded/filter/at_notification.rb +0 -11
  43. data/lib/thredded/filter/base.rb +0 -13
  44. data/lib/thredded/filter/bbcode.rb +0 -75
  45. data/lib/thredded/filter/emoji.rb +0 -11
  46. data/lib/thredded/filter/markdown.rb +0 -25
  47. data/lib/thredded/filter/syntax.rb +0 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 63f6eebe937c5b969d191a5650bb160b07b5976a
4
- data.tar.gz: 73b1e243259935e0f8e80a653ffe4c922e581e28
3
+ metadata.gz: df7af89356e2a063cd53eb323694e5e5ddce74a4
4
+ data.tar.gz: fffc4fd4e91f2828b3d45dd7761bf01861dc8802
5
5
  SHA512:
6
- metadata.gz: f38401e4c39f48e55dd2def77978ab913d662a13012de3e013fd0f67d4fd62bf7df03bc259cb5e933442ca6234aed36537e2a45ddfa04e3a03b97dc4d2793825
7
- data.tar.gz: 718c48c5501ecb3712ae25c7113bdcf457de3eb6cc1a72fce282a825c9dd5644a548ecd5d1da3667cec8b41c5cb1219a2b1aa791cf83566c960a758620517198
6
+ metadata.gz: 77112aabf3ce777664be0d5c19cad1449d7d6cc67f67c04ac82b23b3c2a134b176a30c5a0a59f6eade60ab860004f4a9f17c183810f3a615247b33f9d716e32f
7
+ data.tar.gz: 49465daf00d25b2bd94dfe37d0b322049f4d8b32864f3674dfb92b9207a6b24d28cbe1ae2e2e650e7f59b83e13f2226e85d30f2bf3410da8285f2c098914694e
@@ -16,6 +16,10 @@ Thredded.email_incoming_host = 'incoming.example.com'
16
16
  Thredded.email_from = 'no-reply@example.com'
17
17
  Thredded.email_outgoing_prefix = '[Thredded] '
18
18
  Thredded.user_path = ->(user){ "/path/to/where/you/show/#{user}" }
19
+ Thredded.file_storage = :file # or :fog
20
+ Thredded.asset_root = 'http://assets.website.com/assets' # where important things, like emojis, might live
21
+ Thredded.layout = 'thredded' # looks for `app/views/layouts/thredded.html.erb`
22
+ Thredded.avatar_default = 'mm' # or other gravatar defaults or URL to an image
19
23
  ```
20
24
 
21
25
  Copy the migrations over to your parent application and migrate:
@@ -44,4 +48,25 @@ class User < ActiveRecord::Base
44
48
  end
45
49
  ```
46
50
 
51
+ 2. Ensure you have a view layout that thredded will wrap around its views.
52
+
53
+ A couple of notes with regards to your layout.
54
+
55
+ * When using route helpers -- eg: `new_session_path`, et al -- make sure to prepend main_app to the helper: `main_app.new_session_path` as rails engines like thredded will not know about those routes' existence unless explicitly told so.
56
+ * As noted above, by default thredded will look for a layout file in your application called `thredded.html.erb`. If you would like to use something else, like your main application layout, you may change it to that in your initializer.
57
+ * The chosen layout has two content_tags available to yield - `:thredded_page_title` and `:thredded_page_id`. The views within thredded pass those up through to your layout if you would like to use them. Example layout:
58
+
59
+ ```html
60
+ <html>
61
+ <head>
62
+ <title>My Application | <%= yield :thredded_page_title %></title>
63
+ </head>
64
+ <body id="<%= yield :thredded_page_id %>">
65
+ <%= yield %>
66
+ </body>
67
+ </html>
68
+ ```
69
+
70
+ * * *
71
+
47
72
  For more information see [the full-fledged rails app](https://github.com/jayroh/thredded_app)
@@ -1,24 +1,48 @@
1
1
  module Thredded
2
2
  class ApplicationController < ::ApplicationController
3
3
  helper Thredded::Engine.helpers
4
- helper_method :messageboard, :topic, :preferences
4
+ helper_method :messageboard, :preferences
5
+ layout Thredded.layout
6
+
7
+ rescue_from CanCan::AccessDenied,
8
+ Thredded::Errors::MessageboardNotFound,
9
+ Thredded::Errors::MessageboardReadDenied,
10
+ Thredded::Errors::TopicCreateDenied do |exception|
5
11
 
6
- rescue_from CanCan::AccessDenied do |exception|
7
12
  redirect_to thredded.root_path, alert: exception.message
8
13
  end
9
14
 
10
- rescue_from Thredded::Errors::MessageboardNotFound do |exception|
11
- redirect_to thredded.root_path, alert: exception.message
15
+ rescue_from Thredded::Errors::EmptySearchResults,
16
+ Thredded::Errors::TopicNotFound do |exception|
17
+
18
+ redirect_to messageboard_topics_path(messageboard),
19
+ alert: exception.message
12
20
  end
13
21
 
14
22
  private
15
23
 
16
- def update_user_activity
17
- if messageboard && current_user
18
- messageboard.update_activity_for!(current_user)
24
+ def authorize_reading(obj)
25
+ if cannot? :read, obj
26
+ class_name = obj.class.to_s
27
+ error = class_name
28
+ .gsub(/Thredded::/, 'Thredded::Errors::') + 'ReadDenied'
29
+ raise error.constantize
30
+ end
31
+ end
32
+
33
+ def authorize_creating(obj)
34
+ if cannot? :create, obj
35
+ class_name = obj.class.to_s
36
+ error = class_name
37
+ .gsub(/Thredded::/, 'Thredded::Errors::') + 'CreateDenied'
38
+ raise error.constantize
19
39
  end
20
40
  end
21
41
 
42
+ def update_user_activity
43
+ messageboard.update_activity_for!(current_user)
44
+ end
45
+
22
46
  def current_ability
23
47
  @current_ability ||= Ability.new(current_user)
24
48
  end
@@ -32,11 +56,5 @@ module Thredded
32
56
  @preferences ||= UserPreference.where(user_id: current_user.id).first
33
57
  end
34
58
  end
35
-
36
- def topic
37
- if messageboard
38
- @topic ||= messageboard.topics.find(params[:topic_id])
39
- end
40
- end
41
59
  end
42
60
  end
@@ -4,14 +4,15 @@ module Thredded
4
4
  helper_method :messageboard, :topic, :user_topic
5
5
  before_filter :update_user_activity
6
6
 
7
- rescue_from Thredded::Errors::TopicNotFound do |exception|
8
- redirect_to messageboard_topics_path(messageboard), alert: exception.message
9
- end
10
-
11
7
  def index
12
8
  authorize! :read, topic
13
9
 
14
- @posts = topic.posts.page(current_page)
10
+ @posts = Post
11
+ .where(topic_id: topic.id)
12
+ .includes(:user, :messageboard, :topic, :attachments)
13
+ .order('id ASC')
14
+ .page(current_page)
15
+
15
16
  @post = messageboard.posts.build(topic: topic)
16
17
 
17
18
  update_read_status!
@@ -23,11 +24,12 @@ module Thredded
23
24
  end
24
25
 
25
26
  def edit
26
- authorize! :manage, post
27
+ authorize! :edit, post
27
28
  end
28
29
 
29
30
  def update
30
- post.update_attributes(post_params)
31
+ post.update_attributes(post_params.except(:user, :ip))
32
+
31
33
  redirect_to messageboard_topic_posts_url(messageboard, topic)
32
34
  end
33
35
 
@@ -1,36 +1,23 @@
1
1
  module Thredded
2
2
  class TopicsController < Thredded::ApplicationController
3
- helper_method :current_page
3
+ helper_method :current_page, :topic
4
4
  before_filter :update_user_activity
5
5
 
6
6
  def index
7
- if cannot? :read, messageboard
8
- error = 'You are not authorized access to this messageboard.'
9
- redirect_to default_home, flash: { error: error }
10
- end
7
+ authorize_reading messageboard
11
8
 
12
9
  @topics = topics
13
10
  end
14
11
 
15
12
  def search
16
- @topics = search_results
17
-
18
- if @topics.empty?
19
- error = 'No topics found for this search.'
20
- redirect_to messageboard_topics_path(messageboard),
21
- flash: { error: error }
22
- end
13
+ @topics = Topic.search(params[:q], messageboard)
23
14
  end
24
15
 
25
16
  def new
26
17
  @topic = messageboard.topics.build
27
18
  @topic.posts.build
28
19
 
29
- unless can? :create, @topic
30
- error = 'Sorry, you are not authorized to post on this messageboard.'
31
- redirect_to messageboard_topics_url(messageboard),
32
- flash: { error: error }
33
- end
20
+ authorize_creating @topic
34
21
  end
35
22
 
36
23
  def by_category
@@ -55,9 +42,16 @@ module Thredded
55
42
  private
56
43
 
57
44
  def topic
58
- if messageboard
59
- @topic ||= messageboard.topics.friendly.find(params[:id])
60
- end
45
+ @topic ||= messageboard.topics.find_by_slug(params[:id])
46
+ end
47
+
48
+ def topics
49
+ Topic
50
+ .public
51
+ .for_messageboard(messageboard)
52
+ .includes(:user_topic_reads, :categories, :messageboard, :last_user, :user)
53
+ .order_by_stuck_and_updated_time
54
+ .on_page(current_page)
61
55
  end
62
56
 
63
57
  def topic_params
@@ -88,10 +82,6 @@ module Thredded
88
82
  })
89
83
  end
90
84
 
91
- def search_results
92
- Topic.full_text_search(params[:q], messageboard)
93
- end
94
-
95
85
  def topics_by_category(category_id)
96
86
  topics = Category.find(category_id)
97
87
  .topics
@@ -102,15 +92,6 @@ module Thredded
102
92
  .on_page(current_page)
103
93
  end
104
94
 
105
- def topics
106
- Topic
107
- .public
108
- .for_messageboard(messageboard)
109
- .includes(:user_topic_reads)
110
- .order_by_stuck_and_updated_time
111
- .on_page(current_page)
112
- end
113
-
114
95
  def current_page
115
96
  params[:page] || 1
116
97
  end
@@ -15,6 +15,15 @@ module Thredded
15
15
  end
16
16
  end
17
17
 
18
+ def user_link
19
+ if post.user
20
+ user_path = Thredded.user_path(post.user)
21
+ "<a href='#{user_path}'>#{post.user}</a>".html_safe
22
+ else
23
+ '<a href="#">?</a>'.html_safe
24
+ end
25
+ end
26
+
18
27
  def original
19
28
  post
20
29
  end
@@ -36,7 +45,7 @@ module Thredded
36
45
  end
37
46
 
38
47
  def gravatar_url
39
- super.gsub /http:/, ''
48
+ super.gsub(/http:/, '')
40
49
  end
41
50
 
42
51
  private
@@ -24,12 +24,12 @@ module Thredded
24
24
  end
25
25
 
26
26
  def last_user_link
27
- if last_user && last_user.valid?
27
+ if last_user && last_user.to_s != 'Anonymous User'
28
28
  last_user_path = Thredded.user_path(last_user)
29
29
 
30
30
  "<a href='#{last_user_path}'>#{last_user}</a>".html_safe
31
31
  else
32
- 'Anonymous'
32
+ last_user.to_s
33
33
  end
34
34
  end
35
35
 
@@ -55,7 +55,7 @@ module Thredded
55
55
  end
56
56
 
57
57
  def user_link
58
- if topic.user && topic.user.valid?
58
+ if topic.user && topic.user.to_s != 'Anonymous User'
59
59
  user_path = Thredded.user_path(topic.user)
60
60
  "<a href='#{user_path}'>#{topic.user}</a>".html_safe
61
61
  else
@@ -63,7 +63,6 @@ module Thredded
63
63
  end
64
64
  end
65
65
 
66
-
67
66
  def decorated_topic
68
67
  @decorated_topic ||= TopicDecorator.new(topic)
69
68
  end
@@ -73,7 +72,7 @@ module Thredded
73
72
  attr_reader :topic, :user
74
73
 
75
74
  def read_status
76
- if user.valid?
75
+ if user.id > 0
77
76
  @read_status ||= topic.user_topic_reads.select do |reads|
78
77
  reads.user_id == user.id
79
78
  end
@@ -1,9 +1,4 @@
1
1
  module Thredded
2
2
  module ApplicationHelper
3
- def method_missing(method, *args, &block)
4
- main_app.send(method, *args, &block)
5
- rescue NoMethodError
6
- super
7
- end
8
3
  end
9
4
  end
@@ -12,8 +12,16 @@ module Thredded
12
12
  Thredded::MessageboardUserPermissions.new(messageboard, user).readable?
13
13
  end
14
14
 
15
- can :manage, Thredded::Topic do |topic|
16
- Thredded::TopicUserPermissions.new(topic, user, user_details).manageable?
15
+ can :admin, Thredded::Topic do |topic|
16
+ Thredded::TopicUserPermissions.new(topic, user, user_details).adminable?
17
+ end
18
+
19
+ can :edit, Thredded::Topic do |topic|
20
+ Thredded::TopicUserPermissions.new(topic, user, user_details).editable?
21
+ end
22
+
23
+ can :update, Thredded::Topic do |topic|
24
+ Thredded::TopicUserPermissions.new(topic, user, user_details).editable?
17
25
  end
18
26
 
19
27
  can :read, Thredded::Topic do |topic|
@@ -1,6 +1,6 @@
1
1
  module Thredded
2
2
  class Attachment < ActiveRecord::Base
3
- belongs_to :post
3
+ belongs_to :post, touch: true
4
4
  validates_presence_of :attachment
5
5
  mount_uploader :attachment, Thredded::AttachmentUploader
6
6
  before_save :update_attachment_attributes
@@ -53,6 +53,7 @@ module Thredded
53
53
  def active_users
54
54
  Role
55
55
  .joins(:user)
56
+ .includes(:user)
56
57
  .where(messageboard_id: self.id)
57
58
  .where('last_seen > ?', 5.minutes.ago)
58
59
  .order(:last_seen)
@@ -4,14 +4,8 @@ require 'gravtastic'
4
4
  module Thredded
5
5
  class Post < ActiveRecord::Base
6
6
  include Gravtastic
7
- include Thredded::Filter::Base
8
- include Thredded::Filter::Bbcode
9
- include Thredded::Filter::Markdown
10
- include Thredded::Filter::Attachment
11
- include Thredded::Filter::Emoji
12
- include Thredded::Filter::AtNotification
13
-
14
- gravtastic :user_email
7
+
8
+ gravtastic :user_email, default: Thredded.avatar_default
15
9
  paginates_per 50
16
10
 
17
11
  belongs_to :messageboard, counter_cache: true
@@ -28,10 +22,6 @@ module Thredded
28
22
  after_save :notify_at_users
29
23
  after_create :modify_parent_posts_counts
30
24
 
31
- def self.default_scope
32
- order('id ASC')
33
- end
34
-
35
25
  def created_date
36
26
  created_at.strftime("%b %d, %Y %I:%M:%S %Z") if created_at
37
27
  end
@@ -41,15 +31,75 @@ module Thredded
41
31
  end
42
32
 
43
33
  def gravatar_url
44
- super.gsub /http:/, ''
34
+ super.gsub(/http:/, '')
45
35
  end
46
36
 
47
37
  def self.filters
48
38
  ['bbcode', 'markdown']
49
39
  end
50
40
 
41
+ def filtered_content
42
+ pipeline = HTML::Pipeline.new [
43
+ HTML::Pipeline::AttachedImageFilter,
44
+ html_filter_for_pipeline,
45
+ HTML::Pipeline::SanitizationFilter,
46
+ HTML::Pipeline::AtMentionFilter,
47
+ HTML::Pipeline::EmojiFilter,
48
+ HTML::Pipeline::AutolinkFilter,
49
+ ], context_options
50
+
51
+ result = pipeline.call(content)
52
+ result[:output].to_s
53
+ end
54
+
51
55
  private
52
56
 
57
+ def context_options
58
+ {
59
+ asset_root: Thredded.asset_root,
60
+ post: self,
61
+ whitelist: sanitize_whitelist
62
+ }
63
+ end
64
+
65
+ def sanitize_whitelist
66
+ HTML::Pipeline::SanitizationFilter::WHITELIST.deep_merge({
67
+ attributes: {
68
+ 'code' => ['class'],
69
+ 'img' => ['src', 'class', 'width', 'height'],
70
+ 'blockquote' => ['class'],
71
+ },
72
+ transformers: [
73
+ lambda do |env|
74
+ node = env[:node]
75
+ node_name = env[:node_name]
76
+
77
+ return if env[:is_whitelisted] || !node.element?
78
+ return if node_name != 'iframe'
79
+ return if (node['src'] =~ /\A(https?:)?\/\/(?:www\.)?youtube(?:-nocookie)?\.com\//).nil?
80
+
81
+ Sanitize.clean_node!(node, {
82
+ elements: %w[iframe],
83
+
84
+ attributes: {
85
+ 'iframe' => %w[allowfullscreen frameborder height src width]
86
+ }
87
+ })
88
+
89
+ { node_whitelist: [node]}
90
+ end
91
+ ]
92
+ })
93
+ end
94
+
95
+ def html_filter_for_pipeline
96
+ if filter == 'bbcode'
97
+ HTML::Pipeline::BbcodeFilter
98
+ else
99
+ HTML::Pipeline::MarkdownFilter
100
+ end
101
+ end
102
+
53
103
  def modify_parent_posts_counts
54
104
  Thredded::UserDetail.increment_counter(:posts_count, user_id)
55
105
  topic.last_user = user
@@ -62,15 +62,17 @@ module Thredded
62
62
  order('sticky DESC, updated_at DESC')
63
63
  end
64
64
 
65
- def self.full_text_search(query, messageboard)
66
- if query.empty?
67
- []
68
- else
69
- sql_builder = Thredded::SearchSqlBuilder.new(query, messageboard)
70
- sql = sql_builder.build
71
- sql_params = [sql].concat(sql_builder.binds)
72
- find_by_sql sql_params
65
+ def self.search(query, messageboard)
66
+ sql_builder = Thredded::SearchSqlBuilder.new(query, messageboard)
67
+ sql = sql_builder.build
68
+ sql_params = [sql].concat(sql_builder.binds)
69
+ results = find_by_sql(sql_params)
70
+
71
+ if results.empty?
72
+ raise Thredded::Errors::EmptySearchResults, query
73
73
  end
74
+
75
+ results
74
76
  end
75
77
 
76
78
  def self.decorate
@@ -3,7 +3,7 @@ require 'carrierwave/processing/mini_magick'
3
3
  module Thredded
4
4
  class AttachmentUploader < CarrierWave::Uploader::Base
5
5
  include CarrierWave::MiniMagick
6
- storage :file
6
+ storage Thredded.file_storage
7
7
 
8
8
  def store_dir
9
9
  "uploads/#{mounted_as}/#{model.id}"
@@ -3,8 +3,7 @@ require 'carrierwave/processing/mini_magick'
3
3
  module Thredded
4
4
  class ImageUploader < CarrierWave::Uploader::Base
5
5
  include CarrierWave::MiniMagick
6
-
7
- storage :file
6
+ storage Thredded.file_storage
8
7
 
9
8
  def store_dir
10
9
  "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
@@ -1,3 +1,6 @@
1
+ <% content_for :thredded_page_title, 'Messageboards' %>
2
+ <% content_for :thredded_page_id, 'thredded_messageboards_index' %>
3
+
1
4
  <header>
2
5
  <nav>
3
6
  <ul class="breadcrumbs">
@@ -1,6 +1,6 @@
1
1
  <p><span style="font-size:11px; color: gray;">- write above this line to post a reply -</span></p>
2
2
 
3
- <%= @post.filtered_content %>
3
+ <%== @post.filtered_content %>
4
4
 
5
5
  <hr />
6
6
 
@@ -1,7 +1,7 @@
1
- <% post = Thredded::PostDecorator.new(post) %>
1
+ <% cache [current_user, 'post', post] do %>
2
+ <% post = Thredded::PostDecorator.new(post) %>
2
3
 
3
- <%= content_tag_for(:article, post) do %>
4
- <% cache post do %>
4
+ <%= content_tag_for(:article, post) do %>
5
5
  <header>
6
6
  <%= image_tag post.gravatar_url, class: 'avatar' %>
7
7
  <cite>
@@ -11,19 +11,19 @@
11
11
  </header>
12
12
 
13
13
  <div class="content">
14
- <p><%= post.filtered_content %></p>
14
+ <%== post.filtered_content %>
15
15
  <ul class="attachments"><%= render post.attachments %></ul>
16
16
  </div>
17
- <% end %>
18
17
 
19
- <footer>
20
- <% if can? :edit, post.original %>
21
- <%= link_to 'edit post', edit_messageboard_topic_post_path(
22
- messageboard,
23
- topic,
24
- post
25
- ),
26
- class: 'edit' %>
27
- <% end %>
28
- </footer>
18
+ <footer>
19
+ <% if can? :edit, post.original %>
20
+ <%= link_to 'edit post', edit_messageboard_topic_post_path(
21
+ messageboard,
22
+ topic,
23
+ post
24
+ ),
25
+ class: 'edit' %>
26
+ <% end %>
27
+ </footer>
28
+ <% end %>
29
29
  <% end %>
@@ -1,3 +1,6 @@
1
+ <% content_for :thredded_page_title, 'Edit Post' %>
2
+ <% content_for :thredded_page_id, 'thredded_edit_post' %>
3
+
1
4
  <header>
2
5
  <nav>
3
6
  <ul class="breadcrumbs">
@@ -1,3 +1,6 @@
1
+ <% content_for :thredded_page_title, topic.title %>
2
+ <% content_for :thredded_page_id, 'thredded_posts' %>
3
+
1
4
  <% content_for :breadcrumbs do %>
2
5
  <ul class="breadcrumbs">
3
6
  <li><%= link_to 'Forums', thredded.root_path %></li>
@@ -1,3 +1,6 @@
1
+ <% content_for :thredded_page_title, 'Messageboard Preferences' %>
2
+ <% content_for :thredded_page_id, 'thredded_preferences' %>
3
+
1
4
  <fieldset>
2
5
  <legend>Update Preferences For <%= messageboard.name %></legend>
3
6
 
@@ -1,3 +1,6 @@
1
+ <% content_for :thredded_page_title, 'Private Topics' %>
2
+ <% content_for :thredded_page_id, 'thredded_private_topics_index' %>
3
+
1
4
  <% content_for :breadcrumbs do %>
2
5
  <ul class="breadcrumbs">
3
6
  <li><%= link_to 'Forums', thredded.root_path %></li>
@@ -1,3 +1,6 @@
1
+ <% content_for :thredded_page_title, 'Create a New Private Topic' %>
2
+ <% content_for :thredded_page_id, 'thredded_new_private_topic' %>
3
+
1
4
  <header>
2
5
  <nav>
3
6
  <ul class="breadcrumbs">
@@ -1,4 +1,5 @@
1
- <% content_for :page_title do %>Thredded Setup<% end %>
1
+ <% content_for :thredded_page_title, 'Set Up Thredded' %>
2
+ <% content_for :thredded_page_id, 'thredded_new_setup' %>
2
3
 
3
4
  <h1>Setup</h1>
4
5
 
@@ -1,6 +1,6 @@
1
1
  <p><span style="font-size:11px; color: gray;">- write above this line to post a reply -</span></p>
2
2
 
3
- <%= @topic.posts.first.filtered_content %>
3
+ <%== @topic.posts.first.filtered_content %>
4
4
 
5
5
  <hr />
6
6
 
@@ -6,7 +6,7 @@
6
6
  </li>
7
7
  <% end %>
8
8
 
9
- <% if can? :manage, form.object %>
9
+ <% if can? :admin, form.object %>
10
10
  <li class="locked">
11
11
  <%= form.label :locked do %>
12
12
  Locked <%= form.check_box :locked %>
@@ -1,3 +1,6 @@
1
+ <% content_for :thredded_page_title, 'Topic Categories' %>
2
+ <% content_for :thredded_page_id, 'thredded_topic_categories' %>
3
+
1
4
  <% content_for :breadcrumbs do %>
2
5
  <ul class="breadcrumbs">
3
6
  <li><%= link_to 'Forums', thredded.root_path %></li>
@@ -1,3 +1,6 @@
1
+ <% content_for :thredded_page_title, "Edit \"#{topic.title}\"" %>
2
+ <% content_for :thredded_page_id, 'thredded_edit_topic' %>
3
+
1
4
  <header>
2
5
  <nav>
3
6
  <ul class="breadcrumbs">
@@ -1,3 +1,6 @@
1
+ <% content_for :thredded_page_title, 'Topics' %>
2
+ <% content_for :thredded_page_id, 'thredded_topics_index' %>
3
+
1
4
  <% content_for :breadcrumbs do %>
2
5
  <ul class="breadcrumbs">
3
6
  <li><%= link_to 'Forums', thredded.root_path %></li>
@@ -1,3 +1,6 @@
1
+ <% content_for :thredded_page_title, 'Create a New Topic' %>
2
+ <% content_for :thredded_page_id, 'thredded_new_topic' %>
3
+
1
4
  <header>
2
5
  <nav>
3
6
  <ul class="breadcrumbs">
@@ -1,3 +1,6 @@
1
+ <% content_for :thredded_page_title, 'Search Results' %>
2
+ <% content_for :thredded_page_id, 'thredded_topic_search_results' %>
3
+
1
4
  <% content_for :breadcrumbs do %>
2
5
  <ul class="breadcrumbs">
3
6
  <li><%= link_to 'Forums', thredded.root_path %></li>
@@ -0,0 +1,19 @@
1
+ require 'thredded/at_users'
2
+
3
+ module HTML
4
+ class Pipeline
5
+ class AtMentionFilter < Filter
6
+ def initialize(text, context = nil, result = nil)
7
+ super text, context, result
8
+ @text = text.to_s.gsub "\r", ''
9
+ @post = context[:post]
10
+ end
11
+
12
+ def call
13
+ html = Thredded::AtUsers.render(@text, @post.messageboard)
14
+ html.rstrip!
15
+ html
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,9 +1,16 @@
1
- module Thredded
2
- module Filter
3
- module Attachment
4
- def filtered_content
5
- content = super
6
- matches = content.scan(/(?<full>\[t:(?<tag>\w+)=?(?<img_nmb>\d+)? ?(?<attribs>[^\]]+)?\])/)
1
+
2
+ module HTML
3
+ class Pipeline
4
+ class AttachedImageFilter < Filter
5
+ def initialize(text, context = nil, result = nil)
6
+ super text, context, result
7
+ @text = text.gsub "\r", ''
8
+ @post = context[:post]
9
+ end
10
+
11
+ def call
12
+ html = @text
13
+ matches = @text.scan(/(?<full>\[t:(?<tag>\w+)=?(?<img_nmb>\d+)? ?(?<attribs>[^\]]+)?\])/)
7
14
 
8
15
  matches.each do |match|
9
16
  str_buff = ''
@@ -12,7 +19,7 @@ module Thredded
12
19
  img_number = match[2] ? match[2].to_i - 1 : 0 # default to first attachment
13
20
  attribs = match[3]
14
21
 
15
- if(tag != 'img' || !self.attachments[img_number])
22
+ if(tag != 'img' || !@post.attachments[img_number])
16
23
  next
17
24
  end
18
25
 
@@ -20,7 +27,7 @@ module Thredded
20
27
  str_buff += '<img '
21
28
 
22
29
  # get attachment object at spot img_number - 1
23
- attachment = self.attachments[img_number]
30
+ attachment = @post.attachments[img_number]
24
31
  str_buff += 'src="' + attachment.attachment.to_s + '" '
25
32
 
26
33
  # do attribute stuff, left right first
@@ -41,11 +48,12 @@ module Thredded
41
48
  str_buff += '/>'
42
49
 
43
50
  # replace in post content
44
- content = content.sub(full, str_buff)
51
+ html = html.sub(full, str_buff)
45
52
  end
46
53
 
47
- content.html_safe
54
+ html
48
55
  end
49
56
  end
50
57
  end
51
58
  end
59
+
@@ -0,0 +1,19 @@
1
+ require 'bbcoder'
2
+
3
+ module HTML
4
+ class Pipeline
5
+ class BbcodeFilter < TextFilter
6
+ def initialize(text, context = {}, result = nil)
7
+ super text, context, result
8
+ @context = context
9
+ @text = @text.gsub "\r", ''
10
+ end
11
+
12
+ def call
13
+ html = BBCoder.new(@text).to_html.gsub(/\n|\r\n/, '<br />')
14
+ html.rstrip!
15
+ "<p>#{html}</p>"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -7,24 +7,32 @@ require 'friendly_id'
7
7
  require 'nested_form'
8
8
  require 'thredded/email_processor'
9
9
  require 'thredded/errors'
10
- require 'thredded/filter/base'
11
10
  require 'thredded/at_notifier'
12
- require 'thredded/filter/at_notification'
13
- require 'thredded/filter/attachment'
14
- require 'thredded/filter/bbcode'
15
- require 'thredded/filter/emoji'
16
- require 'thredded/filter/markdown'
11
+ require 'html/pipeline'
12
+ require 'html/pipeline/bbcode_filter'
13
+ require 'html/pipeline/attached_image_filter'
14
+ require 'html/pipeline/at_mention_filter'
17
15
  require 'thredded/messageboard_user_permissions'
18
16
  require 'thredded/post_user_permissions'
19
17
  require 'thredded/private_topic_user_permissions'
20
18
  require 'thredded/topic_user_permissions'
19
+ require 'thredded/search_sql_builder'
21
20
 
22
21
  module Thredded
23
22
  mattr_accessor :user_class,
24
23
  :email_incoming_host,
25
24
  :email_from,
26
25
  :email_outgoing_prefix,
27
- :user_path
26
+ :user_path,
27
+ :file_storage,
28
+ :asset_root,
29
+ :layout,
30
+ :avatar_default
31
+
32
+ self.file_storage = :file # or :fog
33
+ self.asset_root = '' # or fully qualified URI to assets
34
+ self.layout = 'thredded'
35
+ self.avatar_default = 'mm'
28
36
 
29
37
  def self.user_class
30
38
  if @@user_class.is_a?(Class)
@@ -14,5 +14,27 @@ module Thredded
14
14
  'This messageboard does not exist.'
15
15
  end
16
16
  end
17
+
18
+ class MessageboardReadDenied < Thredded::Error
19
+ def message
20
+ 'You are not authorized access to this messageboard.'
21
+ end
22
+ end
23
+
24
+ class TopicCreateDenied < Thredded::Error
25
+ def message
26
+ 'You are not authorized to post in this messageboard.'
27
+ end
28
+ end
29
+
30
+ class EmptySearchResults < Thredded::Error
31
+ def initialize(query)
32
+ @query = query
33
+ end
34
+
35
+ def message
36
+ "There are no results for your search - '#{@query}'"
37
+ end
38
+ end
17
39
  end
18
40
  end
@@ -13,8 +13,12 @@ module Thredded
13
13
  member? || messageboard_restrictions_allow?
14
14
  end
15
15
 
16
- def manageable?
17
- superadmin? || started_by_user? || administrates_messageboard?
16
+ def adminable?
17
+ superadmin? || administrates_messageboard?
18
+ end
19
+
20
+ def editable?
21
+ superadmin? || administrates_messageboard? || started_by_user?
18
22
  end
19
23
 
20
24
  def readable?
@@ -1,3 +1,3 @@
1
1
  module Thredded
2
- VERSION = '0.0.10'
2
+ VERSION = '0.0.12'
3
3
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thredded
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Oliveira
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-09 00:00:00.000000000 Z
11
+ date: 2014-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bb-ruby
14
+ name: bbcoder
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - '>='
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: unf
70
+ name: fog
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - '>='
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: fog
84
+ name: friendly_id
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - '>='
@@ -95,7 +95,21 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: friendly_id
98
+ name: gemoji
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: github-markdown
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
115
  - - '>='
@@ -136,6 +150,20 @@ dependencies:
136
150
  - - '>='
137
151
  - !ruby/object:Gem::Version
138
152
  version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: html-pipeline
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
139
167
  - !ruby/object:Gem::Dependency
140
168
  name: htmlentities
141
169
  requirement: !ruby/object:Gem::Requirement
@@ -235,7 +263,21 @@ dependencies:
235
263
  - !ruby/object:Gem::Version
236
264
  version: 4.0.0
237
265
  - !ruby/object:Gem::Dependency
238
- name: rails_emoji
266
+ name: rinku
267
+ requirement: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - '>='
270
+ - !ruby/object:Gem::Version
271
+ version: '0'
272
+ type: :runtime
273
+ prerelease: false
274
+ version_requirements: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - '>='
277
+ - !ruby/object:Gem::Version
278
+ version: '0'
279
+ - !ruby/object:Gem::Dependency
280
+ name: sanitize
239
281
  requirement: !ruby/object:Gem::Requirement
240
282
  requirements:
241
283
  - - '>='
@@ -249,7 +291,7 @@ dependencies:
249
291
  - !ruby/object:Gem::Version
250
292
  version: '0'
251
293
  - !ruby/object:Gem::Dependency
252
- name: redcarpet
294
+ name: unf
253
295
  requirement: !ruby/object:Gem::Requirement
254
296
  requirements:
255
297
  - - '>='
@@ -374,7 +416,7 @@ dependencies:
374
416
  - - '>='
375
417
  - !ruby/object:Gem::Version
376
418
  version: '0'
377
- description: Extracted from the full rails app at thredded.com
419
+ description: A messageboard and/or forum engine for Rails 4.0 apps
378
420
  email:
379
421
  - joel@thredded.com
380
422
  executables: []
@@ -465,6 +507,9 @@ files:
465
507
  - db/migrate/20131019014258_index_necessary_columns.rb
466
508
  - db/migrate/20131026202621_move_filter_to_messageboards.rb
467
509
  - db/migrate/20131029034507_convert_textile_to_markdown.rb
510
+ - lib/html/pipeline/at_mention_filter.rb
511
+ - lib/html/pipeline/attached_image_filter.rb
512
+ - lib/html/pipeline/bbcode_filter.rb
468
513
  - lib/tasks/thredded_tasks.rake
469
514
  - lib/thredded/at_notification_extractor.rb
470
515
  - lib/thredded/at_notifier.rb
@@ -472,14 +517,6 @@ files:
472
517
  - lib/thredded/email_processor.rb
473
518
  - lib/thredded/engine.rb
474
519
  - lib/thredded/errors.rb
475
- - lib/thredded/filter/at_notification.rb
476
- - lib/thredded/filter/attachment.rb
477
- - lib/thredded/filter/base.rb
478
- - lib/thredded/filter/bbcode.rb
479
- - lib/thredded/filter/emoji.rb
480
- - lib/thredded/filter/markdown.rb
481
- - lib/thredded/filter/syntax.rb
482
- - lib/thredded/filter.rb
483
520
  - lib/thredded/messageboard_user_permissions.rb
484
521
  - lib/thredded/post_sql_builder.rb
485
522
  - lib/thredded/post_user_permissions.rb
@@ -1,4 +0,0 @@
1
- module Thredded
2
- module Filter
3
- end
4
- end
@@ -1,11 +0,0 @@
1
- require 'thredded/at_users'
2
-
3
- module Thredded
4
- module Filter
5
- module AtNotification
6
- def filtered_content
7
- @filtered_content = Thredded::AtUsers.render(super, messageboard).html_safe
8
- end
9
- end
10
- end
11
- end
@@ -1,13 +0,0 @@
1
- module Thredded
2
- module Filter
3
- module Base
4
- Filters = []
5
-
6
- def filters; Filters; end
7
-
8
- def filtered_content
9
- self.content
10
- end
11
- end
12
- end
13
- end
@@ -1,75 +0,0 @@
1
- module Thredded
2
- module Filter
3
- module Bbcode
4
- require 'bb-ruby'
5
-
6
- BB = {
7
- 'Spoilers' => [
8
- /\[spoiler\](.*?)\[\/spoiler\1?\]/mi,
9
- '<blockquote class="spoiler">\1</blockquote>',
10
- 'Spoiler Text',
11
- '[spoiler]Dumbledore dies[/spoiler]',
12
- :spoiler],
13
- 'YouTube' => [
14
- /\[youtube\]https?\:\/\/(www\.)?youtube.com\/((watch)?\?vi?=|embed\/)(.*?)\[\/youtube\1?\]/i,
15
- '<iframe class="youtube" width="560" height="315" src="//www.youtube.com/embed/\4?&rel=0&theme=light&showinfo=0&hd=1&autohide=1&color=white" frameborder="0" allowfullscreen="allowfullscreen"></iframe>',
16
- 'Youtube Video',
17
- :video],
18
- 'Link (Legacy)' => [
19
- /\[link=(?:&quot;)?(.*?)(?:&quot;)?\](.*?)\[\/link\]/mi,
20
- '<a href="\1">\2</a>',
21
- 'Hyperlink to somewhere else',
22
- 'Maybe try looking on [link=http://google.com]Google[/link]?',
23
- :link],
24
- 'Link (Legacy Implied)' => [
25
- /\[link\](.*?)\[\/link\]/mi,
26
- '<a href="\1">\1</a>',
27
- 'Hyperlink (legacy implied)',
28
- "Maybe try looking on [link]http://google.com[/link]",
29
- :link],
30
- }
31
-
32
- def self.included(base)
33
- base.class_eval do
34
- Thredded::Post::Filters << :bbcode
35
- end
36
- end
37
-
38
- def filtered_content
39
- if filter.to_sym == :bbcode
40
- content = super
41
- content = replace_code_tags(content)
42
- content = replace_quote_tags(content)
43
- content = content.bbcode_to_html(BB)
44
- content = remove_empty_p_tags(content)
45
- content = CGI.unescapeHTML(content)
46
-
47
- content.html_safe
48
- else
49
- super
50
- end
51
- end
52
-
53
- def replace_code_tags(content)
54
- content.gsub!(/\[code\]/, '<pre><code>')
55
- content.gsub!(/\[code:(\D+?)\]/, '<pre><code class="language-\1" lang="\1">')
56
- content.gsub!(/\[\/code\]/, '</code></pre>')
57
- content.html_safe
58
- end
59
-
60
- def replace_quote_tags(content)
61
- content.gsub!(/\[quote(:.*)?=(?:&quot;)?(.*?)(?:&quot;)?\]/,
62
- '</p><fieldset><legend>\2</legend><blockquote><p>')
63
- content.gsub!(/\[quote(:.*?)?\]/,
64
- '</p><fieldset><blockquote><p>')
65
- content.gsub!(/\[\/quote\]/,
66
- '</p></blockquote></fieldset><p>')
67
- content.html_safe
68
- end
69
-
70
- def remove_empty_p_tags(content)
71
- content.gsub(/&lt;p&gt;\s*?&lt;\/p&gt;/, '')
72
- end
73
- end
74
- end
75
- end
@@ -1,11 +0,0 @@
1
- require 'rails_emoji'
2
-
3
- module Thredded
4
- module Filter
5
- module Emoji
6
- def filtered_content
7
- @filtered_content = RailsEmoji.render(super, size: 26).html_safe
8
- end
9
- end
10
- end
11
- end
@@ -1,25 +0,0 @@
1
- require 'redcarpet'
2
-
3
- module Thredded
4
- module Filter
5
- module Markdown
6
- def self.included(base)
7
- base.class_eval do
8
- Thredded::Post::Filters << :markdown
9
- end
10
- end
11
-
12
- def filtered_content
13
- if filter.to_sym == :markdown
14
- renderer = Redcarpet::Render::HTML.new(hard_wrap: true, filter_html: true)
15
- markdown = Redcarpet::Markdown.new(renderer, autolink: true,
16
- space_after_headers: true, no_intraemphasis: true,
17
- fenced_code: true, gh_blockcode: true)
18
- @filtered_content = markdown.render(super).html_safe
19
- else
20
- super
21
- end
22
- end
23
- end
24
- end
25
- end
@@ -1,28 +0,0 @@
1
- require 'coderay'
2
- require 'htmlentities'
3
-
4
- module Thredded
5
- module Filter
6
- module Syntax
7
- def filtered_content
8
- content = String.new(super)
9
- content = HTMLEntities.new.decode(content)
10
-
11
- content = content.to_s
12
- .gsub(/\<pre\>\<code( lang="(.+?)")?\>(.+?)\<\/code\>\<\/pre\>/m) do
13
- filter = $2.nil? ? :ruby : $2.to_sym
14
- temp_code = $3.gsub(/&quot;/, '"').
15
- gsub(/&#39;/,"'").
16
- gsub(/&amp;/, "&").
17
- gsub(/&gt;/, ">").
18
- gsub(/&lt;/, "<").
19
- gsub(/\<br \/\>/, "")
20
-
21
- ::CodeRay.scan(temp_code, filter).div(css: :class)
22
- end
23
-
24
- content.html_safe
25
- end
26
- end
27
- end
28
- end