thredded 0.0.10 → 0.0.12

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.
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