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.
- checksums.yaml +7 -0
- data/.gitignore +66 -0
- data/.yardopts +4 -0
- data/CNAME +1 -0
- data/CONTRIBUTING.md +32 -0
- data/Gemfile +2 -0
- data/LICENSE.md +9 -0
- data/README.md +538 -0
- data/Rakefile +52 -0
- data/app/assets/fonts/admin/fontawesome.eot +0 -0
- data/app/assets/fonts/admin/fontawesome.svg +565 -0
- data/app/assets/fonts/admin/fontawesome.ttf +0 -0
- data/app/assets/fonts/admin/fontawesome.woff +0 -0
- data/app/assets/fonts/admin/fontawesome.woff2 +0 -0
- data/app/assets/images/admin/columbia_banner.png +0 -0
- data/app/assets/images/admin/favicon.ico +0 -0
- data/app/assets/images/admin/noise.png +0 -0
- data/app/assets/images/admin/select_arrows.svg +1 -0
- data/app/assets/javascripts/admin/admin.js +4 -0
- data/app/assets/javascripts/admin/base.js +12 -0
- data/app/assets/javascripts/admin/lib/backbone.js +1888 -0
- data/app/assets/javascripts/admin/lib/jquery.chosen.js +1272 -0
- data/app/assets/javascripts/admin/lib/jquery.js +10361 -0
- data/app/assets/javascripts/admin/lib/jquery.selection.js +352 -0
- data/app/assets/javascripts/admin/lib/moment.js +3103 -0
- data/app/assets/javascripts/admin/lib/no.js +6 -0
- data/app/assets/javascripts/admin/lib/underscore.js +1570 -0
- data/app/assets/javascripts/admin/models/composer_buttons.js +45 -0
- data/app/assets/javascripts/admin/models/rails_meta.js +4 -0
- data/app/assets/javascripts/admin/views/field_with_errors.js +19 -0
- data/app/assets/javascripts/admin/views/fields/attachment_field.js +32 -0
- data/app/assets/javascripts/admin/views/fields/has_many.js +64 -0
- data/app/assets/javascripts/admin/views/fields/image_association_select.js +31 -0
- data/app/assets/javascripts/admin/views/fields/markdown_composer.js +167 -0
- data/app/assets/javascripts/admin/views/fields/searchable_select.js +70 -0
- data/app/assets/javascripts/admin/views/fields/slug_field.js +38 -0
- data/app/assets/javascripts/admin/views/fields/swatch_field.js +55 -0
- data/app/assets/javascripts/admin/views/fields/timestamp_field.js +80 -0
- data/app/assets/javascripts/admin/views/flash_message.js +18 -0
- data/app/assets/javascripts/admin/views/form_orchestrator.js +41 -0
- data/app/assets/javascripts/admin/views/navigation.js +20 -0
- data/app/assets/javascripts/admin/views/resource_form.js +18 -0
- data/app/assets/javascripts/admin/views/search_form.js +20 -0
- data/app/assets/javascripts/admin/views/sessions.js +109 -0
- data/app/assets/javascripts/admin/views/virtual_form.js +47 -0
- data/app/assets/stylesheets/admin/_base.scss +5 -0
- data/app/assets/stylesheets/admin/_reset.scss +149 -0
- data/app/assets/stylesheets/admin/_root.scss +63 -0
- data/app/assets/stylesheets/admin/admin.scss +4 -0
- data/app/assets/stylesheets/admin/components/_blank_slate.scss +44 -0
- data/app/assets/stylesheets/admin/components/_buttons.scss +82 -0
- data/app/assets/stylesheets/admin/components/_flash_message.scss +64 -0
- data/app/assets/stylesheets/admin/components/_footer.scss +9 -0
- data/app/assets/stylesheets/admin/components/_header.scss +107 -0
- data/app/assets/stylesheets/admin/components/_index_table.scss +120 -0
- data/app/assets/stylesheets/admin/components/_main.scss +68 -0
- data/app/assets/stylesheets/admin/components/_markdown_body.scss +109 -0
- data/app/assets/stylesheets/admin/components/_navigation.scss +110 -0
- data/app/assets/stylesheets/admin/components/_pagination.scss +36 -0
- data/app/assets/stylesheets/admin/components/_pill.scss +11 -0
- data/app/assets/stylesheets/admin/components/_resource_form.scss +222 -0
- data/app/assets/stylesheets/admin/components/_search_form.scss +36 -0
- data/app/assets/stylesheets/admin/components/_sessions.scss +152 -0
- data/app/assets/stylesheets/admin/components/_show_table.scss +67 -0
- data/app/assets/stylesheets/admin/components/forms/_attachment_field.scss +59 -0
- data/app/assets/stylesheets/admin/components/forms/_chosen.scss +478 -0
- data/app/assets/stylesheets/admin/components/forms/_image_association_select.scss +20 -0
- data/app/assets/stylesheets/admin/components/forms/_markdown_composer.scss +149 -0
- data/app/assets/stylesheets/admin/components/forms/_nested_fields.scss +63 -0
- data/app/assets/stylesheets/admin/components/forms/_searchable_select.scss +8 -0
- data/app/assets/stylesheets/admin/components/forms/_slug_field.scss +20 -0
- data/app/assets/stylesheets/admin/components/forms/_swatch_field.scss +47 -0
- data/app/assets/stylesheets/admin/components/forms/_timestamp_field.scss +15 -0
- data/app/assets/stylesheets/admin/components/help_link.scss +6 -0
- data/app/assets/stylesheets/admin/mixins/_clearfix.scss +18 -0
- data/app/assets/stylesheets/admin/mixins/_min_max_width.scss +11 -0
- data/app/assets/stylesheets/admin/mixins/_rgbb.scss +7 -0
- data/app/assets/stylesheets/admin/mixins/_visuallyhidden.scss +33 -0
- data/app/assets/stylesheets/admin/settings/_animations.scss +21 -0
- data/app/assets/stylesheets/admin/settings/_breakpoints.scss +2 -0
- data/app/assets/stylesheets/admin/settings/_colors.scss +32 -0
- data/app/assets/stylesheets/admin/settings/_fonts.scss +31 -0
- data/app/assets/stylesheets/admin/settings/_icons.scss +1658 -0
- data/app/controllers/admin/admin_controller.rb +21 -0
- data/app/controllers/admin/sessions_controller.rb +112 -0
- data/app/controllers/tolaria/resource_controller.rb +132 -0
- data/app/controllers/tolaria/tolaria_controller.rb +40 -0
- data/app/helpers/admin/table_helper.rb +175 -0
- data/app/helpers/admin/view_helper.rb +76 -0
- data/app/mailers/passcode_mailer.rb +11 -0
- data/app/models/administrator.rb +146 -0
- data/app/views/admin/administrators/_form.html.erb +16 -0
- data/app/views/admin/administrators/_index.html.erb +20 -0
- data/app/views/admin/administrators/_search.html.erb +5 -0
- data/app/views/admin/administrators/_show.html.erb +14 -0
- data/app/views/admin/help/help_link.html.erb +16 -0
- data/app/views/admin/session/form.html.erb +52 -0
- data/app/views/admin/shared/_flash_messages.html.erb +42 -0
- data/app/views/admin/shared/_footer.html.erb +8 -0
- data/app/views/admin/shared/_head.html.erb +11 -0
- data/app/views/admin/shared/_header.html.erb +43 -0
- data/app/views/admin/shared/_navigation.html.erb +47 -0
- data/app/views/admin/shared/_skiplinks.html.erb +0 -0
- data/app/views/admin/shared/forms/_attachment_field.html.erb +17 -0
- data/app/views/admin/shared/forms/_has_many.html.erb +14 -0
- data/app/views/admin/shared/forms/_has_many_header.html.erb +19 -0
- data/app/views/admin/shared/forms/_image_association_select.html.erb +6 -0
- data/app/views/admin/shared/forms/_image_field.html.erb +19 -0
- data/app/views/admin/shared/forms/_markdown_composer.html.erb +29 -0
- data/app/views/admin/shared/forms/_searchable_select.html.erb +3 -0
- data/app/views/admin/shared/forms/_slug_field.html.erb +9 -0
- data/app/views/admin/shared/forms/_swatch_field.html.erb +4 -0
- data/app/views/admin/shared/forms/_timestamp_field.html.erb +19 -0
- data/app/views/admin/tolaria_resource/_form_buttons.html.erb +10 -0
- data/app/views/admin/tolaria_resource/_index_table.html.erb +73 -0
- data/app/views/admin/tolaria_resource/_search_form.html.erb +32 -0
- data/app/views/admin/tolaria_resource/_show_buttons.html.erb +13 -0
- data/app/views/admin/tolaria_resource/edit.html.erb +34 -0
- data/app/views/admin/tolaria_resource/index.html.erb +36 -0
- data/app/views/admin/tolaria_resource/new.html.erb +1 -0
- data/app/views/admin/tolaria_resource/show.html.erb +52 -0
- data/app/views/kaminari/admin/_first_page.html.erb +9 -0
- data/app/views/kaminari/admin/_last_page.html.erb +9 -0
- data/app/views/kaminari/admin/_next_page.html.erb +9 -0
- data/app/views/kaminari/admin/_page.html.erb +17 -0
- data/app/views/kaminari/admin/_paginator.html.erb +21 -0
- data/app/views/kaminari/admin/_prev_page.html.erb +9 -0
- data/app/views/layouts/admin/admin.html.erb +21 -0
- data/app/views/layouts/admin/sessions.html.erb +12 -0
- data/app/views/passcode_mailer/passcode.text.erb +5 -0
- data/lib/generators/tolaria/install/install_generator.rb +21 -0
- data/lib/generators/tolaria/install/templates/administrators_migration.rb +31 -0
- data/lib/generators/tolaria/install/templates/tolaria_initializer.rb +93 -0
- data/lib/tasks/admin.rake +32 -0
- data/lib/tolaria.rb +27 -0
- data/lib/tolaria/active_record.rb +55 -0
- data/lib/tolaria/admin.rb +4 -0
- data/lib/tolaria/categories.rb +21 -0
- data/lib/tolaria/config.rb +40 -0
- data/lib/tolaria/default_config.rb +74 -0
- data/lib/tolaria/engine.rb +23 -0
- data/lib/tolaria/form_buildable.rb +203 -0
- data/lib/tolaria/help_links.rb +78 -0
- data/lib/tolaria/introspection.rb +13 -0
- data/lib/tolaria/manage.rb +57 -0
- data/lib/tolaria/managed_class.rb +90 -0
- data/lib/tolaria/markdown.rb +28 -0
- data/lib/tolaria/random_tokens.rb +16 -0
- data/lib/tolaria/reload.rb +21 -0
- data/lib/tolaria/routes.rb +33 -0
- data/lib/tolaria/version.rb +13 -0
- data/test/demo/Rakefile +4 -0
- data/test/demo/app/assets/javascripts/application.js +1 -0
- data/test/demo/app/assets/stylesheets/application.scss +1 -0
- data/test/demo/app/controllers/application_controller.rb +5 -0
- data/test/demo/app/controllers/concerns/.keep +0 -0
- data/test/demo/app/controllers/homepage_controller.rb +4 -0
- data/test/demo/app/helpers/application_helper.rb +2 -0
- data/test/demo/app/mailers/.keep +0 -0
- data/test/demo/app/models/.keep +0 -0
- data/test/demo/app/models/blog_post.rb +43 -0
- data/test/demo/app/models/footnote.rb +5 -0
- data/test/demo/app/models/image.rb +19 -0
- data/test/demo/app/models/legal_page.rb +24 -0
- data/test/demo/app/models/miscellany.rb +12 -0
- data/test/demo/app/models/topic.rb +22 -0
- data/test/demo/app/models/video.rb +16 -0
- data/test/demo/app/views/admin/blog_posts/_form.html.erb +48 -0
- data/test/demo/app/views/admin/blog_posts/_search.html.erb +5 -0
- data/test/demo/app/views/admin/help/markdown-help.md +95 -0
- data/test/demo/app/views/admin/images/_form.html.erb +26 -0
- data/test/demo/app/views/admin/legal_pages/_form.html.erb +15 -0
- data/test/demo/app/views/admin/topics/_form.html.erb +3 -0
- data/test/demo/app/views/admin/videos/_form.html.erb +11 -0
- data/test/demo/app/views/homepage/homepage.html.erb +3 -0
- data/test/demo/app/views/layouts/application.html.erb +14 -0
- data/test/demo/bin/bundle +3 -0
- data/test/demo/bin/rails +4 -0
- data/test/demo/bin/rake +4 -0
- data/test/demo/bin/setup +29 -0
- data/test/demo/config.ru +4 -0
- data/test/demo/config/application.rb +26 -0
- data/test/demo/config/boot.rb +4 -0
- data/test/demo/config/database.yml +18 -0
- data/test/demo/config/environment.rb +3 -0
- data/test/demo/config/environments/development.rb +43 -0
- data/test/demo/config/environments/test.rb +44 -0
- data/test/demo/config/initializers/assets.rb +11 -0
- data/test/demo/config/initializers/cookies_serializer.rb +2 -0
- data/test/demo/config/initializers/filter_parameter_logging.rb +3 -0
- data/test/demo/config/initializers/inflections.rb +17 -0
- data/test/demo/config/initializers/markdown.rb +44 -0
- data/test/demo/config/initializers/secret_token.rb +2 -0
- data/test/demo/config/initializers/session_store.rb +2 -0
- data/test/demo/config/initializers/tolaria.rb +17 -0
- data/test/demo/config/initializers/wrap_parameters.rb +14 -0
- data/test/demo/config/routes.rb +4 -0
- data/test/demo/db/migrate/20150601202901_create_administrators.rb +31 -0
- data/test/demo/db/migrate/20150603204006_add_testing_models.rb +27 -0
- data/test/demo/db/migrate/20150609232013_create_footnotes.rb +10 -0
- data/test/demo/db/migrate/20150610135235_create_additional_demo_objects.rb +50 -0
- data/test/demo/db/schema.rb +112 -0
- data/test/demo/log/.keep +0 -0
- data/test/demo/public/404.html +67 -0
- data/test/demo/public/422.html +67 -0
- data/test/demo/public/500.html +66 -0
- data/test/demo/public/favicon.ico +0 -0
- data/test/integration/help_link_test.rb +73 -0
- data/test/integration/interface_test.rb +63 -0
- data/test/integration/router_test.rb +73 -0
- data/test/integration/session_test.rb +88 -0
- data/test/test_helper.rb +58 -0
- data/test/unit/configuration_test.rb +21 -0
- data/test/unit/managed_classes_test.rb +54 -0
- data/test/unit/markdown_test.rb +12 -0
- data/test/unit/menu_test.rb +32 -0
- data/test/unit/random_tokens_test.rb +13 -0
- data/tolaria.gemspec +35 -0
- 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
|