thredded 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.mkdn +46 -0
  4. data/Rakefile +31 -0
  5. data/app/assets/javascripts/thredded/application.js +15 -0
  6. data/app/assets/stylesheets/thredded/application.css +13 -0
  7. data/app/controllers/thredded/application_controller.rb +50 -0
  8. data/app/controllers/thredded/messageboards_controller.rb +9 -0
  9. data/app/controllers/thredded/posts_controller.rb +86 -0
  10. data/app/controllers/thredded/preferences_controller.rb +20 -0
  11. data/app/controllers/thredded/private_topics_controller.rb +25 -0
  12. data/app/controllers/thredded/setups_controller.rb +39 -0
  13. data/app/controllers/thredded/topics_controller.rb +121 -0
  14. data/app/decorators/thredded/post_decorator.rb +52 -0
  15. data/app/decorators/thredded/topic_decorator.rb +96 -0
  16. data/app/helpers/thredded/application_helper.rb +9 -0
  17. data/app/helpers/thredded/messageboard_helper.rb +52 -0
  18. data/app/helpers/thredded/posts_helper.rb +7 -0
  19. data/app/helpers/thredded/topics_helper.rb +21 -0
  20. data/app/mailers/thredded/post_mailer.rb +28 -0
  21. data/app/mailers/thredded/topic_mailer.rb +29 -0
  22. data/app/models/thredded/ability.rb +50 -0
  23. data/app/models/thredded/attachment.rb +24 -0
  24. data/app/models/thredded/category.rb +10 -0
  25. data/app/models/thredded/image.rb +27 -0
  26. data/app/models/thredded/messageboard.rb +92 -0
  27. data/app/models/thredded/messageboard_decorator.rb +18 -0
  28. data/app/models/thredded/messageboard_preference.rb +15 -0
  29. data/app/models/thredded/null_preference.rb +9 -0
  30. data/app/models/thredded/null_topic_read.rb +13 -0
  31. data/app/models/thredded/null_user.rb +27 -0
  32. data/app/models/thredded/post.rb +75 -0
  33. data/app/models/thredded/post_notification.rb +6 -0
  34. data/app/models/thredded/private_topic.rb +33 -0
  35. data/app/models/thredded/private_user.rb +7 -0
  36. data/app/models/thredded/role.rb +18 -0
  37. data/app/models/thredded/topic.rb +145 -0
  38. data/app/models/thredded/topic_category.rb +7 -0
  39. data/app/models/thredded/user_detail.rb +6 -0
  40. data/app/models/thredded/user_extender.rb +27 -0
  41. data/app/models/thredded/user_preference.rb +6 -0
  42. data/app/models/thredded/user_topic_read.rb +67 -0
  43. data/app/uploaders/thredded/attachment_uploader.rb +30 -0
  44. data/app/uploaders/thredded/image_uploader.rb +17 -0
  45. data/app/views/thredded/messageboards/_messageboard.html.erb +17 -0
  46. data/app/views/thredded/messageboards/index.html.erb +15 -0
  47. data/app/views/thredded/post_mailer/at_notification.html.erb +17 -0
  48. data/app/views/thredded/post_mailer/at_notification.text.erb +13 -0
  49. data/app/views/thredded/posts/_form.html.erb +25 -0
  50. data/app/views/thredded/posts/_null_user.html.erb +0 -0
  51. data/app/views/thredded/posts/_post.html.erb +25 -0
  52. data/app/views/thredded/posts/_user.html.erb +7 -0
  53. data/app/views/thredded/posts/edit.html.erb +28 -0
  54. data/app/views/thredded/posts/index.html.erb +74 -0
  55. data/app/views/thredded/preferences/edit.html.erb +23 -0
  56. data/app/views/thredded/search/_form.html.erb +9 -0
  57. data/app/views/thredded/setups/_form.html.erb +35 -0
  58. data/app/views/thredded/setups/new.html.erb +5 -0
  59. data/app/views/thredded/shared/_currently_online.html.erb +10 -0
  60. data/app/views/thredded/shared/_error_msgs.html.erb +7 -0
  61. data/app/views/thredded/shared/_google_analytics.html.erb +10 -0
  62. data/app/views/thredded/shared/_topic_nav.html.erb +18 -0
  63. data/app/views/thredded/topic_mailer/message_notification.html.erb +17 -0
  64. data/app/views/thredded/topic_mailer/message_notification.text.erb +13 -0
  65. data/app/views/thredded/topics/_form.html.erb +6 -0
  66. data/app/views/thredded/topics/_topic_condensed.html.erb +20 -0
  67. data/app/views/thredded/topics/_topic_form.html.erb +27 -0
  68. data/app/views/thredded/topics/by_category.html.erb +51 -0
  69. data/app/views/thredded/topics/edit.html.erb +25 -0
  70. data/app/views/thredded/topics/index.html.erb +52 -0
  71. data/app/views/thredded/topics/menu/_new_topic.html.erb +3 -0
  72. data/app/views/thredded/topics/new.html.erb +18 -0
  73. data/app/views/thredded/topics/search.html.erb +45 -0
  74. data/config/routes.rb +26 -0
  75. data/db/migrate/20130425230852_create_thredded_tables.rb +143 -0
  76. data/lib/tasks/thredded_tasks.rake +4 -0
  77. data/lib/thredded.rb +38 -0
  78. data/lib/thredded/at_notification_extractor.rb +15 -0
  79. data/lib/thredded/at_notifier.rb +65 -0
  80. data/lib/thredded/at_users.rb +17 -0
  81. data/lib/thredded/email_processor.rb +74 -0
  82. data/lib/thredded/engine.rb +17 -0
  83. data/lib/thredded/filter.rb +4 -0
  84. data/lib/thredded/filter/at_notification.rb +11 -0
  85. data/lib/thredded/filter/attachment.rb +51 -0
  86. data/lib/thredded/filter/base.rb +13 -0
  87. data/lib/thredded/filter/bbcode.rb +75 -0
  88. data/lib/thredded/filter/emoji.rb +11 -0
  89. data/lib/thredded/filter/markdown.rb +25 -0
  90. data/lib/thredded/filter/syntax.rb +28 -0
  91. data/lib/thredded/filter/textile.rb +21 -0
  92. data/lib/thredded/messageboard_user_permissions.rb +27 -0
  93. data/lib/thredded/post_sql_builder.rb +34 -0
  94. data/lib/thredded/post_user_permissions.rb +37 -0
  95. data/lib/thredded/private_topic_notifier.rb +56 -0
  96. data/lib/thredded/private_topic_user_permissions.rb +32 -0
  97. data/lib/thredded/search_parser.rb +45 -0
  98. data/lib/thredded/search_sql_builder.rb +25 -0
  99. data/lib/thredded/setup_thredded.rb +7 -0
  100. data/lib/thredded/table_sql_builder.rb +105 -0
  101. data/lib/thredded/topic_sql_builder.rb +32 -0
  102. data/lib/thredded/topic_user_permissions.rb +51 -0
  103. data/lib/thredded/version.rb +3 -0
  104. metadata +537 -0
