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,76 @@
1
+ module Admin::ViewHelper
2
+
3
+ ADMIN_PILL_COLORS = HashWithIndifferentAccess.new({
4
+ green: "3BAB46",
5
+ red: "DA3946",
6
+ blue: "3497BE",
7
+ black: "343242",
8
+ grey: "777777",
9
+ })
10
+
11
+ # Returns a navigation menu link with the given label,
12
+ # Font Awesome icon name, and URI
13
+ def tolaria_navigation_link(label, icon, index_path, options = {})
14
+ options[:class] = "#{options[:class]} current" if index_path.in?(url_for)
15
+ link_to index_path, options do
16
+ fontawesome_icon(icon) << " #{label}"
17
+ end
18
+ end
19
+
20
+ # Returns an `<i>` tag that displays a Font Awesome icon
21
+ def fontawesome_icon(icon = "", options = {})
22
+ icon = icon.to_s.parameterize.tr("_", "-")
23
+ content_tag :i, nil, options.reverse_merge({
24
+ :class => "icon icon-#{icon}",
25
+ :"aria-hidden" => true,
26
+ })
27
+ end
28
+
29
+ # Returns a URI to a Gravatar for the given email
30
+ def gravatar_for(email)
31
+ digest = Digest::MD5.hexdigest(email)
32
+ return "https://secure.gravatar.com/avatar/#{digest}?d=retro&s=36"
33
+ end
34
+
35
+ # Returns true if a partial is available at "admin/#{template_path}"
36
+ def admin_template_exists?(template_path)
37
+ lookup_context.template_exists?("admin/#{template_path}", [], true)
38
+ end
39
+
40
+ # True if Ransack filtering parameters are present
41
+ def currently_filtering?
42
+ params[:q].present? && params[:q].is_a?(Hash) && params[:q].keys.reject{|key| key == "s"}.any?
43
+ end
44
+
45
+ # Attempt to automatically construct a default text search
46
+ # field name for Ransack from a given model's table settings
47
+ def ransack_text_search_chain(model)
48
+ textual_columns = model.columns_hash.select do |column, settings|
49
+ settings.sql_type.include?("char") || settings.sql_type.include?("text")
50
+ end
51
+ textual_columns = {id:"id"} if textual_columns.none?
52
+ return %{#{textual_columns.keys.join("_or_")}_cont}.to_sym
53
+ end
54
+
55
+ # Returns a deletion warning message for the given ActiveRecord instance
56
+ def deletion_warning(resource)
57
+ return %{Are you sure you want to delete the #{resource.model_name.human.downcase} “#{Tolaria.display_name(resource)}”? This action is not reversible.}
58
+ end
59
+
60
+ # Returns a `<span>` tag that displays the given +label+ as a pill
61
+ # status badge. You can change the color of the pill by providing a
62
+ # six-digit hexadecimal +color+, or passing one of the predefined
63
+ # color names: `:green`, `:red`, `:blue`, `:black`, `:grey`.
64
+ def pill(label, color: :black)
65
+
66
+ if ADMIN_PILL_COLORS[color].present?
67
+ color = ADMIN_PILL_COLORS[color]
68
+ else
69
+ color = color.to_s.delete("#")
70
+ end
71
+
72
+ content_tag :span, label.to_s, class:"pill", style:"background-color:##{color}"
73
+
74
+ end
75
+
76
+ end
@@ -0,0 +1,11 @@
1
+ class PasscodeMailer < ActionMailer::Base
2
+
3
+ default from:Tolaria.config.from_address
4
+
5
+ def passcode(administrator, passcode)
6
+ @administrator = administrator
7
+ @passcode = passcode
8
+ mail(to:administrator.email, subject:"#{Tolaria.config.company_name} Passcode")
9
+ end
10
+
11
+ end
@@ -0,0 +1,146 @@
1
+ class Administrator < ActiveRecord::Base
2
+
3
+ after_initialize :initialize_authentication!
4
+ before_validation :normalize_email!
5
+
6
+ # -----------------------------------------------------------------------------
7
+ # VALIDATIONS
8
+ # Use some extra validation redundancy
9
+ # -----------------------------------------------------------------------------
10
+
11
+ validates :email, {
12
+ uniqueness: true,
13
+ # Don't try to predict all of the possible crazy emails people can have
14
+ # Just validate that there is one @ and at least one dot: *@*.*
15
+ format: /\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/
16
+ }
17
+
18
+ # Require all user-visible fields
19
+ validates_presence_of :name
20
+ validates_presence_of :organization
21
+
22
+ # Parts of the admin system should not be empty
23
+ validates_presence_of :auth_token
24
+ validates_presence_of :passcode
25
+ validates_presence_of :passcode_expires_at
26
+ validates_presence_of :account_unlocks_at
27
+
28
+ # Downcase and strip whitespace from the current email
29
+ def normalize_email!
30
+ self.email = self.email.to_s.downcase.squish
31
+ end
32
+
33
+ # -----------------------------------------------------------------------------
34
+ # AUTHENTICATION SYSTEM
35
+ # The admin must request a passcode challenge via email
36
+ # To pass the challenge, the admin must enter the correct email address
37
+ # and passcode inside the time window
38
+ # -----------------------------------------------------------------------------
39
+
40
+ # Initialize +passcode+, +passcode_expires_at+,
41
+ # +auth_token+, and +account_unlocks_at+ for a new admin.
42
+ # To prevent passcode system fields from being null,
43
+ # we fill them with an immediately expired passcode.
44
+ def initialize_authentication!
45
+ self.passcode ||= BCrypt::Password.create(Tolaria::RandomTokens.passcode, cost:Tolaria.config.bcrypt_cost)
46
+ self.passcode_expires_at ||= Time.current
47
+ self.auth_token ||= Tolaria::RandomTokens.auth_token
48
+ self.account_unlocks_at ||= Time.current
49
+ end
50
+
51
+ # Send a passcode challenge email to the admin
52
+ def send_passcode_email!
53
+ plaintext_passcode = self.set_passcode!
54
+ PasscodeMailer.passcode(self, plaintext_passcode).deliver_now
55
+ end
56
+
57
+ # Generate a new passcode challenge.
58
+ # Create a passcode, save it, and set an expiration window.
59
+ # Returns the plaintext passcode to send to the user.
60
+ def set_passcode!
61
+ plaintext_passcode = Tolaria::RandomTokens.passcode
62
+ self.update!(
63
+ passcode: BCrypt::Password.create(plaintext_passcode, cost:Tolaria.config.bcrypt_cost),
64
+ passcode_expires_at: Time.current + Tolaria.config.passcode_lifespan,
65
+ )
66
+ return plaintext_passcode
67
+ end
68
+
69
+ # Attempt to authenticate the account with the given plaintext +passcode+.
70
+ # Returns true if the passcode was valid, false otherwise.
71
+ def authenticate!(passcode)
72
+
73
+ # Always run bcrypt first so that we incur the time penalty
74
+ bcrypt_valid = BCrypt::Password.new(self.passcode) == passcode
75
+
76
+ # Reject if currently locked
77
+ return false if self.locked?
78
+
79
+ # Clear strikes and consume the passcode if the passcode was valid.
80
+ # Reject and incur a strike if the challenge was failed.
81
+ if bcrypt_valid && Time.current < self.passcode_expires_at
82
+ self.consume_passcode!
83
+ return true
84
+ else
85
+ self.accrue_strike!
86
+ return false
87
+ end
88
+
89
+ end
90
+
91
+ # Immediately expire the current passcode and reset lockout strikes.
92
+ def consume_passcode!
93
+ self.update!(
94
+ passcode_expires_at: Time.current,
95
+ lockout_strikes: 0,
96
+ )
97
+ end
98
+
99
+ # Add one strike to the account.
100
+ # An admin is given a strike for requesting a code or flunking a challenge.
101
+ # Will lock the account if they’ve hit the threshold.
102
+ def accrue_strike!
103
+ self.update!(
104
+ lockout_strikes: self.lockout_strikes + 1,
105
+ total_strikes: self.total_strikes + 1,
106
+ )
107
+ if self.lockout_strikes >= Tolaria.config.lockout_threshold
108
+ self.lock_account!
109
+ end
110
+ end
111
+
112
+ # Lock this account immediately and reset lockout strikes.
113
+ def lock_account!
114
+ self.update!(
115
+ account_unlocks_at: Time.current + Tolaria.config.lockout_duration,
116
+ lockout_strikes: 0,
117
+ )
118
+ end
119
+
120
+ # Unlock the user’s account. Currently only usable by someone
121
+ # with Rails console access.
122
+ def unlock_account!
123
+ self.update!(
124
+ account_unlocks_at: Time.current,
125
+ lockout_strikes: 0,
126
+ )
127
+ end
128
+
129
+ # True if the account is currently inside a lockout window
130
+ def locked?
131
+ return Time.current < self.account_unlocks_at
132
+ end
133
+
134
+ # -----------------------------------------------------------------------------
135
+ # MANAGE
136
+ # Register this model with Tolaria
137
+ # -----------------------------------------------------------------------------
138
+
139
+ manage_with_tolaria using: {
140
+ icon: "shield",
141
+ category: "Settings",
142
+ priority: 100,
143
+ permit_params: %i[email name organization],
144
+ }
145
+
146
+ end
@@ -0,0 +1,16 @@
1
+ <%= f.label :email %>
2
+ <%= f.text_field :email, placeholder:"lovelace@example.org" %>
3
+ <%= f.hint %{
4
+ The email address this administrator will use to sign in.
5
+ Administrators have the power to change site content, and can create other administrators.
6
+ Only people who work directly on web content should be given accounts.
7
+ } %>
8
+
9
+ <%= f.label :name %>
10
+ <%= f.text_field :name, placeholder:"Ada Lovelace" %>
11
+ <%= f.hint "The full name of this person." %>
12
+
13
+ <%= f.label :organization %>
14
+ <%= f.text_field :organization, placeholder:"Analytical Engineering" %>
15
+ <%= f.hint "This person's organization or department." %>
16
+
@@ -0,0 +1,20 @@
1
+ <table class="index-table">
2
+ <thead>
3
+ <tr>
4
+ <%= index_th :id %>
5
+ <%= index_th :name %>
6
+ <%= index_th :organization %>
7
+ <%= actions_th %>
8
+ </tr>
9
+ </thead>
10
+ <tbody>
11
+ <% @resources.each do |resource| %>
12
+ <tr>
13
+ <%= index_td resource, :id %>
14
+ <%= index_td resource, :name, image:gravatar_for(resource.email) %>
15
+ <%= index_td resource, :organization %>
16
+ <%= actions_td resource %>
17
+ </tr>
18
+ <% end %>
19
+ </tbody>
20
+ </table>
@@ -0,0 +1,5 @@
1
+ <%= f.label :email_cont, "Email contains" %>
2
+ <%= f.search_field :email_cont, placeholder:"Contains anything" %>
3
+
4
+ <%= f.label ransack_text_search_chain(@managed_class.klass), "Containing the text" %>
5
+ <%= f.search_field ransack_text_search_chain(@managed_class.klass), placeholder:"Anything" %>
@@ -0,0 +1,14 @@
1
+ <%= show_table do %>
2
+
3
+ <thead>
4
+ <%= show_thead_tr %>
5
+ </thead>
6
+ <tbody>
7
+ <%= show_tr "Avatar", image_tag(gravatar_for(@resource.email)) %>
8
+ <%= show_tr :name %>
9
+ <%= show_tr :organization %>
10
+ <%= show_tr :email, class:"monospace" %>
11
+ <%= show_tr "Created At", @resource.created_at.presence.try(:strftime, "%Y-%m-%d %I:%M %p"), class:"monospace" %>
12
+ </tbody>
13
+
14
+ <% end %>
@@ -0,0 +1,16 @@
1
+ <%= content_for :title, @help_link.title %>
2
+
3
+ <div class="main-controls">
4
+
5
+ <div class="main-controls-left">
6
+ <h1>
7
+ <%= fontawesome_icon :info_circle %>
8
+ <%= content_for :title %>
9
+ </h1>
10
+ </div>
11
+
12
+ </div>
13
+
14
+ <div class="help-link-body markdown-body">
15
+ <%= Tolaria.render_markdown(File.read(@help_link.markdown_file)) %>
16
+ </div>
@@ -0,0 +1,52 @@
1
+ <%= form_for @admin, url:admin_signin_path, html:{id:"session-form", class:"session-form"} do |f| %>
2
+
3
+ <h1><%= @greeting %></h1>
4
+
5
+ <div class="session-spinner" id="session-spinner" style="display:none"></div>
6
+
7
+ <% if flash[:error] || flash[:success] %>
8
+ <p class="session-form-feedback" id="session-form-feedback">
9
+ <%= flash[:error] %> <%= flash[:success] %>
10
+ </p>
11
+ <% else %>
12
+ <p class="session-form-feedback" id="session-form-feedback" style="display:none"></p>
13
+ <% end %>
14
+
15
+ <%= f.label :email, "Email address", for:"session-form-email", class:"visuallyhidden" %>
16
+ <%= f.email_field :email, {
17
+ id: "session-form-email",
18
+ placeholder: "Enter your email address",
19
+ autocorrect: "off",
20
+ autocapitalize: "none",
21
+ tabindex: 1,
22
+ value: @email,
23
+ } %>
24
+
25
+ <%= f.label :passcode, "Passcode", for:"session-form-passcode", class:"visuallyhidden" %>
26
+ <%= f.text_field :passcode, {
27
+ id: "session-form-passcode",
28
+ placeholder: "Passcode",
29
+ autocorrect: "off",
30
+ autocomplete: "off",
31
+ spellcheck: "false",
32
+ pattern: "[0-9]*",
33
+ tabindex: 2,
34
+ style: "display:none"
35
+ } %>
36
+
37
+ <%= f.button "Request a passcode", type:"submit", id:"session-form-submit", class:"session-button" %>
38
+
39
+ <div id="session-form-remember-group" class="session-form-checkbox-group" style="display:none">
40
+ <%= hidden_field_tag :remember_me, 1 %>
41
+ <%= check_box_tag :remember_me, 1, true, {
42
+ class: "session-form-remember",
43
+ id: "session-form-remember"
44
+ } %>
45
+ <%= label_tag "session-form-remember", "Remember this device" %>
46
+ </div>
47
+
48
+ <p class="session-form-resend" id="session-form-resend" style="display:none">
49
+ <button type="button">Request another code</button>
50
+ </p>
51
+
52
+ <% end %>
@@ -0,0 +1,42 @@
1
+ <% if flash[:success].present? %>
2
+
3
+ <div class="flash-message">
4
+ <div class="inner-align">
5
+ <button class="dismiss">Dismiss</button>
6
+ <p><%= fontawesome_icon :check %> <%= flash[:success] %></p>
7
+ </div>
8
+ </div>
9
+
10
+ <% elsif flash[:error].present? %>
11
+
12
+ <div class="flash-message -error">
13
+ <div class="inner-align">
14
+ <button class="dismiss">Dismiss</button>
15
+ <p>
16
+ <%= fontawesome_icon :exclamation_triangle %> <%= flash[:error] %>
17
+ <% if defined?(@resource) && @resource.respond_to?(:errors) && @resource.errors.any? %>
18
+ <%= @resource.errors.full_messages.to_sentence.capitalize %>.
19
+ <% end %>
20
+ </p>
21
+ </div>
22
+ </div>
23
+
24
+ <% elsif flash[:destructive].present? %>
25
+
26
+ <div class="flash-message">
27
+ <div class="inner-align">
28
+ <button class="dismiss">Dismiss</button>
29
+ <p><%= fontawesome_icon :trash %> <%= flash[:destructive] %></p>
30
+ </div>
31
+ </div>
32
+
33
+ <% elsif flash[:restricted].present? %>
34
+
35
+ <div class="flash-message -error">
36
+ <div class="inner-align">
37
+ <button class="dismiss">Dismiss</button>
38
+ <p><%= fontawesome_icon :minus_circle %> <%= flash[:restricted] %></p>
39
+ </div>
40
+ </div>
41
+
42
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <div class="footer">
2
+ <div class="inner-align">
3
+ <p>
4
+ <%= "© #{Time.current.year} #{Tolaria.config.company_name}." %>
5
+ Information may be proprietary or confidential.
6
+ </p>
7
+ </div>
8
+ </div>
@@ -0,0 +1,11 @@
1
+ <head>
2
+ <meta charset="utf-8">
3
+ <title><%= "#{content_for(:title)} • " if content_for(:title) %><%= Tolaria.config.company_name %></title>
4
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
+ <meta name="robots" content="noindex">
6
+ <meta name="google" content="notranslate">
7
+ <%= favicon_link_tag "admin/favicon.ico" %>
8
+ <%= csrf_meta_tags %>
9
+ <%= stylesheet_link_tag "admin/admin", media:"all" %>
10
+ <%= javascript_include_tag "admin/lib/no" %>
11
+ </head>
@@ -0,0 +1,43 @@
1
+ <div class="header-stripe"></div>
2
+
3
+ <div class="header">
4
+ <div class="inner-align">
5
+
6
+ <%= link_to Tolaria.config.default_redirect, class:"header-menu-trigger mobile-only" do %>
7
+ <span><%= fontawesome_icon :bars %> <%= Tolaria.config.company_name %></span>
8
+ <% end %>
9
+
10
+ <%= link_to Tolaria.config.default_redirect, class:"header-app-title" do %>
11
+ <%= Tolaria.config.company_name %>
12
+ <% end %>
13
+
14
+ <ul class="header-user-controls">
15
+
16
+ <% Tolaria.help_links.each do |help_link| %>
17
+ <% if help_link.markdown_type? %>
18
+ <li><%= link_to help_link.title, admin_help_link_path(help_link), class:"header-help-link", target:"_blank" %></li>
19
+ <% else %>
20
+ <li><%= link_to help_link.title, help_link.link_to, class:"header-help-link", target:"_blank" %></li>
21
+ <% end %>
22
+ <% end %>
23
+
24
+ <li>
25
+ <%= link_to edit_admin_administrator_path(current_administrator), class:"header-user-profile desktop-only" do %>
26
+ <%= image_tag gravatar_for(current_administrator.email), alt:"", size:"18x18" %>
27
+ <%= current_administrator.name %>
28
+ <% end %>
29
+ </li>
30
+
31
+ <li>
32
+ <%= form_tag admin_destroy_session_path, method:"delete" do %>
33
+ <%= button_tag class:"header-user-signout" do %>
34
+ <%= fontawesome_icon :sign_out %>
35
+ Sign Out
36
+ <% end %>
37
+ <% end %>
38
+ </li>
39
+
40
+ </ul>
41
+
42
+ </div>
43
+ </div>