tolaria 1.0.0

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 (219) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +66 -0
  3. data/.yardopts +4 -0
  4. data/CNAME +1 -0
  5. data/CONTRIBUTING.md +32 -0
  6. data/Gemfile +2 -0
  7. data/LICENSE.md +9 -0
  8. data/README.md +538 -0
  9. data/Rakefile +52 -0
  10. data/app/assets/fonts/admin/fontawesome.eot +0 -0
  11. data/app/assets/fonts/admin/fontawesome.svg +565 -0
  12. data/app/assets/fonts/admin/fontawesome.ttf +0 -0
  13. data/app/assets/fonts/admin/fontawesome.woff +0 -0
  14. data/app/assets/fonts/admin/fontawesome.woff2 +0 -0
  15. data/app/assets/images/admin/columbia_banner.png +0 -0
  16. data/app/assets/images/admin/favicon.ico +0 -0
  17. data/app/assets/images/admin/noise.png +0 -0
  18. data/app/assets/images/admin/select_arrows.svg +1 -0
  19. data/app/assets/javascripts/admin/admin.js +4 -0
  20. data/app/assets/javascripts/admin/base.js +12 -0
  21. data/app/assets/javascripts/admin/lib/backbone.js +1888 -0
  22. data/app/assets/javascripts/admin/lib/jquery.chosen.js +1272 -0
  23. data/app/assets/javascripts/admin/lib/jquery.js +10361 -0
  24. data/app/assets/javascripts/admin/lib/jquery.selection.js +352 -0
  25. data/app/assets/javascripts/admin/lib/moment.js +3103 -0
  26. data/app/assets/javascripts/admin/lib/no.js +6 -0
  27. data/app/assets/javascripts/admin/lib/underscore.js +1570 -0
  28. data/app/assets/javascripts/admin/models/composer_buttons.js +45 -0
  29. data/app/assets/javascripts/admin/models/rails_meta.js +4 -0
  30. data/app/assets/javascripts/admin/views/field_with_errors.js +19 -0
  31. data/app/assets/javascripts/admin/views/fields/attachment_field.js +32 -0
  32. data/app/assets/javascripts/admin/views/fields/has_many.js +64 -0
  33. data/app/assets/javascripts/admin/views/fields/image_association_select.js +31 -0
  34. data/app/assets/javascripts/admin/views/fields/markdown_composer.js +167 -0
  35. data/app/assets/javascripts/admin/views/fields/searchable_select.js +70 -0
  36. data/app/assets/javascripts/admin/views/fields/slug_field.js +38 -0
  37. data/app/assets/javascripts/admin/views/fields/swatch_field.js +55 -0
  38. data/app/assets/javascripts/admin/views/fields/timestamp_field.js +80 -0
  39. data/app/assets/javascripts/admin/views/flash_message.js +18 -0
  40. data/app/assets/javascripts/admin/views/form_orchestrator.js +41 -0
  41. data/app/assets/javascripts/admin/views/navigation.js +20 -0
  42. data/app/assets/javascripts/admin/views/resource_form.js +18 -0
  43. data/app/assets/javascripts/admin/views/search_form.js +20 -0
  44. data/app/assets/javascripts/admin/views/sessions.js +109 -0
  45. data/app/assets/javascripts/admin/views/virtual_form.js +47 -0
  46. data/app/assets/stylesheets/admin/_base.scss +5 -0
  47. data/app/assets/stylesheets/admin/_reset.scss +149 -0
  48. data/app/assets/stylesheets/admin/_root.scss +63 -0
  49. data/app/assets/stylesheets/admin/admin.scss +4 -0
  50. data/app/assets/stylesheets/admin/components/_blank_slate.scss +44 -0
  51. data/app/assets/stylesheets/admin/components/_buttons.scss +82 -0
  52. data/app/assets/stylesheets/admin/components/_flash_message.scss +64 -0
  53. data/app/assets/stylesheets/admin/components/_footer.scss +9 -0
  54. data/app/assets/stylesheets/admin/components/_header.scss +107 -0
  55. data/app/assets/stylesheets/admin/components/_index_table.scss +120 -0
  56. data/app/assets/stylesheets/admin/components/_main.scss +68 -0
  57. data/app/assets/stylesheets/admin/components/_markdown_body.scss +109 -0
  58. data/app/assets/stylesheets/admin/components/_navigation.scss +110 -0
  59. data/app/assets/stylesheets/admin/components/_pagination.scss +36 -0
  60. data/app/assets/stylesheets/admin/components/_pill.scss +11 -0
  61. data/app/assets/stylesheets/admin/components/_resource_form.scss +222 -0
  62. data/app/assets/stylesheets/admin/components/_search_form.scss +36 -0
  63. data/app/assets/stylesheets/admin/components/_sessions.scss +152 -0
  64. data/app/assets/stylesheets/admin/components/_show_table.scss +67 -0
  65. data/app/assets/stylesheets/admin/components/forms/_attachment_field.scss +59 -0
  66. data/app/assets/stylesheets/admin/components/forms/_chosen.scss +478 -0
  67. data/app/assets/stylesheets/admin/components/forms/_image_association_select.scss +20 -0
  68. data/app/assets/stylesheets/admin/components/forms/_markdown_composer.scss +149 -0
  69. data/app/assets/stylesheets/admin/components/forms/_nested_fields.scss +63 -0
  70. data/app/assets/stylesheets/admin/components/forms/_searchable_select.scss +8 -0
  71. data/app/assets/stylesheets/admin/components/forms/_slug_field.scss +20 -0
  72. data/app/assets/stylesheets/admin/components/forms/_swatch_field.scss +47 -0
  73. data/app/assets/stylesheets/admin/components/forms/_timestamp_field.scss +15 -0
  74. data/app/assets/stylesheets/admin/components/help_link.scss +6 -0
  75. data/app/assets/stylesheets/admin/mixins/_clearfix.scss +18 -0
  76. data/app/assets/stylesheets/admin/mixins/_min_max_width.scss +11 -0
  77. data/app/assets/stylesheets/admin/mixins/_rgbb.scss +7 -0
  78. data/app/assets/stylesheets/admin/mixins/_visuallyhidden.scss +33 -0
  79. data/app/assets/stylesheets/admin/settings/_animations.scss +21 -0
  80. data/app/assets/stylesheets/admin/settings/_breakpoints.scss +2 -0
  81. data/app/assets/stylesheets/admin/settings/_colors.scss +32 -0
  82. data/app/assets/stylesheets/admin/settings/_fonts.scss +31 -0
  83. data/app/assets/stylesheets/admin/settings/_icons.scss +1658 -0
  84. data/app/controllers/admin/admin_controller.rb +21 -0
  85. data/app/controllers/admin/sessions_controller.rb +112 -0
  86. data/app/controllers/tolaria/resource_controller.rb +132 -0
  87. data/app/controllers/tolaria/tolaria_controller.rb +40 -0
  88. data/app/helpers/admin/table_helper.rb +175 -0
  89. data/app/helpers/admin/view_helper.rb +76 -0
  90. data/app/mailers/passcode_mailer.rb +11 -0
  91. data/app/models/administrator.rb +146 -0
  92. data/app/views/admin/administrators/_form.html.erb +16 -0
  93. data/app/views/admin/administrators/_index.html.erb +20 -0
  94. data/app/views/admin/administrators/_search.html.erb +5 -0
  95. data/app/views/admin/administrators/_show.html.erb +14 -0
  96. data/app/views/admin/help/help_link.html.erb +16 -0
  97. data/app/views/admin/session/form.html.erb +52 -0
  98. data/app/views/admin/shared/_flash_messages.html.erb +42 -0
  99. data/app/views/admin/shared/_footer.html.erb +8 -0
  100. data/app/views/admin/shared/_head.html.erb +11 -0
  101. data/app/views/admin/shared/_header.html.erb +43 -0
  102. data/app/views/admin/shared/_navigation.html.erb +47 -0
  103. data/app/views/admin/shared/_skiplinks.html.erb +0 -0
  104. data/app/views/admin/shared/forms/_attachment_field.html.erb +17 -0
  105. data/app/views/admin/shared/forms/_has_many.html.erb +14 -0
  106. data/app/views/admin/shared/forms/_has_many_header.html.erb +19 -0
  107. data/app/views/admin/shared/forms/_image_association_select.html.erb +6 -0
  108. data/app/views/admin/shared/forms/_image_field.html.erb +19 -0
  109. data/app/views/admin/shared/forms/_markdown_composer.html.erb +29 -0
  110. data/app/views/admin/shared/forms/_searchable_select.html.erb +3 -0
  111. data/app/views/admin/shared/forms/_slug_field.html.erb +9 -0
  112. data/app/views/admin/shared/forms/_swatch_field.html.erb +4 -0
  113. data/app/views/admin/shared/forms/_timestamp_field.html.erb +19 -0
  114. data/app/views/admin/tolaria_resource/_form_buttons.html.erb +10 -0
  115. data/app/views/admin/tolaria_resource/_index_table.html.erb +73 -0
  116. data/app/views/admin/tolaria_resource/_search_form.html.erb +32 -0
  117. data/app/views/admin/tolaria_resource/_show_buttons.html.erb +13 -0
  118. data/app/views/admin/tolaria_resource/edit.html.erb +34 -0
  119. data/app/views/admin/tolaria_resource/index.html.erb +36 -0
  120. data/app/views/admin/tolaria_resource/new.html.erb +1 -0
  121. data/app/views/admin/tolaria_resource/show.html.erb +52 -0
  122. data/app/views/kaminari/admin/_first_page.html.erb +9 -0
  123. data/app/views/kaminari/admin/_last_page.html.erb +9 -0
  124. data/app/views/kaminari/admin/_next_page.html.erb +9 -0
  125. data/app/views/kaminari/admin/_page.html.erb +17 -0
  126. data/app/views/kaminari/admin/_paginator.html.erb +21 -0
  127. data/app/views/kaminari/admin/_prev_page.html.erb +9 -0
  128. data/app/views/layouts/admin/admin.html.erb +21 -0
  129. data/app/views/layouts/admin/sessions.html.erb +12 -0
  130. data/app/views/passcode_mailer/passcode.text.erb +5 -0
  131. data/lib/generators/tolaria/install/install_generator.rb +21 -0
  132. data/lib/generators/tolaria/install/templates/administrators_migration.rb +31 -0
  133. data/lib/generators/tolaria/install/templates/tolaria_initializer.rb +93 -0
  134. data/lib/tasks/admin.rake +32 -0
  135. data/lib/tolaria.rb +27 -0
  136. data/lib/tolaria/active_record.rb +55 -0
  137. data/lib/tolaria/admin.rb +4 -0
  138. data/lib/tolaria/categories.rb +21 -0
  139. data/lib/tolaria/config.rb +40 -0
  140. data/lib/tolaria/default_config.rb +74 -0
  141. data/lib/tolaria/engine.rb +23 -0
  142. data/lib/tolaria/form_buildable.rb +203 -0
  143. data/lib/tolaria/help_links.rb +78 -0
  144. data/lib/tolaria/introspection.rb +13 -0
  145. data/lib/tolaria/manage.rb +57 -0
  146. data/lib/tolaria/managed_class.rb +90 -0
  147. data/lib/tolaria/markdown.rb +28 -0
  148. data/lib/tolaria/random_tokens.rb +16 -0
  149. data/lib/tolaria/reload.rb +21 -0
  150. data/lib/tolaria/routes.rb +33 -0
  151. data/lib/tolaria/version.rb +13 -0
  152. data/test/demo/Rakefile +4 -0
  153. data/test/demo/app/assets/javascripts/application.js +1 -0
  154. data/test/demo/app/assets/stylesheets/application.scss +1 -0
  155. data/test/demo/app/controllers/application_controller.rb +5 -0
  156. data/test/demo/app/controllers/concerns/.keep +0 -0
  157. data/test/demo/app/controllers/homepage_controller.rb +4 -0
  158. data/test/demo/app/helpers/application_helper.rb +2 -0
  159. data/test/demo/app/mailers/.keep +0 -0
  160. data/test/demo/app/models/.keep +0 -0
  161. data/test/demo/app/models/blog_post.rb +43 -0
  162. data/test/demo/app/models/footnote.rb +5 -0
  163. data/test/demo/app/models/image.rb +19 -0
  164. data/test/demo/app/models/legal_page.rb +24 -0
  165. data/test/demo/app/models/miscellany.rb +12 -0
  166. data/test/demo/app/models/topic.rb +22 -0
  167. data/test/demo/app/models/video.rb +16 -0
  168. data/test/demo/app/views/admin/blog_posts/_form.html.erb +48 -0
  169. data/test/demo/app/views/admin/blog_posts/_search.html.erb +5 -0
  170. data/test/demo/app/views/admin/help/markdown-help.md +95 -0
  171. data/test/demo/app/views/admin/images/_form.html.erb +26 -0
  172. data/test/demo/app/views/admin/legal_pages/_form.html.erb +15 -0
  173. data/test/demo/app/views/admin/topics/_form.html.erb +3 -0
  174. data/test/demo/app/views/admin/videos/_form.html.erb +11 -0
  175. data/test/demo/app/views/homepage/homepage.html.erb +3 -0
  176. data/test/demo/app/views/layouts/application.html.erb +14 -0
  177. data/test/demo/bin/bundle +3 -0
  178. data/test/demo/bin/rails +4 -0
  179. data/test/demo/bin/rake +4 -0
  180. data/test/demo/bin/setup +29 -0
  181. data/test/demo/config.ru +4 -0
  182. data/test/demo/config/application.rb +26 -0
  183. data/test/demo/config/boot.rb +4 -0
  184. data/test/demo/config/database.yml +18 -0
  185. data/test/demo/config/environment.rb +3 -0
  186. data/test/demo/config/environments/development.rb +43 -0
  187. data/test/demo/config/environments/test.rb +44 -0
  188. data/test/demo/config/initializers/assets.rb +11 -0
  189. data/test/demo/config/initializers/cookies_serializer.rb +2 -0
  190. data/test/demo/config/initializers/filter_parameter_logging.rb +3 -0
  191. data/test/demo/config/initializers/inflections.rb +17 -0
  192. data/test/demo/config/initializers/markdown.rb +44 -0
  193. data/test/demo/config/initializers/secret_token.rb +2 -0
  194. data/test/demo/config/initializers/session_store.rb +2 -0
  195. data/test/demo/config/initializers/tolaria.rb +17 -0
  196. data/test/demo/config/initializers/wrap_parameters.rb +14 -0
  197. data/test/demo/config/routes.rb +4 -0
  198. data/test/demo/db/migrate/20150601202901_create_administrators.rb +31 -0
  199. data/test/demo/db/migrate/20150603204006_add_testing_models.rb +27 -0
  200. data/test/demo/db/migrate/20150609232013_create_footnotes.rb +10 -0
  201. data/test/demo/db/migrate/20150610135235_create_additional_demo_objects.rb +50 -0
  202. data/test/demo/db/schema.rb +112 -0
  203. data/test/demo/log/.keep +0 -0
  204. data/test/demo/public/404.html +67 -0
  205. data/test/demo/public/422.html +67 -0
  206. data/test/demo/public/500.html +66 -0
  207. data/test/demo/public/favicon.ico +0 -0
  208. data/test/integration/help_link_test.rb +73 -0
  209. data/test/integration/interface_test.rb +63 -0
  210. data/test/integration/router_test.rb +73 -0
  211. data/test/integration/session_test.rb +88 -0
  212. data/test/test_helper.rb +58 -0
  213. data/test/unit/configuration_test.rb +21 -0
  214. data/test/unit/managed_classes_test.rb +54 -0
  215. data/test/unit/markdown_test.rb +12 -0
  216. data/test/unit/menu_test.rb +32 -0
  217. data/test/unit/random_tokens_test.rb +13 -0
  218. data/tolaria.gemspec +35 -0
  219. metadata +499 -0
