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,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>