tolaria 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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