enki-engine 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (206) hide show
  1. data/.gitignore +13 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +3 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +284 -0
  6. data/README.textile +112 -0
  7. data/Rakefile +13 -0
  8. data/TODO.textile +8 -0
  9. data/app/assets/images/admin/flash_bg.gif +0 -0
  10. data/app/assets/images/admin/future_bg.png +0 -0
  11. data/app/assets/images/admin/gray_bg.gif +0 -0
  12. data/app/assets/images/admin/new_button.png +0 -0
  13. data/app/assets/images/admin/silver_bg.gif +0 -0
  14. data/app/assets/images/admin/submit_bg.gif +0 -0
  15. data/app/assets/images/admin/subnav_bg.gif +0 -0
  16. data/app/assets/images/openid_icon.png +0 -0
  17. data/app/assets/images/rails.png +0 -0
  18. data/app/assets/images/silk/arrow_undo.png +0 -0
  19. data/app/assets/images/silk/delete.png +0 -0
  20. data/app/assets/images/silk/pencil.png +0 -0
  21. data/app/assets/javascripts/admin/actions.js +18 -0
  22. data/app/assets/javascripts/admin/comments.js +3 -0
  23. data/app/assets/javascripts/admin/common.js +109 -0
  24. data/app/assets/javascripts/admin/dashboard.js +33 -0
  25. data/app/assets/javascripts/admin/edit-preview.js +40 -0
  26. data/app/assets/javascripts/admin/pages.js +1 -0
  27. data/app/assets/javascripts/admin/posts.js +1 -0
  28. data/app/assets/javascripts/admin/shortcut.js +223 -0
  29. data/app/assets/javascripts/admin.js +17 -0
  30. data/app/assets/javascripts/application.js +15 -0
  31. data/app/assets/javascripts/common.js +22 -0
  32. data/app/assets/javascripts/enki.js +13 -0
  33. data/app/assets/javascripts/live-comment-preview.js +36 -0
  34. data/app/assets/stylesheets/admin.css +304 -0
  35. data/app/assets/stylesheets/application.css.scss +486 -0
  36. data/app/assets/stylesheets/humanmsg.css +112 -0
  37. data/app/assets/stylesheets/login.css +65 -0
  38. data/app/controllers/enki/admin/base_controller.rb +15 -0
  39. data/app/controllers/enki/admin/comments_controller.rb +52 -0
  40. data/app/controllers/enki/admin/dashboard_controller.rb +12 -0
  41. data/app/controllers/enki/admin/health_controller.rb +20 -0
  42. data/app/controllers/enki/admin/pages_controller.rb +97 -0
  43. data/app/controllers/enki/admin/posts_controller.rb +104 -0
  44. data/app/controllers/enki/admin/undo_items_controller.rb +43 -0
  45. data/app/controllers/enki/application_controller.rb +21 -0
  46. data/app/controllers/enki/archives_controller.rb +7 -0
  47. data/app/controllers/enki/base_controller.rb +5 -0
  48. data/app/controllers/enki/comments_controller.rb +43 -0
  49. data/app/controllers/enki/pages_controller.rb +7 -0
  50. data/app/controllers/enki/posts_controller.rb +27 -0
  51. data/app/helpers/enki/admin/navigation_helper.rb +10 -0
  52. data/app/helpers/enki/application_helper.rb +35 -0
  53. data/app/helpers/enki/date_helper.rb +15 -0
  54. data/app/helpers/enki/form_helper.rb +7 -0
  55. data/app/helpers/enki/host_helper.rb +19 -0
  56. data/app/helpers/enki/navigation_helper.rb +23 -0
  57. data/app/helpers/enki/page_title_helper.rb +33 -0
  58. data/app/helpers/enki/posts_helper.rb +9 -0
  59. data/app/helpers/enki/tag_helper.rb +7 -0
  60. data/app/helpers/enki/url_helper.rb +25 -0
  61. data/app/models/enki/base/post.rb +153 -0
  62. data/app/models/enki/comment.rb +75 -0
  63. data/app/models/enki/comment_activity.rb +33 -0
  64. data/app/models/enki/delete_comment_undo.rb +33 -0
  65. data/app/models/enki/delete_page_undo.rb +32 -0
  66. data/app/models/enki/delete_post_undo.rb +36 -0
  67. data/app/models/enki/page.rb +42 -0
  68. data/app/models/enki/post.rb +4 -0
  69. data/app/models/enki/stats.rb +19 -0
  70. data/app/models/enki/tag.rb +19 -0
  71. data/app/models/enki/tagging.rb +7 -0
  72. data/app/models/enki/undo_item.rb +10 -0
  73. data/app/views/enki/admin/comments/_comment.html.erb +12 -0
  74. data/app/views/enki/admin/comments/index.html.erb +30 -0
  75. data/app/views/enki/admin/comments/show.html.erb +9 -0
  76. data/app/views/enki/admin/dashboard/show.html.erb +61 -0
  77. data/app/views/enki/admin/health/index.html.erb +3 -0
  78. data/app/views/enki/admin/pages/_form.html.erb +3 -0
  79. data/app/views/enki/admin/pages/_page.html.erb +12 -0
  80. data/app/views/enki/admin/pages/index.html.erb +25 -0
  81. data/app/views/enki/admin/pages/new.html.erb +8 -0
  82. data/app/views/enki/admin/pages/show.html.erb +8 -0
  83. data/app/views/enki/admin/posts/_form.html.erb +11 -0
  84. data/app/views/enki/admin/posts/_post.html.erb +12 -0
  85. data/app/views/enki/admin/posts/_taggings_form.html.erb +4 -0
  86. data/app/views/enki/admin/posts/_upload_form.html.erb +0 -0
  87. data/app/views/enki/admin/posts/index.html.erb +25 -0
  88. data/app/views/enki/admin/posts/new.html.erb +8 -0
  89. data/app/views/enki/admin/posts/show.html.erb +8 -0
  90. data/app/views/enki/admin/undo_items/index.html.erb +24 -0
  91. data/app/views/enki/archives/index.html.erb +17 -0
  92. data/app/views/enki/comments/_comment.html.erb +4 -0
  93. data/app/views/enki/pages/_page.html.erb +3 -0
  94. data/app/views/enki/pages/show.html.erb +5 -0
  95. data/app/views/enki/posts/_post.html.erb +13 -0
  96. data/app/views/enki/posts/index.atom.builder +27 -0
  97. data/app/views/enki/posts/index.html.erb +15 -0
  98. data/app/views/enki/posts/show.html.erb +37 -0
  99. data/autotest/discover.rb +2 -0
  100. data/config/cucumber.yml +8 -0
  101. data/config/enki.yml.sample +16 -0
  102. data/config/initializers/enki_ext.rb +3 -0
  103. data/config/initializers/set_chronic_timezone.rb +1 -0
  104. data/config/initializers/verification.rb +135 -0
  105. data/config/routes.rb +34 -0
  106. data/db/migrate/20110709024316_initialize_db.rb +97 -0
  107. data/db/seeds.rb +8 -0
  108. data/enki-engine.gemspec +47 -0
  109. data/features/admin_dashboard.feature +10 -0
  110. data/features/admin_health.feature +10 -0
  111. data/features/admin_undo.feature +20 -0
  112. data/features/browsing.feature +16 -0
  113. data/features/step_definitions/admin.rb +27 -0
  114. data/features/step_definitions/browsing.rb +3 -0
  115. data/features/step_definitions/posts.rb +11 -0
  116. data/features/step_definitions/web_steps.rb +1 -0
  117. data/features/support/env.rb +59 -0
  118. data/features/support/paths.rb +35 -0
  119. data/features/support/selectors.rb +39 -0
  120. data/lib/core_extensions/object.rb +9 -0
  121. data/lib/core_extensions/string.rb +22 -0
  122. data/lib/enki/config.rb +44 -0
  123. data/lib/enki/engine.rb +19 -0
  124. data/lib/enki/html5_tags.rb +8 -0
  125. data/lib/enki/pagination_shim.rb +25 -0
  126. data/lib/enki/version.rb +3 -0
  127. data/lib/enki.rb +14 -0
  128. data/lib/enki_formatter.rb +11 -0
  129. data/lib/tag_list.rb +2 -0
  130. data/lib/tags_helper.rb +13 -0
  131. data/lib/tasks/cucumber.rake +65 -0
  132. data/lib/tasks/enki.rake +29 -0
  133. data/lib/undo_failed.rb +2 -0
  134. data/script/cucumber +10 -0
  135. data/spec/controllers/admin/comments_controller_spec.rb +140 -0
  136. data/spec/controllers/admin/dashboard_controller_spec.rb +47 -0
  137. data/spec/controllers/admin/health_controller_spec.rb +49 -0
  138. data/spec/controllers/admin/pages_controller_spec.rb +136 -0
  139. data/spec/controllers/admin/posts_controller_spec.rb +183 -0
  140. data/spec/controllers/admin/undo_items_controller_spec.rb +93 -0
  141. data/spec/controllers/archives_controller_spec.rb +37 -0
  142. data/spec/controllers/comments_controller_spec.rb +126 -0
  143. data/spec/controllers/pages_controller_spec.rb +46 -0
  144. data/spec/controllers/posts_controller_spec.rb +168 -0
  145. data/spec/dummy/Gemfile +5 -0
  146. data/spec/dummy/Rakefile +7 -0
  147. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  148. data/spec/dummy/config/application.rb +34 -0
  149. data/spec/dummy/config/boot.rb +10 -0
  150. data/spec/dummy/config/database.yml +6 -0
  151. data/spec/dummy/config/enki.yml +20 -0
  152. data/spec/dummy/config/environment.rb +5 -0
  153. data/spec/dummy/config/environments/development.rb +34 -0
  154. data/spec/dummy/config/environments/test.rb +32 -0
  155. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  156. data/spec/dummy/config/initializers/session_store.rb +8 -0
  157. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  158. data/spec/dummy/config/locales/en.yml +5 -0
  159. data/spec/dummy/config/routes.rb +14 -0
  160. data/spec/dummy/config.ru +6 -0
  161. data/spec/dummy/script/rails +6 -0
  162. data/spec/factories/factories.rb +36 -0
  163. data/spec/helpers/page_title_helper_spec.rb +54 -0
  164. data/spec/helpers/url_helper_spec.rb +23 -0
  165. data/spec/lib/slugorize_spec.rb +44 -0
  166. data/spec/models/comment_activity_spec.rb +60 -0
  167. data/spec/models/comment_spec.rb +125 -0
  168. data/spec/models/delete_comment_undo_spec.rb +52 -0
  169. data/spec/models/delete_post_undo_spec.rb +18 -0
  170. data/spec/models/page_spec.rb +75 -0
  171. data/spec/models/post_spec.rb +257 -0
  172. data/spec/models/stats_spec.rb +28 -0
  173. data/spec/models/tag_spec.rb +13 -0
  174. data/spec/models/tagging_spec.rb +30 -0
  175. data/spec/rcov.opts +2 -0
  176. data/spec/routing/admin/pages_routing_spec.rb +29 -0
  177. data/spec/routing/archives_routing_spec.rb +9 -0
  178. data/spec/routing/comments_routing_spec.rb +17 -0
  179. data/spec/routing/pages_routing_spec.rb +9 -0
  180. data/spec/routing/posts_routing_spec.rb +26 -0
  181. data/spec/spec.opts +4 -0
  182. data/spec/spec_helper.rb +60 -0
  183. data/spec/support/be_valid_html5.rb +150 -0
  184. data/spec/support/be_valid_xhtml.rb +148 -0
  185. data/spec/support/routes_override_helper.rb +12 -0
  186. data/spec/views/admin/comments/index.html_spec.rb +26 -0
  187. data/spec/views/admin/comments/show.html_spec.rb +28 -0
  188. data/spec/views/admin/dashboard/show.html_spec.rb +37 -0
  189. data/spec/views/admin/pages/index.html_spec.rb +23 -0
  190. data/spec/views/admin/pages/new.html_spec.rb +16 -0
  191. data/spec/views/admin/pages/show.html_spec.rb +16 -0
  192. data/spec/views/admin/posts/index.html_spec.rb +24 -0
  193. data/spec/views/admin/posts/new.html_spec.rb +16 -0
  194. data/spec/views/admin/posts/show.html_spec.rb +16 -0
  195. data/spec/views/admin/undo_items/index.html_spec.rb +19 -0
  196. data/spec/views/archives/index.html_spec.rb +34 -0
  197. data/spec/views/pages/show.html_spec.rb +23 -0
  198. data/spec/views/posts/index.atom.builder_spec.rb +36 -0
  199. data/spec/views/posts/index.html_spec.rb +39 -0
  200. data/spec/views/posts/show.html_spec.rb +49 -0
  201. data/vendor/assets/javascripts/humanmsg.js +86 -0
  202. data/vendor/assets/javascripts/jquery.easing.1.3.js +205 -0
  203. data/vendor/assets/javascripts/jquery.form.js +869 -0
  204. data/vendor/assets/javascripts/jquery.jfeed.js +143 -0
  205. data/vendor/assets/javascripts/jquery.livequery.js +250 -0
  206. metadata +464 -0