@@ -0,0 +1,21 @@
1
+ class Admin::AdminController < Tolaria::TolariaController
2
+
3
+ skip_before_filter :authenticate_admin!, only:[:markdown]
4
+
5
+ def root
6
+ redirect_to(Tolaria.config.default_redirect, status:303)
7
+ end
8
+
9
+ def markdown
10
+ return render(nothing:true, status:404) unless current_administrator.present?
11
+ return render(inline:Tolaria.render_markdown(request.raw_post))
12
+ end
13
+
14
+ def help_link
15
+ @help_link = Tolaria.help_links.find do |help_link|
16
+ help_link.slug == params[:slug]
17
+ end or raise ActiveRecord::RecordNotFound
18
+ return render tolaria_template("help/help_link")
19
+ end
20
+
21
+ end
@@ -0,0 +1,112 @@
1
+ class Admin::SessionsController < Tolaria::TolariaController
2
+
3
+ skip_before_filter :authenticate_admin!
4
+
5
+ # Present the signin form
6
+
7
+ def new
8
+ if current_administrator
9
+ return redirect_to(Tolaria.config.default_redirect, status:303)
10
+ end
11
+ @greeting = random_greeting
12
+ @admin = Administrator.new
13
+ return render "admin/session/form", layout:"admin/sessions"
14
+ end
15
+
16
+ # Code request: Dispatch an email with the admin’s passcode, or return JSON errors
17
+
18
+ def request_code
19
+
20
+ email = params[:administrator].try(:[], :email).to_s.downcase.chomp
21
+ @administrator = Administrator.find_by_email(email)
22
+
23
+ unless @administrator
24
+ response.status = 404
25
+ return render json: {
26
+ status: response.status,
27
+ error: "That email address couldn’t be found. Contact an existing site administrator if you need an account created for you.",
28
+ }
29
+ end
30
+
31
+ if @administrator.locked?
32
+ response.status = 423
33
+ return render json: {
34
+ status: response.status,
35
+ error: %{
36
+ Your account has made too many requests and has been locked.
37
+ Please try again after #{Tolaria.config.lockout_duration/60} minutes.
38
+ }.squish,
39
+ }
40
+ end
41
+
42
+ if @administrator.send_passcode_email!
43
+ @administrator.accrue_strike!
44
+ response.status = 204
45
+ return render nothing: true
46
+ else
47
+ response.status = 500
48
+ return render json: {
49
+ status: response.status,
50
+ error: "An email couldn’t be sent for you. Please try again later."
51
+ }
52
+ end
53
+
54
+ end
55
+
56
+ # Create: Attempt to sign in the admin with the email/passcode combination.
57
+
58
+ def create
59
+
60
+ email = params[:administrator].try(:[], :email).to_s.downcase.chomp
61
+ passcode = params[:administrator].try(:[], :passcode).to_s
62
+
63
+ @administrator = Administrator.find_by_email(email)
64
+
65
+ if @administrator && @administrator.authenticate!(passcode)
66
+
67
+ # Auth successful
68
+ # Set an signed admin cookie with our auth_token
69
+ cookies.encrypted[:admin_auth_token] = {
70
+ value: @administrator.auth_token,
71
+ expires: params[:remember_me].eql?("1") ? 1.year.from_now : nil,
72
+ secure: Rails.env.production?, # Expect a TLS connection in production
73
+ httponly: true, # JavaScript should not read this cookie
74
+ }
75
+
76
+ # Redirect to the admin pane
77
+ return redirect_to(Tolaria.config.default_redirect, status:303)
78
+
79
+ else
80
+
81
+ # Auth failed
82
+ flash[:error] = "That passcode wasn’t correct. Please request a new passcode and try again."
83
+ return redirect_to(admin_new_session_path, status:303)
84
+
85
+ end
86
+
87
+ end
88
+
89
+ # Destroy: Sign out the admin and reset the session
90
+
91
+ def destroy
92
+ cookies.delete(:admin_auth_token)
93
+ reset_session
94
+ flash[:success] = "You have successfully signed out."
95
+ return redirect_to(admin_new_session_path, status:303)
96
+ end
97
+
98
+ protected
99
+
100
+ # Returns a random UI greeting.
101
+ def random_greeting
102
+ case [1,2,3].sample
103
+ when 1
104
+ return "Have we met before?"
105
+ when 2
106
+ return "Happy #{Date.current.strftime('%A')}!"
107
+ when 3
108
+ return "Hey there! Welcome back."
109
+ end
110
+ end
111
+
112
+ end
@@ -0,0 +1,132 @@
1
+ class Tolaria::ResourceController < Tolaria::TolariaController
2
+
3
+ before_filter :load_managed_class!
4
+ before_filter :strip_invalid_ransack_params!, only:[:index]
5
+
6
+ def index
7
+ @search = @managed_class.klass.ransack(params[:q])
8
+ @resources = @search.result
9
+ if @managed_class.paginated?
10
+ @resources = @resources.page(params[:page]).per(Tolaria.config.page_size)
11
+ end
12
+ unless currently_sorting?
13
+ @resources = @resources.order(@managed_class.default_order)
14
+ end
15
+ return render tolaria_template("tolaria_resource/index")
16
+ end
17
+
18
+ def show
19
+ @resource = @managed_class.klass.find_by_id(params[:id]) or raise ActiveRecord::RecordNotFound
20
+ return render tolaria_template("tolaria_resource/show")
21
+ end
22
+
23
+ def new
24
+ @resource = @managed_class.klass.new
25
+ return render tolaria_template("tolaria_resource/new")
26
+ end
27
+
28
+ def create
29
+
30
+ @resource = @managed_class.klass.new
31
+ @resource.assign_attributes(resource_params[@managed_class.param_key])
32
+ display_name = Tolaria.display_name(@resource)
33
+
34
+ if @resource.save
35
+ flash[:success] = "#{random_blingword} You created the #{@managed_class.model_name.human} “#{display_name}”."
36
+ return redirect_to url_for([:admin, @managed_class.klass])
37
+ else
38
+ log_validation_errors!
39
+ flash.now[:error] = "Your changes couldn’t be saved. Please correct the following errors:"
40
+ return render tolaria_template("tolaria_resource/new")
41
+ end
42
+
43
+ end
44
+
45
+ def edit
46
+ @resource = @managed_class.klass.find_by_id(params[:id]) or raise ActiveRecord::RecordNotFound
47
+ return render tolaria_template("tolaria_resource/edit")
48
+ end
49
+
50
+ def update
51
+
52
+ @resource = @managed_class.klass.find_by_id(params[:id]) or raise ActiveRecord::RecordNotFound
53
+ @resource.assign_attributes(resource_params[@managed_class.param_key])
54
+ display_name = Tolaria.display_name(@resource)
55
+
56
+ if @resource.save
57
+ flash[:success] = "#{random_blingword} You updated the #{@managed_class.model_name.human.downcase} “#{display_name}”."
58
+ return redirect_to url_for([:admin, @managed_class.klass])
59
+ else
60
+ log_validation_errors!
61
+ flash.now[:error] = "Your changes couldn’t be saved. Please correct the following errors:"
62
+ return render tolaria_template("tolaria_resource/edit")
63
+ end
64
+
65
+ end
66
+
67
+ def destroy
68
+
69
+ @resource = @managed_class.klass.find_by_id(params[:id]) or raise ActiveRecord::RecordNotFound
70
+ display_name = Tolaria.display_name(@resource)
71
+
72
+ begin
73
+ @resource.destroy
74
+ rescue ActiveRecord::DeleteRestrictionError => e
75
+ flash[:restricted] = "You cannot delete “#{display_name}” because other items are using it."
76
+ return redirect_to url_for([:admin, @managed_class.klass])
77
+ end
78
+
79
+ flash[:destructive] = "You deleted the #{@managed_class.model_name.human.downcase} “#{display_name}”."
80
+ return redirect_to url_for([:admin, @managed_class.klass])
81
+
82
+ end
83
+
84
+ protected
85
+
86
+ # Returns a random positive expression for use in
87
+ # flash messages
88
+ def random_blingword
89
+ ["Done!", "Okay!", "Success!"].sample
90
+ end
91
+
92
+ # Load the Tolaria managed class for this controller
93
+ def load_managed_class!
94
+ @managed_class ||= Tolaria.managed_classes.find do |managed_class|
95
+ self.class.to_s == "Admin::#{managed_class.controller_name}"
96
+ end
97
+ end
98
+
99
+ # Filters params, allows the default params Tolaria needs
100
+ # and the configured `permitted_params` from the managed class
101
+ def resource_params
102
+ params.permit(
103
+ *Tolaria.config.permitted_params,
104
+ @managed_class.param_key => @managed_class.permitted_params
105
+ )
106
+ end
107
+
108
+ # Some Ransack methods raise exceptions if the `q` param is invalid.
109
+ # Strip `q` params not created by Ransack
110
+ def strip_invalid_ransack_params!
111
+ return true if params[:q].blank?
112
+ unless params[:q].is_a?(Hash)
113
+ params.delete(:q)
114
+ end
115
+ end
116
+
117
+ # Returns true if there is a sorting parameter for Ransack
118
+ def currently_sorting?
119
+ params[:q].present? && params[:q][:s].present?
120
+ end
121
+
122
+ # Logs all validation errors for the current resource to the Rails console
123
+ def log_validation_errors!
124
+ unless Rails.env.test?
125
+ puts "#{@resource.class} failed validation and was not saved:"
126
+ @resource.errors.full_messages.each do |message|
127
+ puts " #{message}"
128
+ end
129
+ end
130
+ end
131
+
132
+ end
@@ -0,0 +1,40 @@
1
+ class Tolaria::TolariaController < ::ApplicationController
2
+
3
+ protect_from_forgery
4
+ before_filter :add_admin_headers!
5
+ before_filter :authenticate_admin!
6
+
7
+ protected
8
+
9
+ def add_admin_headers!
10
+ # Don't use old IE rendering modes
11
+ response.headers["X-UA-Compatible"] = "IE=edge"
12
+ # Forbid putting the admin in a frameset/iframe
13
+ response.headers["X-Frame-Options"] = "DENY"
14
+ # Strict sniffing and XSS modes for browsers that use these flags
15
+ response.headers["X-Content-Type-Options"] = "nosniff"
16
+ response.headers["X-XSS-Protection"] = "1; mode=block"
17
+ end
18
+
19
+ def tolaria_template(name)
20
+ return {
21
+ template: "admin/#{name}",
22
+ layout: "admin/admin"
23
+ }
24
+ end
25
+
26
+ def authenticate_admin!
27
+ unless current_administrator
28
+ flash[:error] = "You must log in to continue. Request a passcode below."
29
+ return redirect_to(admin_new_session_path, status:303)
30
+ end
31
+ end
32
+
33
+ def current_administrator
34
+ @current_administrator ||= Administrator.find_by_auth_token(cookies.encrypted[:admin_auth_token])
35
+ end
36
+
37
+ helper_method :current_administrator
38
+
39
+ end
40
+
@@ -0,0 +1,175 @@
1
+ module Admin::TableHelper
2
+
3
+ # Returns a `<table class="index-table">` tag with the appropriate wrapper
4
+ # and the given +content+ or block content inside it.
5
+ def index_table(content = nil, &block)
6
+ content_tag :div, class:"index-table-wrap" do
7
+ content_tag :table, class:"index-table" do
8
+ content || yield
9
+ end
10
+ end
11
+ end
12
+
13
+ # Returns a `<table class="show-table">` tag with the given +content+
14
+ # or block content inside it.
15
+ def show_table(content = nil, &block)
16
+ content_tag :table, class:"show-table" do
17
+ content || yield
18
+ end
19
+ end
20
+
21
+ # Returns the following `<tr>`, suitable for use in a `table.show-table`:
22
+ #
23
+ # <tr>
24
+ # <th>Field</th>
25
+ # <th>Details</th>
26
+ # </tr>
27
+ def show_thead_tr
28
+ %{<tr><th>Field</th><th>Details</th></tr>}.html_safe
29
+ end
30
+
31
+ # Returns a `<tr>` with two `<td>`s suitable for use in a `table.show-table`.
32
+ # The given +label+ is placed inside the first `<td>`, while the +value+
33
+ # is placed in the second `<td>`. Options are forwarded to `content_tag`
34
+ # for the *second* `<td>`.
35
+ #
36
+ # If +label+ is a symbol, it is assumed to be a method on a variable named
37
+ # `@resource` in the current template, and the `<tr>` is constructed
38
+ # automatically for you by converting the symbol to a human-readable label
39
+ # and calling the named method on @resource to get the +value+.
40
+ #
41
+ # ==== Signatures
42
+ #
43
+ # # Set the values yourself, and a class on the second `<td>`
44
+ # show_tr "Slug", resource.slug, class:"monospace"
45
+ #
46
+ # # Attempt to auto-fill the row based on a method name
47
+ # show_tr :slug
48
+ def show_tr(label, value = nil, options = nil)
49
+
50
+ if label.is_a?(Symbol)
51
+ options = value
52
+ value = @resource.send(label)
53
+ label = label.to_s.titleize
54
+ end
55
+
56
+ content = content_tag(:td, class:"show-td-field") do
57
+ content_tag :span do
58
+ label
59
+ end
60
+ end
61
+
62
+ content << content_tag(:td, options) do
63
+ value.to_s
64
+ end
65
+
66
+ content_tag(:tr) do
67
+ content
68
+ end
69
+
70
+ end
71
+
72
+ # Returns a `<th>` tag, suitable for use inside a `table.index-table`.
73
+ # +field_or_label+ may be any string, or a symbol naming a model column.
74
+ # +sort+ may be `true`, `false`, or a symbol. See the signtures below.
75
+ #
76
+ # If the column is sortable, the `<th>` will contain a Ransack sort link
77
+ # that allows the end-user to organize the table by that column.
78
+ #
79
+ # ==== Signatures
80
+ #
81
+ # # Create a header that sorts a named column
82
+ # index_th(:title, sort:true)
83
+ #
84
+ # # Create a header that sorts a column, with custom label
85
+ # index_th("Strange Title", sort: :title)
86
+ #
87
+ # # Create a header that can't be sorted
88
+ # index_th("Strange Title", sort:false)
89
+ def index_th(field_or_label, sort:true)
90
+
91
+ case field_or_label
92
+ when :id
93
+ display_label = "ID"
94
+ when Symbol
95
+ display_label = field_or_label.to_s.humanize.titleize
96
+ else
97
+ display_label = field_or_label
98
+ end
99
+
100
+ if sort.is_a?(Symbol)
101
+ return content_tag(:th, sort_link(@search, sort, display_label), class:"index-th")
102
+ end
103
+
104
+ if sort.eql?(true) && field_or_label.is_a?(Symbol)
105
+ return content_tag(:th, sort_link(@search, field_or_label, display_label), class:"index-th")
106
+ end
107
+
108
+ return content_tag(:th, display_label, class:"index-th")
109
+
110
+ end
111
+
112
+ # Returns a `<td>` tag, suitable for use inside a `table.index-table`.
113
+ # If +method_or_content+ is a symbol, it will call that method on the
114
+ # given +resource+ to obtain the content of the `<td>`. Otherwise
115
+ # it expects +method_or_content+ or a passed block to provide suitable string.
116
+ #
117
+ # #### Special Options
118
+ #
119
+ # - `:image` - A URL to a square image to use in the <td>, floating to the
120
+ # left of the content. The image should be a square at least
121
+ # 14×14px in size.
122
+ #
123
+ # Other options are forwarded to `content_tag` for the `<td>`.
124
+ def index_td(resource, method_or_content, options = {}, &block)
125
+
126
+ options = method_or_content if block_given?
127
+
128
+ if block_given?
129
+ content = yield
130
+ elsif method_or_content.is_a?(Symbol)
131
+ content = resource.send(method_or_content)
132
+ else
133
+ content = method_or_content
134
+ end
135
+
136
+ options[:class] = "index-td #{options[:class]}"
137
+
138
+ if image = options.delete(:image)
139
+ image = image_tag(image, size:"18x18", alt:"")
140
+ end
141
+
142
+ return content_tag(:td, options) do
143
+ link_to("#{image}#{content}".html_safe, url_for(action:"edit", id:resource.id))
144
+ end
145
+
146
+ end
147
+
148
+ # Returns an `index_th` with label `"Actions"` that is not sortable.
149
+ def actions_th
150
+ index_th("Actions", sort:false)
151
+ end
152
+
153
+ # Returns a `<td>` tag, suitable for use inside a `table.index-table`.
154
+ # The tag contains buttons to edit, inspect, and delete the given +resource+.
155
+ def actions_td(resource)
156
+
157
+ links = []
158
+
159
+ if @managed_class.allows?(:edit)
160
+ links << link_to("Edit", url_for(action:"edit", id:resource.id), class:"button -small")
161
+ end
162
+
163
+ if @managed_class.allows?(:show)
164
+ links << link_to("Inspect", url_for(action:"show", id:resource.id), class:"button -small")
165
+ end
166
+
167
+ if @managed_class.allows?(:destroy)
168
+ links << link_to("Delete", url_for(action:"destroy", id:resource.id), class: "button -small", method: :delete, :'data-confirm' => deletion_warning(resource))
169
+ end
170
+
171
+ return content_tag(:td, links.join("").html_safe, class:"actions-td")
172
+
173
+ end
174
+
175
+ end