@@ -0,0 +1,6 @@
1
+ <li class="title">
2
+ <%= form.label :title %>
3
+ <%= form.text_field :title, { placeholder: 'Title', autofocus: 'autofocus', } %>
4
+ </li>
5
+
6
+ <%= render 'topic_form', form: form, messageboard: messageboard %>
@@ -0,0 +1,20 @@
1
+ <% if can? :read, topic.original %>
2
+ <%= content_tag_for :article, topic, class: topic.css_class do %>
3
+ <div class="post_count"><%= topic.posts_count %></div>
4
+
5
+ <h1>
6
+ <%= link_to topic.title, [messageboard, topic],
7
+ class: already_read(topic, @tracked_user_reads) %>
8
+ </h1>
9
+
10
+ <cite class="updated_by">
11
+ <%= topic.updated_at_timeago %>
12
+ <%= topic.last_user_link %>
13
+ </cite>
14
+
15
+ <cite class="started_by">
16
+ <%= topic.created_at_timeago %>
17
+ <%= topic.user_link %>
18
+ </cite>
19
+ <% end %>
20
+ <% end %>
@@ -0,0 +1,27 @@
1
+ <% if messageboard.categories.any? %>
2
+ <li class="category">
3
+ <%= form.select :category_ids,
4
+ messageboard.category_options,
5
+ {}, { multiple: true, 'data-placeholder' => 'Categories' } %>
6
+ </li>
7
+ <% end %>
8
+
9
+ <% if can? :manage, form.object %>
10
+ <li class="locked">
11
+ <%= form.label :locked do %>
12
+ Locked <%= form.check_box :locked %>
13
+ <% end %>
14
+ </li>
15
+
16
+ <li class="sticky">
17
+ <%= form.label :sticky do %>
18
+ Sticky <%= form.check_box :sticky %>
19
+ <% end %>
20
+ </li>
21
+ <% end %>
22
+
23
+ <% if action_name != 'edit' %>
24
+ <%= form.fields_for :posts do |post_form| %>
25
+ <%= render 'thredded/posts/form', f: post_form %>
26
+ <% end %>
27
+ <% end %>
@@ -0,0 +1,51 @@
1
+ <% content_for :breadcrumbs do %>
2
+ <ul class="breadcrumbs">
3
+ <li><%= link_to 'Forums', thredded.root_path %></li>
4
+ <li><%= link_to messageboard.title, messageboard_topics_path(messageboard) %></li>
5
+ <li><span>Category</span></li>
6
+ </ul>
7
+ <% end %>
8
+
9
+ <% content_for :actions do %>
10
+ <ul class="actions">
11
+ <%= render 'thredded/search/form' %>
12
+
13
+ <% if can? :create, Thredded::Topic %>
14
+ <li class='new_topic'>
15
+ <%= link_to 'new topic', new_messageboard_topic_path(messageboard) %>
16
+ </li>
17
+ <li class='new_private_topic'>
18
+ <%= link_to 'private topic', new_messageboard_private_topic_path(messageboard) %>
19
+ </li>
20
+ <% end %>
21
+ </ul>
22
+ <% end %>
23
+
24
+ <header>
25
+ <nav>
26
+ <%= yield :breadcrumbs %>
27
+ <%= yield :actions %>
28
+ </nav>
29
+
30
+ <%= render 'thredded/shared/currently_online' %>
31
+ </header>
32
+
33
+ <section class="topics">
34
+ <% if @sticky.any? %>
35
+ <div class="stuck">
36
+ <%= render partial: 'thredded/topics/topic_condensed', collection: @sticky, as: :t %>
37
+ </div>
38
+ <% end %>
39
+
40
+ <div class="currently">
41
+ <%= render partial: 'thredded/topics/topic_condensed', collection: @topics, as: :t %>
42
+ </div>
43
+ </section>
44
+
45
+ <footer>
46
+ <%= paginate @topics %>
47
+ <nav>
48
+ <%= yield :actions %>
49
+ <%= yield :breadcrumbs %>
50
+ </nav>
51
+ </footer>
@@ -0,0 +1,25 @@
1
+ <header>
2
+ <nav>
3
+ <ul class="breadcrumbs">
4
+ <li><%= link_to 'Forums', thredded.root_path %></li>
5
+ <li><%= link_to messageboard.name, messageboard_topics_path(messageboard, topic) %></li>
6
+ <li>
7
+ <span>
8
+ Editing Topic <em><%= link_to topic.title, [messageboard, topic] %></em>
9
+ </span>
10
+ </li>
11
+ </ul>
12
+ </nav>
13
+ </header>
14
+
15
+ <div class="forms">
16
+ <ul>
17
+ <%= nested_form_for [@messageboard, @topic], html: { class: :topic_form, multipart: true } do |form| %>
18
+ <%= render 'form', form: form, messageboard: messageboard.decorate %>
19
+
20
+ <li class="submit">
21
+ <%= form.submit 'Update Topic' %>
22
+ </li>
23
+ <% end %>
24
+ </ul>
25
+ </div>
@@ -0,0 +1,52 @@
1
+ <% content_for :breadcrumbs do %>
2
+ <ul class="breadcrumbs">
3
+ <li><%= link_to 'Forums', thredded.root_path %></li>
4
+ <li><span><%= messageboard.name %></span></li>
5
+ </ul>
6
+ <% end %>
7
+
8
+ <% content_for :actions do %>
9
+ <ul class="actions">
10
+ <%= render 'thredded/search/form' %>
11
+
12
+ <% if can? :create, Thredded::Topic %>
13
+ <li class='new_topic'>
14
+ <%= link_to 'new topic', new_messageboard_topic_path(messageboard) %>
15
+ </li>
16
+ <li class='new_private_topic'>
17
+ <%= link_to 'private topic', new_messageboard_private_topic_path(messageboard) %>
18
+ </li>
19
+ <% end %>
20
+ </ul>
21
+ <% end %>
22
+
23
+ <header>
24
+ <nav>
25
+ <%= yield :breadcrumbs %>
26
+ <%= yield :actions %>
27
+ </nav>
28
+
29
+ <%= render 'thredded/shared/currently_online' %>
30
+ </header>
31
+
32
+ <section class="topics">
33
+ <% if @sticky.any? %>
34
+ <div class="stuck">
35
+ <%= render partial: 'thredded/topics/topic_condensed',
36
+ collection: @sticky.decorate, as: :topic %>
37
+ </div>
38
+ <% end %>
39
+
40
+ <div class="currently">
41
+ <%= render partial: 'thredded/topics/topic_condensed',
42
+ collection: @topics.decorate, as: :topic %>
43
+ </div>
44
+ </section>
45
+
46
+ <footer>
47
+ <%= paginate @topics %>
48
+ <nav>
49
+ <%= yield :actions %>
50
+ <%= yield :breadcrumbs %>
51
+ </nav>
52
+ </footer>
@@ -0,0 +1,3 @@
1
+ <li>
2
+ <%= link_to 'New Topic', new_messageboard_topic_path %>
3
+ </li>
@@ -0,0 +1,18 @@
1
+ <header>
2
+ <nav>
3
+ <ul class="breadcrumbs">
4
+ <li><%= link_to 'Forums', thredded.root_path %></li>
5
+ <li><%= link_to messageboard.name, [messageboard, @topic] %></li>
6
+ <li><span>Create New Topic</span></li>
7
+ </ul>
8
+ </nav>
9
+ </header>
10
+
11
+ <div class="topic form">
12
+ <%= nested_form_for [messageboard, @topic], html: { multipart: true } do |form| %>
13
+ <ul>
14
+ <%= render 'form', form: form, messageboard: messageboard.decorate %>
15
+ <li class="submit"><%= form.submit 'Create New Topic' %></li>
16
+ </ul>
17
+ <% end %>
18
+ </div>
@@ -0,0 +1,45 @@
1
+ <% content_for :breadcrumbs do %>
2
+ <ul class="breadcrumbs">
3
+ <li><%= link_to 'Forums', thredded.root_path %></li>
4
+ <li><%= link_to messageboard.title,
5
+ messageboard_topics_path(messageboard) %></li>
6
+ <li><span>Results for "<%= params[:q]%>"</span></li>
7
+ </ul>
8
+ <% end %>
9
+
10
+ <% content_for :actions do %>
11
+ <ul class="actions">
12
+ <%= render 'thredded/search/form' %>
13
+
14
+ <% if can? :create, Thredded::Topic %>
15
+ <li class='new_topic'>
16
+ <%= link_to 'new topic', new_messageboard_topic_path(messageboard) %>
17
+ </li>
18
+ <li class='new_private_topic'>
19
+ <%= link_to 'private topic', new_messageboard_private_topic_path(messageboard) %>
20
+ </li>
21
+ <% end %>
22
+ </ul>
23
+ <% end %>
24
+
25
+ <header>
26
+ <nav>
27
+ <%= yield :breadcrumbs %>
28
+ <%= yield :actions %>
29
+ </nav>
30
+
31
+ <%= render partial: 'shared/currently_online' %>
32
+ </header>
33
+
34
+ <section class="topics">
35
+ <div class="currently">
36
+ <%= render partial: 'topics/topic_condensed', collection: @topics, as: :t %>
37
+ </div>
38
+ </section>
39
+
40
+ <footer>
41
+ <nav>
42
+ <%= yield :actions %>
43
+ <%= yield :breadcrumbs %>
44
+ </nav>
45
+ </footer>
data/config/routes.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'thredded/setup_thredded'
2
+
3
+ Thredded::Engine.routes.draw do
4
+ constraints(Thredded::SetupThredded.new) do
5
+ resources :setups, path: '', only: [:new, :create]
6
+ root to: 'setups#new'
7
+ end
8
+
9
+ constraints(lambda{|req| req.env['QUERY_STRING'].include? 'q=' }) do
10
+ get '/:messageboard_id(.:format)' => 'topics#search', as: :messageboard_search
11
+ end
12
+
13
+ get '/:messageboard_id/new(.:format)' => 'topics#new', as: :new_messageboard_topic
14
+ get '/:messageboard_id/:id/edit.(:format)' => 'topics#edit', as: :edit_messageboard_topic
15
+
16
+ resources :messageboards, only: [:index], path: '' do
17
+ resource :preferences
18
+ resources :private_topics, only: [:new, :create]
19
+
20
+ resources :topics, except: [:show], path: '' do
21
+ resources :posts, path: ''
22
+ end
23
+ end
24
+
25
+ root to: 'messageboards#index'
26
+ end
@@ -0,0 +1,143 @@
1
+ class CreateThreddedTables < ActiveRecord::Migration
2
+ def change
3
+ create_table :thredded_attachments do |t|
4
+ t.string :attachment
5
+ t.string :content_type
6
+ t.integer :file_size
7
+ t.integer :post_id
8
+ t.timestamps
9
+ end
10
+
11
+ create_table :thredded_categories do |t|
12
+ t.integer :messageboard_id, null: false
13
+ t.string :name, null: false
14
+ t.string :description
15
+ t.timestamps
16
+ end
17
+
18
+ create_table :thredded_images do |t|
19
+ t.integer :post_id
20
+ t.integer :width
21
+ t.integer :height
22
+ t.string :orientation
23
+ t.timestamps
24
+ end
25
+
26
+ create_table :thredded_messageboards do |t|
27
+ t.string :name, null: false
28
+ t.string :slug
29
+ t.text :description
30
+ t.string :security, default: 'public'
31
+ t.string :posting_permission, default: 'anonymous'
32
+ t.integer :topics_count, default: 0
33
+ t.integer :posts_count, default: 0
34
+ t.boolean :closed, default: false, null: false
35
+ t.timestamps
36
+ end
37
+
38
+ add_index :thredded_messageboards, :closed
39
+
40
+ create_table :thredded_post_notifications do |t|
41
+ t.string :email, null: false
42
+ t.integer :post_id, null: false
43
+ t.timestamps
44
+ end
45
+
46
+ create_table :thredded_posts do |t|
47
+ t.integer :user_id
48
+ t.string :user_email
49
+ t.text :content
50
+ t.string :ip
51
+ t.string :filter, default: 'markdown'
52
+ t.string :source, default: 'web'
53
+ t.integer :topic_id, null: false
54
+ t.integer :messageboard_id, null: false
55
+ t.timestamps
56
+ end
57
+
58
+ create_table :thredded_private_users do |t|
59
+ t.integer :private_topic_id
60
+ t.integer :user_id
61
+ t.timestamps
62
+ end
63
+
64
+ create_table :thredded_messageboard_preferences do |t|
65
+ t.boolean :notify_on_mention, default: true
66
+ t.boolean :notify_on_message, default: true
67
+ t.string :filter, default: 'markdown', null: false
68
+ t.integer :user_id, null: false
69
+ t.integer :messageboard_id, null: false
70
+ t.timestamps
71
+ end
72
+
73
+ add_index :thredded_messageboard_preferences, :user_id
74
+ add_index :thredded_messageboard_preferences, :messageboard_id
75
+
76
+ create_table :thredded_roles do |t|
77
+ t.string :level
78
+ t.integer :user_id
79
+ t.integer :messageboard_id
80
+ t.datetime :last_seen
81
+ t.timestamps
82
+ end
83
+
84
+ add_index :thredded_roles, :user_id
85
+ add_index :thredded_roles, :messageboard_id
86
+
87
+ create_table :thredded_topic_categories do |t|
88
+ t.integer :topic_id, null: false
89
+ t.integer :category_id, null: false
90
+ end
91
+
92
+ create_table :thredded_topics do |t|
93
+ t.integer :user_id, null: false
94
+ t.integer :last_user_id, null: false
95
+ t.string :title, null: false
96
+ t.string :slug, null: false
97
+ t.integer :messageboard_id, null: false
98
+ t.integer :posts_count, default: 0
99
+ t.string :attribs, default: '[]'
100
+ t.boolean :sticky, default: false
101
+ t.boolean :locked, default: false
102
+ t.string :hash_id, null: false
103
+ t.string :state, default: 'approved', null: false
104
+ t.string :type
105
+ t.timestamps
106
+ end
107
+
108
+ create_table :thredded_user_details do |t|
109
+ t.integer :user_id, null: false
110
+ t.datetime :latest_activity_at
111
+ t.integer :posts_count, default: 0
112
+ t.integer :topics_count, default: 0
113
+ t.boolean :superadmin, default: false
114
+ t.timestamps
115
+ end
116
+
117
+ add_index :thredded_user_details, :user_id
118
+ add_index :thredded_user_details, :latest_activity_at
119
+
120
+ create_table :thredded_user_preferences do |t|
121
+ t.integer :user_id, null: false
122
+ t.string :time_zone, default: 'Eastern Time (US & Canada)'
123
+ t.timestamps
124
+ end
125
+
126
+ add_index :thredded_user_preferences, :user_id
127
+
128
+ create_table :thredded_user_topic_reads do |t|
129
+ t.integer :user_id, null: false
130
+ t.integer :topic_id, null: false
131
+ t.integer :post_id, null: false
132
+ t.integer :posts_count, default: 0, null: false
133
+ t.integer :page, default: 1, null: false
134
+ t.timestamps
135
+ end
136
+
137
+ add_index :thredded_user_topic_reads, :user_id
138
+ add_index :thredded_user_topic_reads, :topic_id
139
+ add_index :thredded_user_topic_reads, :post_id
140
+ add_index :thredded_user_topic_reads, :page
141
+ add_index :thredded_user_topic_reads, :posts_count
142
+ end
143
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :thredded do
3
+ # # Task goes here
4
+ # end
data/lib/thredded.rb ADDED
@@ -0,0 +1,38 @@
1
+ require 'thredded/engine'
2
+ require 'cancan'
3
+ require 'carrierwave'
4
+ require 'kaminari'
5
+ require 'friendly_id'
6
+ require 'nested_form'
7
+ require 'thredded/filter/base'
8
+ require 'thredded/filter/at_notification'
9
+ require 'thredded/filter/attachment'
10
+ require 'thredded/filter/bbcode'
11
+ require 'thredded/filter/emoji'
12
+ require 'thredded/filter/markdown'
13
+ require 'thredded/filter/textile'
14
+ require 'thredded/messageboard_user_permissions'
15
+ require 'thredded/post_user_permissions'
16
+ require 'thredded/private_topic_user_permissions'
17
+ require 'thredded/topic_user_permissions'
18
+
19
+ module Thredded
20
+ mattr_accessor :user_class,
21
+ :email_incoming_host,
22
+ :email_from,
23
+ :email_outgoing_prefix
24
+
25
+ def self.user_class
26
+ if @@user_class.is_a?(Class)
27
+ raise 'Please use a string instead of a class'
28
+ end
29
+
30
+ if @@user_class.is_a?(String)
31
+ begin
32
+ Object.const_get(@@user_class)
33
+ rescue NameError
34
+ @@user_class.constantize
35
+ end
36
+ end
37
+ end
38
+ end