@@ -0,0 +1,12 @@
1
+ <tr class="<%= cycle('', 'alt') %>">
2
+ <td><%= post.published_at.strftime('%d %b, %Y') %></td>
3
+ <td><%= link_to (post.title == '' ? '[Untitled]' : truncate(post.title, :length => 30)), enki.admin_post_path(post) %></td>
4
+ <td><% tmpc = truncate(post.body, :length => 55) %><%= (tmpc != '' ? tmpc : '&nbsp;') %></td>
5
+ <% if comments? -%><td><%= post.approved_comments.size -%></td><% end -%>
6
+ <td>
7
+ <%= link_to(image_tag('silk/pencil.png', :alt => 'edit'), enki.admin_post_path(post)) %>
8
+ <%= form_for(post, :as => :post, :url => enki.admin_post_path(post), :html => {:class => 'delete-item', :method => :delete}) do |form| -%>
9
+ <%= image_submit_tag("silk/delete.png", :alt => 'Delete Comment') %>
10
+ <% end -%>
11
+ </td>
12
+ </tr>
@@ -0,0 +1,4 @@
1
+ <fieldset>
2
+ <legend>Tags</legend>
3
+ <%= form.input :tag_list, :as => 'string', :required => false, :hint => 'Comma separated: ruby, rails&hellip;'.html_safe -%>
4
+ </fieldset>
File without changes
@@ -0,0 +1,25 @@
1
+ <h1>Your posts</h1>
2
+ <table>
3
+ <thead>
4
+ <tr>
5
+ <th>Published At</th>
6
+ <th>Title</th>
7
+ <th>Excerpt</th>
8
+ <% if comments? -%><th>Comments</th><% end -%>
9
+ <th>Actions</th>
10
+ </tr>
11
+ </thead>
12
+
13
+ <tbody>
14
+ <% if @posts.empty? -%>
15
+ <tr><td colspan="5">There are no posts at this time.</td></tr>
16
+ <% else -%>
17
+ <%= render :partial => 'enki/admin/posts/post', :collection => @posts %>
18
+ <% end -%>
19
+ </tbody>
20
+
21
+ </table>
22
+
23
+ <div class="pagination">
24
+ <%= paginated @posts %>
25
+ </div>
@@ -0,0 +1,8 @@
1
+ <h1>New post</h1>
2
+
3
+ <%= simple_form_for(@post, :url => enki.admin_posts_path) do |form| %>
4
+ <%= render :partial => 'enki/admin/posts/form', :locals => {:form => form} -%>
5
+ <div class="actions">
6
+ <button type="submit" class="button">Save</button>
7
+ </div>
8
+ <% end -%>
@@ -0,0 +1,8 @@
1
+ <h1>Editing post - <%= link_to(@post.title, post_path(@post)) %></h1>
2
+
3
+ <%= simple_form_for @post, :url => enki.admin_post_path(@post) do |form| %>
4
+ <%= render :partial => 'enki/admin/posts/form', :locals => {:form => form} %>
5
+ <div class="actions">
6
+ <button type="submit" class="button">Save</button>
7
+ </div>
8
+ <% end -%>
@@ -0,0 +1,24 @@
1
+ <h1>Recent actions</h1>
2
+ <table>
3
+ <thead>
4
+ <tr>
5
+ <th>Date</th>
6
+ <th>Description</th>
7
+ <th>Action</th>
8
+ </tr>
9
+ </thead>
10
+
11
+ <tbody>
12
+ <% @undo_items.each do |undo_item| -%>
13
+ <tr class="<%= cycle('', 'alt') %>">
14
+ <td><%= undo_item.created_at.strftime('%d %b, %Y') %></td>
15
+ <td><%= undo_item.description %></td>
16
+ <td>
17
+ <%= form_for(undo_item, :as => :undo_item, :url => enki.admin_undo_item_path(undo_item), :html => {:class => 'undo-item', :method => :post}) do |form| -%>
18
+ <%= image_submit_tag("silk/arrow_undo.png", :alt => 'Undo') %>
19
+ <% end -%>
20
+ </td>
21
+ </tr>
22
+ <% end -%>
23
+ </tbody>
24
+ </table>
@@ -0,0 +1,17 @@
1
+ <% content_for(:page_title) do %><%= archives_title %><% end -%>
2
+ <h2>Archives</h2>
3
+
4
+ <% if @months.empty? -%>
5
+ <p>Once posts are added they will start to appear in this archive.</p>
6
+ <% else -%>
7
+
8
+ <% @months.each do |month| -%>
9
+ <h3><%= format_month(month.date) %></h3>
10
+ <ul class='archive-month'>
11
+ <% month.posts.each do |post| -%>
12
+ <li><%= link_to(post.title, post_path(post)) %><% unless post.tags.empty? %> <span class='tags'>(<%= linked_tag_list(post.tags) %>)</span><% end -%></li>
13
+ <% end -%>
14
+ </ul>
15
+ <% end -%>
16
+
17
+ <% end -%>
@@ -0,0 +1,4 @@
1
+ <cite><%= author_link(comment) %></cite> says:
2
+ <br>
3
+ <small class="commentmetadata"><a href="#comment-<%= comment.id %>" title=""><%= format_comment_date(comment.created_at) %></a></small>
4
+ <p><%=raw comment.body_html %></p>
@@ -0,0 +1,3 @@
1
+ <h1><%= page.title -%></h1>
2
+
3
+ <%=raw page.body_html %>
@@ -0,0 +1,5 @@
1
+ <% page = @page unless local_assigns[:page] -%>
2
+ <% content_for(:page_title) do -%>
3
+ <%= page_title(@page) -%>
4
+ <% end -%>
5
+ <%= render :partial => 'enki/pages/page', :locals => {:page => @page} %>
@@ -0,0 +1,13 @@
1
+ <h2><%= link_to(post.title, post_path(post)) %></h2>
2
+ <div class="entrybody">
3
+ <%=raw post.body_html %>
4
+ </div>
5
+ <div class="meta">
6
+ <ul>
7
+ <li class="date">Posted on <%= format_post_date(post.published_at) %></li>
8
+ <% if comments? -%><li class="comments"><%= link_to(pluralize(post.approved_comments.size, "comment"), post_path(post, :anchor => 'comments')) %></li><% end -%>
9
+ <% unless post.tags.empty? -%>
10
+ <li class="tags">Tagged <%= linked_tag_list(post.tags) %></li>
11
+ <% end -%>
12
+ </ul>
13
+ </div>
@@ -0,0 +1,27 @@
1
+ url = if @tag.nil?
2
+ enki.formatted_posts_path(:format => 'atom', :only_path => false)
3
+ else
4
+ enki.posts_path(:tag => @tag, :format => 'atom', :only_path => false)
5
+ end
6
+
7
+ atom_feed(
8
+ :url => url,
9
+ :root_url => enki.posts_path(:tag => @tag, :only_path => false),
10
+ :schema_date => '2008'
11
+ ) do |feed|
12
+ feed.title posts_title(@tag)
13
+ feed.updated @posts.empty? ? Time.now.utc : @posts.collect(&:edited_at).max
14
+ feed.generator "Enki", "uri" => "http://enkiblog.com"
15
+
16
+ feed.author do |xml|
17
+ xml.name author.name
18
+ xml.email author.email unless author.email.nil?
19
+ end
20
+
21
+ @posts.each do |post|
22
+ feed.entry(post, :url => post_path(post, :only_path => false), :published => post.published_at, :updated => post.edited_at) do |entry|
23
+ entry.title post.title
24
+ entry.content post.body_html, :type => 'html'
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ <% content_for(:page_title) do %><%= posts_title(@tag) %><% end -%>
2
+ <% content_for(:head) do %><%= auto_discovery_link_tag(:atom, @tag.nil? ? enki.formatted_posts_path(:format => 'atom') : enki.posts_path(:tag => @tag, :format => 'atom')) %><% end -%>
3
+
4
+ <% if @posts.empty? -%>
5
+ <p>There are no posts yet.</p>
6
+ <% else -%>
7
+ <% @posts.each do |post| -%>
8
+ <div class="post post-<%= post.id %>">
9
+ <%= render :partial => 'enki/posts/post', :locals => {:post => post} %>
10
+ </div>
11
+ <% end -%>
12
+ <% if more_content? -%>
13
+ <div class="related">Looking for more? Head on over to the <%= link_to("archives", enki.archives_path) %>.</div>
14
+ <% end -%>
15
+ <% end -%>
@@ -0,0 +1,37 @@
1
+ <% content_for(:page_title) do -%>
2
+ <%= post_title(@post) -%>
3
+ <% end -%>
4
+ <%= render :partial => 'enki/posts/post', :locals => {:post => @post} %>
5
+
6
+ <% if comments? -%>
7
+ <ol class="commentlist">
8
+ <% @post.approved_comments.each do |comment| -%>
9
+ <li<%=raw cycle(' class="alt"', '') %> id="comment-<%= comment.id %>">
10
+ <%= render :partial => 'enki/comments/comment', :locals => {:comment => comment} %>
11
+ </li>
12
+ <% end -%>
13
+ </ol>
14
+ <% end -%>
15
+
16
+ <div class="related">Looking for more? Head on over to the <%= link_to("archives", enki.archives_path) %>.</div>
17
+
18
+ <% if comments? -%>
19
+ <h2>Post a comment</h2>
20
+ <% unless @comment.errors.empty? -%>
21
+ <div class="errors">
22
+ <h3>Comment not added!</h3>
23
+ <ul>
24
+ <% @comment.errors.sort_by(&:first).each do |error| -%>
25
+ <li><%= format_comment_error(error) %></li>
26
+ <% end -%>
27
+ </ul>
28
+ </div>
29
+ <% end -%>
30
+ <%= form_for @comment, :url => post_comments_path(@post, @comment) do |form| -%>
31
+ <div>
32
+ <p><%= form.text_field 'author' %><label for="comment_author"><small>Name or <a href="http://openidexplained.com/">OpenID</a> (required)</small></label></p>
33
+ <p><%= form.text_area 'body' %><br><small>(<a href="http://lesstile.rubyforge.org">lesstile enabled</a> - surround code blocks with ---)</small></p>
34
+ <p><%= submit_tag "Add Comment" %></p>
35
+ </div>
36
+ <% end -%>
37
+ <% end -%>
@@ -0,0 +1,2 @@
1
+ Autotest.add_discovery { "rails" }
2
+ Autotest.add_discovery { "rspec2" }
@@ -0,0 +1,8 @@
1
+ <%
2
+ rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
3
+ rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
4
+ std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip"
5
+ %>
6
+ default: <%= std_opts %> features
7
+ wip: --tags @wip:3 --wip features
8
+ rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip
@@ -0,0 +1,16 @@
1
+ # Configuration options for your blog - customise to taste and copy to the host app's config folder.
2
+ # This file contains no secret information, so can be stored in source control (unlike database.yml)
3
+ title: My Enki Blog
4
+ url: http://enkiblog.com
5
+ author:
6
+ name: Don Alias # For copyright notice and ATOM feeds
7
+ email: don@enkiblog.com # Exception emails will go here, and it is used in ATOM feeds
8
+ open_id: # These are used to login to the admin area
9
+ - http://enkiblog.com
10
+ - http://secondaryopenid.com
11
+
12
+ # Delete the following section if your site will not be acting as an OpenID delegate (http://wiki.openid.net/Delegation)
13
+ # If you're deploying with mongrel, make sure you read http://rhnh.net/2008/04/13/nginx-openid-delegation-and-yadis
14
+ open_id_delegation:
15
+ server: http://www.myopenid.com/server
16
+ delegate: http://username.myopenid.com
@@ -0,0 +1,3 @@
1
+ require 'core_extensions/string'
2
+ require 'core_extensions/object'
3
+ require 'enki/html5_tags'
@@ -0,0 +1 @@
1
+ Chronic.time_class = Time.zone
@@ -0,0 +1,135 @@
1
+ # From https://github.com/sikachu/verification
2
+ # This used to be an official part of Rails but was deprecated.
3
+ #
4
+ module ActionController #:nodoc:
5
+ module Verification #:nodoc:
6
+ extend ActiveSupport::Concern
7
+
8
+ include AbstractController::Callbacks, Flash, Rendering
9
+
10
+ # This module provides a class-level method for specifying that certain
11
+ # actions are guarded against being called without certain prerequisites
12
+ # being met. This is essentially a special kind of before_filter.
13
+ #
14
+ # An action may be guarded against being invoked without certain request
15
+ # parameters being set, or without certain session values existing.
16
+ #
17
+ # When a verification is violated, values may be inserted into the flash, and
18
+ # a specified redirection is triggered. If no specific action is configured,
19
+ # verification failures will by default result in a 400 Bad Request response.
20
+ #
21
+ # Usage:
22
+ #
23
+ # class GlobalController < ActionController::Base
24
+ # # Prevent the #update_settings action from being invoked unless
25
+ # # the 'admin_privileges' request parameter exists. The
26
+ # # settings action will be redirected to in current controller
27
+ # # if verification fails.
28
+ # verify :params => "admin_privileges", :only => :update_post,
29
+ # :redirect_to => { :action => "settings" }
30
+ #
31
+ # # Disallow a post from being updated if there was no information
32
+ # # submitted with the post, and if there is no active post in the
33
+ # # session, and if there is no "note" key in the flash. The route
34
+ # # named category_url will be redirected to if verification fails.
35
+ #
36
+ # verify :params => "post", :session => "post", "flash" => "note",
37
+ # :only => :update_post,
38
+ # :add_flash => { "alert" => "Failed to create your message" },
39
+ # :redirect_to => :category_url
40
+ #
41
+ # Note that these prerequisites are not business rules. They do not examine
42
+ # the content of the session or the parameters. That level of validation should
43
+ # be encapsulated by your domain model or helper methods in the controller.
44
+ module ClassMethods
45
+ # Verify the given actions so that if certain prerequisites are not met,
46
+ # the user is redirected to a different action. The +options+ parameter
47
+ # is a hash consisting of the following key/value pairs:
48
+ #
49
+ # <tt>:params</tt>::
50
+ # a single key or an array of keys that must be in the <tt>params</tt>
51
+ # hash in order for the action(s) to be safely called.
52
+ # <tt>:session</tt>::
53
+ # a single key or an array of keys that must be in the <tt>session</tt>
54
+ # in order for the action(s) to be safely called.
55
+ # <tt>:flash</tt>::
56
+ # a single key or an array of keys that must be in the flash in order
57
+ # for the action(s) to be safely called.
58
+ # <tt>:method</tt>::
59
+ # a single key or an array of keys--any one of which must match the
60
+ # current request method in order for the action(s) to be safely called.
61
+ # (The key should be a symbol: <tt>:get</tt> or <tt>:post</tt>, for
62
+ # example.)
63
+ # <tt>:xhr</tt>::
64
+ # true/false option to ensure that the request is coming from an Ajax
65
+ # call or not.
66
+ # <tt>:add_flash</tt>::
67
+ # a hash of name/value pairs that should be merged into the session's
68
+ # flash if the prerequisites cannot be satisfied.
69
+ # <tt>:add_headers</tt>::
70
+ # a hash of name/value pairs that should be merged into the response's
71
+ # headers hash if the prerequisites cannot be satisfied.
72
+ # <tt>:redirect_to</tt>::
73
+ # the redirection parameters to be used when redirecting if the
74
+ # prerequisites cannot be satisfied. You can redirect either to named
75
+ # route or to the action in some controller.
76
+ # <tt>:render</tt>::
77
+ # the render parameters to be used when the prerequisites cannot be satisfied.
78
+ # <tt>:only</tt>::
79
+ # only apply this verification to the actions specified in the associated
80
+ # array (may also be a single value).
81
+ # <tt>:except</tt>::
82
+ # do not apply this verification to the actions specified in the associated
83
+ # array (may also be a single value).
84
+ def verify(options={})
85
+ before_filter :only => options[:only], :except => options[:except] do
86
+ verify_action options
87
+ end
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def verify_action(options) #:nodoc:
94
+ if prereqs_invalid?(options)
95
+ flash.update(options[:add_flash]) if options[:add_flash]
96
+ response.headers.merge!(options[:add_headers]) if options[:add_headers]
97
+ apply_remaining_actions(options) unless performed?
98
+ end
99
+ end
100
+
101
+ def prereqs_invalid?(options) # :nodoc:
102
+ verify_presence_of_keys_in_hash_flash_or_params(options) ||
103
+ verify_method(options) ||
104
+ verify_request_xhr_status(options)
105
+ end
106
+
107
+ def verify_presence_of_keys_in_hash_flash_or_params(options) # :nodoc:
108
+ [*options[:params] ].find { |v| v && params[v.to_sym].nil? } ||
109
+ [*options[:session]].find { |v| session[v].nil? } ||
110
+ [*options[:flash] ].find { |v| flash[v].nil? }
111
+ end
112
+
113
+ def verify_method(options) # :nodoc:
114
+ [*options[:method]].all? { |v| request.method_symbol != v.to_sym } if options[:method]
115
+ end
116
+
117
+ def verify_request_xhr_status(options) # :nodoc:
118
+ request.xhr? != options[:xhr] unless options[:xhr].nil?
119
+ end
120
+
121
+ def apply_redirect_to(redirect_to_option) # :nodoc:
122
+ (redirect_to_option.is_a?(Symbol) && redirect_to_option != :back) ? self.__send__(redirect_to_option) : redirect_to_option
123
+ end
124
+
125
+ def apply_remaining_actions(options) # :nodoc:
126
+ case
127
+ when options[:render] ; render(options[:render])
128
+ when options[:redirect_to] ; redirect_to(apply_redirect_to(options[:redirect_to]))
129
+ else head(:bad_request)
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ ActionController::Base.send :include, ActionController::Verification
data/config/routes.rb ADDED
@@ -0,0 +1,34 @@
1
+ Enki::Engine.routes.draw do
2
+ scope :module => 'enki' do
3
+ namespace :admin do
4
+
5
+ resources :posts, :pages do
6
+ post 'preview', :on => :collection
7
+ end
8
+ resources :comments
9
+ resources :undo_items do
10
+ post 'undo', :on => :member
11
+ end
12
+
13
+ match 'health(/:action)' => 'health', :action => 'index', :as => :health
14
+
15
+ root :to => 'dashboard#show'
16
+ end
17
+ resources :archives, :only => [:index]
18
+ resources :pages, :only => [:show]
19
+ end
20
+
21
+ constraints :year => /\d{4}/, :month => /\d{2}/, :day => /\d{2}/ do
22
+ get ':year/:month/:day/:slug/comments' => 'enki/comments#index'
23
+ post ':year/:month/:day/:slug/comments' => 'enki/comments#create'
24
+ get ':year/:month/:day/:slug/comments/new' => 'enki/comments#new'
25
+ get ':year/:month/:day/:slug' => 'enki/posts#show'
26
+ end
27
+
28
+ scope :to => 'enki/posts#index' do
29
+ get 'posts.:format', :as => :formatted_posts
30
+ get '(:tag)', :as => :posts
31
+ end
32
+
33
+ root :to => 'enki/posts#index'
34
+ end
@@ -0,0 +1,97 @@
1
+ class InitializeDb < ActiveRecord::Migration
2
+
3
+ def change
4
+
5
+ create_table "pages" do |t|
6
+ t.string "title", :null => false
7
+ t.string "slug", :null => false
8
+ t.text "body", :null => false
9
+ t.text "body_html", :null => false
10
+
11
+ t.timestamps
12
+ end
13
+
14
+ add_index "pages", 'slug'
15
+ add_index "pages", "title"
16
+ add_index "pages", "created_at"
17
+
18
+ create_table "posts" do |t|
19
+ t.string "title", :null => false
20
+ t.string "slug", :null => false
21
+ t.text "body", :null => false
22
+ t.text "body_html", :null => false
23
+ t.boolean "active", :default => true, :null => false
24
+ t.string "cached_tag_list"
25
+ t.datetime "published_at"
26
+ t.datetime "edited_at", :null => false
27
+
28
+ t.timestamps
29
+ end
30
+
31
+ add_index "posts", 'slug'
32
+ add_index "posts", "published_at"
33
+
34
+ create_table "undo_items" do |t|
35
+ t.string "type", :null => false
36
+ t.datetime "created_at", :null => false
37
+ t.text "data"
38
+ end
39
+
40
+ add_index "undo_items", "created_at"
41
+
42
+ if comments?
43
+
44
+ create_table "comments" do |t|
45
+ t.integer "post_id", :null => false
46
+ t.string "author"
47
+ t.string "author_url"
48
+ t.string "author_email"
49
+ t.text "body", :null => false
50
+ t.text "body_html", :null => false
51
+
52
+ t.timestamps
53
+ end
54
+
55
+ add_index "comments", "post_id"
56
+ add_index "comments", "created_at"
57
+
58
+ add_column "posts", "approved_comments_count", :integer, :default => 0, :null => false
59
+
60
+ end
61
+
62
+ if tags?
63
+
64
+ create_table 'tags' do |t|
65
+ t.string 'name'
66
+ t.integer "taggings_count", :default => 0, :null => false
67
+ end
68
+
69
+ create_table 'taggings' do |t|
70
+ t.references 'tag'
71
+
72
+ t.references 'taggable', :polymorphic => true
73
+ t.references 'tagger', :polymorphic => true
74
+
75
+ t.string 'context', :limit => 128
76
+
77
+ t.timestamps
78
+ end
79
+
80
+ add_index 'taggings', 'tag_id'
81
+ add_index 'taggings', ['taggable_id', 'taggable_type', 'context']
82
+
83
+ end
84
+
85
+ end
86
+
87
+ private
88
+
89
+ def comments?
90
+ Enki::Config.default[:features, :comments]
91
+ end
92
+
93
+ def tags?
94
+ Enki::Config.default[:features, :tags]
95
+ end
96
+
97
+ end
data/db/seeds.rb ADDED
@@ -0,0 +1,8 @@
1
+ if Rails.env == 'development'
2
+ module Enki
3
+ Post.destroy_all
4
+ 20.times do |idx|
5
+ Post.create!(:title => "Test post #{idx}", :body => "Lorem ipsum plipsum nipsum.")
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,47 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "enki/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "enki-engine"
7
+ s.version = Enki::VERSION
8
+ s.date = "2012-02-22"
9
+ s.authors = ["James McCarthy", "Andy Triggs", "Xavier Shay"]
10
+ s.email = ["james2mccarthy@gmail.com"]
11
+ s.homepage = "http://github.com/ThisIsHatch/enki_engine"
12
+ s.summary = %Q{A Rails3 engine adapted from Xavier Shay's Enki blogging app}
13
+ s.description = %Q{An adaptation of the Enki blogging application as a Rails::Engine, for mounting in a host application}
14
+
15
+ s.rubyforge_project = "enki-engine"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.extra_rdoc_files = [
21
+ "LICENSE",
22
+ "README.textile"
23
+ ]
24
+ s.require_paths = ["lib"]
25
+
26
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2.0") if s.respond_to? :required_rubygems_version=
27
+
28
+ s.add_runtime_dependency 'RedCloth', "~> 4.2.9"
29
+ s.add_runtime_dependency 'aaronh-chronic'
30
+ s.add_runtime_dependency 'coderay'
31
+ s.add_runtime_dependency 'lesstile'
32
+ s.add_runtime_dependency 'simple_form'
33
+
34
+ s.add_development_dependency 'acts-as-taggable-on'
35
+ s.add_development_dependency 'rails', "~> 3.2"
36
+ s.add_development_dependency 'rspec-rails', ">= 2.9"
37
+ s.add_development_dependency 'factory_girl_rails'
38
+ s.add_development_dependency 'nokogiri', '~> 1.5.0'
39
+ s.add_development_dependency 'webrat'
40
+ s.add_development_dependency 'sqlite3'
41
+
42
+ # s.add_development_dependency 'database_cleaner'
43
+ # s.add_development_dependency 'cucumber-rails', :require => false
44
+ # s.add_development_dependency 'cucumber-websteps', :require => false
45
+ end
46
+
47
+
@@ -0,0 +1,10 @@
1
+ Feature: Dashboard
2
+ Because I want to see what the go is with my blog
3
+ An admin
4
+ Should be able to see interesting things on the dashboard
5
+
6
+ Scenario: viewing dash board
7
+ Given I am logged in
8
+ And a post with comments exists
9
+ When I go to /admin
10
+ Then I should see "Latest Comments"
@@ -0,0 +1,10 @@
1
+ Feature: Health Monitor
2
+ Because I want to have confidence that my site works
3
+ An admin
4
+ Should be able generate an exception to verify the error reporting stack is working
5
+
6
+ Scenario: generating an exception
7
+ Given I am logged in
8
+ When I go to /admin
9
+ And I follow "Health"
10
+ Then a RuntimeError is thrown when I press "Throw exception"
@@ -0,0 +1,20 @@
1
+ Feature: Undo
2
+ Because I am human and make mistakes
3
+ An admin
4
+ Should be able to undo actions they make
5
+
6
+ Scenario: delete a comment, then undo it
7
+ Given I am logged in
8
+ And the following comment exists:
9
+ | body |
10
+ | Accidental Delete |
11
+ When I go to /admin
12
+ And I follow "Comments"
13
+ And I press "Delete Comment"
14
+ # Not sure why this doesn't redirect automatically
15
+ # And I follow "redirected"
16
+ And I follow "Actions"
17
+ And I press "Undo"
18
+ Then a comment exists with attributes:
19
+ | body |
20
+ | Accidental Delete |
@@ -0,0 +1,16 @@
1
+ Feature: Browsing
2
+ Because I write totally awesome posts
3
+ An everyday Joe
4
+ Should be able to read and comment on my posts
5
+
6
+ Scenario: browsing the home page
7
+ Given there is at least one post tagged "awesome"
8
+ When I go to the home page
9
+ Then I should see "This is a post"
10
+ And I should see a link to all posts tagged "awesome"
11
+
12
+ Scenario: browsing the archive, to find more content to read
13
+ Given there is at least one post titled "My Post"
14
+ When I go to the home page
15
+ And I follow "Archives"
16
+ Then I should see "My Post"