godmin 1.3.0 → 2.1.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 (84) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +0 -2
  3. data/.gitignore +1 -0
  4. data/.travis.yml +7 -15
  5. data/Appraisals +4 -4
  6. data/CHANGELOG.md +83 -2
  7. data/Gemfile +1 -2
  8. data/README.md +74 -9
  9. data/Rakefile +2 -10
  10. data/app/views/godmin/resource/_breadcrumb.html.erb +12 -24
  11. data/app/views/godmin/resource/_breadcrumb_actions.html.erb +41 -0
  12. data/app/views/godmin/resource/_button_actions.html.erb +1 -1
  13. data/app/views/godmin/resource/_table.html.erb +3 -0
  14. data/app/views/godmin/resource/columns/_actions.html.erb +4 -4
  15. data/app/views/godmin/resource/show.html.erb +1 -1
  16. data/config/locales/en.yml +2 -0
  17. data/config/locales/pt-BR.yml +2 -0
  18. data/config/locales/sv.yml +2 -0
  19. data/gemfiles/rails_5.gemfile +3 -4
  20. data/gemfiles/rails_6.gemfile +8 -0
  21. data/godmin.gemspec +18 -16
  22. data/lib/generators/godmin/resource/resource_generator.rb +7 -1
  23. data/lib/generators/godmin/resource/templates/resource_model.rb +4 -0
  24. data/lib/godmin/application_controller.rb +10 -11
  25. data/lib/godmin/authentication.rb +11 -11
  26. data/lib/godmin/authentication/sessions_controller.rb +2 -1
  27. data/lib/godmin/authorization.rb +6 -20
  28. data/lib/godmin/engine_wrapper.rb +10 -1
  29. data/lib/godmin/generators/base.rb +4 -4
  30. data/lib/godmin/generators/named_base.rb +4 -4
  31. data/lib/godmin/helpers/application.rb +3 -3
  32. data/lib/godmin/helpers/batch_actions.rb +1 -1
  33. data/lib/godmin/helpers/forms.rb +5 -1
  34. data/lib/godmin/paginator.rb +12 -4
  35. data/lib/godmin/resolver.rb +23 -5
  36. data/lib/godmin/resources/resource_controller.rb +24 -5
  37. data/lib/godmin/resources/resource_controller/batch_actions.rb +1 -1
  38. data/lib/godmin/resources/resource_service.rb +8 -7
  39. data/lib/godmin/resources/resource_service/associations.rb +23 -0
  40. data/lib/godmin/version.rb +1 -1
  41. data/template.rb +42 -7
  42. data/test/dummy/admin/app/controllers/admin/authorized_articles_controller.rb +15 -0
  43. data/test/dummy/admin/app/models/admin/article.rb +4 -0
  44. data/test/dummy/admin/app/policies/admin/article_policy.rb +7 -0
  45. data/test/dummy/admin/config/routes.rb +1 -0
  46. data/test/dummy/app/assets/config/manifest.js +4 -0
  47. data/test/dummy/app/controllers/another_admin_sessions_controller.rb +8 -0
  48. data/test/dummy/app/controllers/comments_controller.rb +3 -0
  49. data/test/dummy/app/models/another_admin_user.rb +7 -0
  50. data/test/dummy/app/models/article.rb +1 -0
  51. data/test/dummy/app/models/comment.rb +7 -0
  52. data/test/dummy/app/services/article_service.rb +2 -0
  53. data/test/dummy/app/services/comment_service.rb +7 -0
  54. data/test/dummy/bin/rails +1 -1
  55. data/test/dummy/config/application.rb +2 -14
  56. data/test/dummy/config/locales/en.yml +9 -0
  57. data/test/dummy/config/routes.rb +6 -1
  58. data/test/dummy/db/migrate/20150717121532_create_articles.rb +1 -1
  59. data/test/dummy/db/migrate/20150907133753_create_admin_users.rb +1 -1
  60. data/test/dummy/db/migrate/20160713134238_create_comment.rb +9 -0
  61. data/test/dummy/db/migrate/20170207081043_create_another_admin_user.rb +10 -0
  62. data/test/dummy/db/schema.rb +26 -11
  63. data/test/fakes/article.rb +1 -1
  64. data/test/fakes/article_service.rb +3 -7
  65. data/test/generators/resource_generator_test.rb +77 -0
  66. data/test/integration/authentication_test.rb +8 -0
  67. data/test/integration/authorization_test.rb +5 -0
  68. data/test/integration/nested_resources_test.rb +47 -0
  69. data/test/test_helper.rb +1 -4
  70. data/test/{lib/godmin → unit}/engine_wrapper_test.rb +1 -1
  71. data/test/{lib/godmin → unit}/helpers/filters_test.rb +0 -0
  72. data/test/{lib/godmin → unit}/paginator_test.rb +11 -0
  73. data/test/{lib/godmin → unit}/resolver_test.rb +0 -0
  74. data/test/{lib/godmin → unit}/resources/resource_service/batch_actions_test.rb +1 -1
  75. data/test/{lib/godmin → unit}/resources/resource_service/filters_test.rb +1 -1
  76. data/test/{lib/godmin → unit}/resources/resource_service/ordering_test.rb +1 -1
  77. data/test/{lib/godmin → unit}/resources/resource_service/pagination_test.rb +0 -0
  78. data/test/{lib/godmin → unit}/resources/resource_service/scopes_test.rb +0 -0
  79. data/test/{lib/godmin → unit}/resources/resource_service_test.rb +0 -0
  80. metadata +167 -107
  81. data/gemfiles/rails_4.gemfile +0 -9
  82. data/lib/godmin/authorization/policy_finder.rb +0 -31
  83. data/lib/tasks/godmin_tasks.rake +0 -4
  84. data/test/lib/godmin/policy_finder_test.rb +0 -55
data/Rakefile CHANGED
@@ -36,14 +36,14 @@ namespace :sandbox do
36
36
  task :deploy do
37
37
  message = "Generated from: https://github.com/varvet/godmin/commit/#{`git rev-parse HEAD`.strip}"
38
38
  template_path = File.expand_path("../template.rb", __FILE__)
39
- Bundler.with_clean_env do
39
+ Bundler.with_unbundled_env do
40
40
  Dir.mktmpdir do |dir|
41
41
  Dir.chdir(dir)
42
42
  system("git clone git@github.com:varvet/godmin-sandbox.git")
43
43
  if $CHILD_STATUS.success?
44
44
  Dir.chdir("godmin-sandbox")
45
45
  system("rm -rf *")
46
- system("rails new . -d postgresql -m #{template_path} --without-engine")
46
+ system("rails _5.2.5_ new . -d postgresql -m #{template_path} --without-engine --skip-spring")
47
47
  if $CHILD_STATUS.success?
48
48
  system("git add --all")
49
49
  system("git commit -m '#{message}'")
@@ -53,12 +53,4 @@ namespace :sandbox do
53
53
  end
54
54
  end
55
55
  end
56
-
57
- desc "Empty and reseed the database on Heroku"
58
- task :reseed do
59
- app = "godmin-sandbox"
60
- Bundler.with_clean_env do
61
- system("heroku run rake sandbox:reseed --app #{app}")
62
- end
63
- end
64
56
  end
@@ -1,12 +1,22 @@
1
1
  <div id="breadcrumb">
2
2
  <ol class="breadcrumb">
3
+ <% if @resource_parents %>
4
+ <% @resource_parents.each do |parent| %>
5
+ <li>
6
+ <%= link_to parent.class.model_name.human(count: 2), parent.class %>
7
+ </li>
8
+ <li>
9
+ <%= link_to parent.to_s, parent %>
10
+ </li>
11
+ <% end %>
12
+ <% end %>
3
13
  <% if action_name == "index" %>
4
14
  <li class="active">
5
15
  <%= @resource_class.model_name.human(count: 2) %>
6
16
  </li>
7
17
  <% else %>
8
18
  <li>
9
- <%= link_to @resource_class.model_name.human(count: 2), @resource_class %>
19
+ <%= link_to @resource_class.model_name.human(count: 2), [*@resource_parents, @resource_class] %>
10
20
  </li>
11
21
  <li class="active">
12
22
  <% if @resource.new_record? %>
@@ -16,29 +26,7 @@
16
26
  <% end %>
17
27
  </li>
18
28
  <% if @resource.persisted? %>
19
- <li class="dropdown pull-right">
20
- <a href="#" data-toggle="dropdown" role="button">
21
- <%= translate_scoped("actions.label") %> <span class="caret"></span>
22
- </a>
23
- <ul class="dropdown-menu">
24
- <% if policy(@resource).show? && action_name != "show" %>
25
- <li>
26
- <%= link_to translate_scoped("actions.show"), @resource %>
27
- </li>
28
- <% end %>
29
- <% if policy(@resource).edit? && action_name != "edit" %>
30
- <li>
31
- <%= link_to translate_scoped("actions.edit"), [:edit, @resource] %>
32
- </li>
33
- <% end %>
34
- <% if policy(@resource).destroy? %>
35
- <li>
36
- <%= link_to translate_scoped("actions.destroy"), @resource, method: :delete,
37
- data: { confirm: translate_scoped("actions.confirm_message") } %>
38
- </li>
39
- <% end %>
40
- </ul>
41
- </li>
29
+ <%= render partial: "breadcrumb_actions" %>
42
30
  <% end %>
43
31
  <% end %>
44
32
  </ol>
@@ -0,0 +1,41 @@
1
+ <li class="dropdown pull-right">
2
+ <a href="#" data-toggle="dropdown">
3
+ <%= translate_scoped("actions.label") %> <span class="caret"></span>
4
+ </a>
5
+ <ul class="dropdown-menu">
6
+ <% if policy(@resource).show? && action_name != "show" %>
7
+ <li>
8
+ <%= link_to translate_scoped("actions.show"), [*@resource_parents, @resource] %>
9
+ </li>
10
+ <% end %>
11
+ <% if policy(@resource).edit? && action_name != "edit" %>
12
+ <li>
13
+ <%= link_to translate_scoped("actions.edit"), [:edit, *@resource_parents, @resource] %>
14
+ </li>
15
+ <% end %>
16
+ <% if policy(@resource).destroy? %>
17
+ <li>
18
+ <%= link_to translate_scoped("actions.destroy"), [*@resource_parents, @resource], method: :delete,
19
+ data: { confirm: translate_scoped("actions.confirm_message") } %>
20
+ </li>
21
+ <% end %>
22
+ </ul>
23
+ </li>
24
+
25
+ <% if @resource_service.has_many_map.present? %>
26
+ <li class="dropdown pull-right">
27
+ <a href="#" data-toggle="dropdown">
28
+ <%= translate_scoped("associations.label") %> <span class="caret"></span>
29
+ </a>
30
+ <ul class="dropdown-menu">
31
+ <% @resource_service.has_many_map.each do |name, options| %>
32
+ <% if policy(options[:class_name].constantize).index? %>
33
+ <li>
34
+ <%= link_to(options[:class_name].constantize.model_name.human(count: 2),
35
+ send("#{@resource_class.name.underscore}_#{name}_path", @resource)) %>
36
+ </li>
37
+ <% end %>
38
+ <% end %>
39
+ </ul>
40
+ </li>
41
+ <% end %>
@@ -1,3 +1,3 @@
1
1
  <% if policy(@resource_service.build_resource({})).new? %>
2
- <%= link_to t("helpers.submit.create", model: @resource_class.model_name.human), [:new, @resource_class.model_name.singular_route_key], class: "btn btn-default" %>
2
+ <%= link_to t("helpers.submit.create", model: @resource_class.model_name.human), [:new, *@resource_parents, @resource_class.model_name.singular_route_key.to_sym], class: "btn btn-default" %>
3
3
  <% end %>
@@ -1,5 +1,8 @@
1
1
  <div id="table" class="table-responsive">
2
2
  <table class="table table-bordered table-hover">
3
+ <caption class="hide">
4
+ <%= @resource_class.model_name.human(count: 2) %>
5
+ </caption>
3
6
  <thead>
4
7
  <tr>
5
8
  <% if @resource_service.include_batch_actions? %>
@@ -2,7 +2,7 @@
2
2
  <% if policy(resource).show? %>
3
3
  <%= link_to(
4
4
  translate_scoped("actions.show"),
5
- resource,
5
+ [*@resource_parents, resource],
6
6
  class: "btn btn-default",
7
7
  title: translate_scoped("actions.show_title", resource: resource)
8
8
  ) %>
@@ -10,7 +10,7 @@
10
10
  <% if policy(resource).edit? %>
11
11
  <%= link_to(
12
12
  translate_scoped("actions.edit"),
13
- [:edit, resource],
13
+ [:edit, *@resource_parents, resource],
14
14
  class: "btn btn-default",
15
15
  title: translate_scoped("actions.edit_title", resource: resource)
16
16
  ) %>
@@ -18,9 +18,9 @@
18
18
  <% if policy(resource).destroy? %>
19
19
  <%= link_to(
20
20
  translate_scoped("actions.destroy"),
21
- resource,
21
+ [*@resource_parents, resource],
22
22
  method: :delete,
23
- class: "btn btn-danger",
23
+ class: "btn btn-default",
24
24
  title: translate_scoped("actions.destroy_title", resource: resource),
25
25
  data: { confirm: translate_scoped("actions.confirm_message") }
26
26
  ) %>
@@ -1,6 +1,6 @@
1
1
  <%= render partial: "breadcrumb" %>
2
2
 
3
- <table class="table table-striped">
3
+ <table class="table">
4
4
  <% @resource_service.attrs_for_show.each do |attr| %>
5
5
  <tr>
6
6
  <th><%= @resource_class.human_attribute_name(attr) %></th>
@@ -25,6 +25,8 @@ en:
25
25
  confirm_message: Are you sure?
26
26
  export: Export
27
27
  export_as: As
28
+ associations:
29
+ label: Nested resources
28
30
  sessions:
29
31
  sign_in: Sign in
30
32
  sign_out: Sign out
@@ -25,6 +25,8 @@ pt-BR:
25
25
  confirm_message: Você tem certeza?
26
26
  export: Exportar
27
27
  export_as: Como
28
+ associations:
29
+ label: Nested resources
28
30
  sessions:
29
31
  sign_in: Entrar
30
32
  sign_out: Sair
@@ -25,6 +25,8 @@ sv:
25
25
  confirm_message: Är du säker?
26
26
  export: Exportera
27
27
  export_as: Som
28
+ associations:
29
+ label: Nästlade resurser
28
30
  sessions:
29
31
  sign_in: Logga in
30
32
  sign_out: Logga ut
@@ -2,8 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "admin", :path => "../test/dummy/admin", :group => [:test, :development]
6
- gem "codeclimate-test-reporter", :group => :test, :require => nil
7
- gem "rails", "~> 5.0"
5
+ gem "admin", path: "../test/dummy/admin", group: [:test, :development]
6
+ gem "rails", "~> 5.2"
8
7
 
9
- gemspec :path => "../"
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "admin", path: "../test/dummy/admin", group: [:test, :development]
6
+ gem "rails", "~> 6.1"
7
+
8
+ gemspec path: "../"
data/godmin.gemspec CHANGED
@@ -10,8 +10,8 @@ Gem::Specification.new do |gem|
10
10
  gem.authors = ["Jens Ljungblad", "Linus Pettersson", "Varvet"]
11
11
  gem.email = ["info@varvet.se"]
12
12
  gem.homepage = "https://github.com/varvet/godmin"
13
- gem.summary = "Godmin is an admin framework for Rails 4+"
14
- gem.description = "Godmin is an admin framework for Rails 4+. Use it to build dedicated admin sections for your apps, or stand alone admin apps such as internal tools."
13
+ gem.summary = "Godmin is an admin framework for Rails 5+"
14
+ gem.description = "Godmin is an admin framework for Rails 5+. Use it to build dedicated admin sections for your apps, or stand alone admin apps such as internal tools."
15
15
  gem.license = "MIT"
16
16
 
17
17
  gem.files = `git ls-files`.split($/)
@@ -19,23 +19,25 @@ Gem::Specification.new do |gem|
19
19
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
20
20
  gem.require_paths = ["lib"]
21
21
 
22
- gem.add_dependency "bcrypt", "~> 3.1"
23
- gem.add_dependency "bootstrap_form", "~> 2.4"
22
+ gem.add_dependency "bcrypt", [">= 3.0", "< 4.0"]
24
23
  gem.add_dependency "bootstrap-sass", "~> 3.3"
25
- gem.add_dependency "coffee-rails", [">= 4.0", "< 6.0"]
24
+ gem.add_dependency "bootstrap_form", "~> 2.4"
26
25
  gem.add_dependency "csv_builder", "~> 2.1"
27
- gem.add_dependency "jquery-rails", [">= 3.0", "< 5.0"]
26
+ gem.add_dependency "jquery-rails", [">= 4.0", "< 5.0"]
28
27
  gem.add_dependency "momentjs-rails", "~> 2.8"
29
- gem.add_dependency "rails", [">= 4.0", "< 6.0"]
30
- gem.add_dependency "sass-rails", [">= 4.0", "< 6.0"]
28
+ gem.add_dependency "pundit", [">= 1.1", "< 2.0"]
29
+ gem.add_dependency "rails", [">= 5.0", "< 7.0"]
30
+ gem.add_dependency "sass-rails", [">= 5.0", "< 7.0"]
31
31
  gem.add_dependency "selectize-rails", "~> 0.12"
32
32
 
33
- gem.add_development_dependency "appraisal", "~> 2.1"
34
- gem.add_development_dependency "capybara", "~> 2.4"
35
- gem.add_development_dependency "m", "~> 1.3"
36
- gem.add_development_dependency "minitest-reporters", "~> 1.0"
37
- gem.add_development_dependency "minitest", "~> 5.5"
38
- gem.add_development_dependency "poltergeist", "~> 1.7"
39
- gem.add_development_dependency "pry", "~> 0.10"
40
- gem.add_development_dependency "sqlite3", "~> 1.3"
33
+ gem.add_development_dependency "appraisal"
34
+ gem.add_development_dependency "bootsnap"
35
+ gem.add_development_dependency "byebug"
36
+ gem.add_development_dependency "capybara"
37
+ gem.add_development_dependency "minitest"
38
+ gem.add_development_dependency "minitest-reporters"
39
+ gem.add_development_dependency "poltergeist"
40
+ gem.add_development_dependency "pry"
41
+ gem.add_development_dependency "puma"
42
+ gem.add_development_dependency "sqlite3"
41
43
  end
@@ -4,7 +4,7 @@ class Godmin::ResourceGenerator < Godmin::Generators::NamedBase
4
4
  argument :attributes, type: :array, default: [], banner: "attribute attribute"
5
5
 
6
6
  def add_route
7
- route "resources :#{file_name.pluralize}"
7
+ invoke "resource_route"
8
8
  end
9
9
 
10
10
  def add_navigation
@@ -15,6 +15,12 @@ class Godmin::ResourceGenerator < Godmin::Generators::NamedBase
15
15
  end
16
16
  end
17
17
 
18
+ def create_model
19
+ if namespaced?
20
+ template "resource_model.rb", File.join("app/models", class_path, "#{file_name}.rb")
21
+ end
22
+ end
23
+
18
24
  def create_controller
19
25
  template "resource_controller.rb", File.join("app/controllers", class_path, "#{file_name.pluralize}_controller.rb")
20
26
  end
@@ -0,0 +1,4 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %> < ::<%= class_name %>
3
+ end
4
+ <% end -%>
@@ -28,15 +28,6 @@ module Godmin
28
28
 
29
29
  protected
30
30
 
31
- def redirect_back
32
- case Rails::VERSION::MAJOR
33
- when 4
34
- redirect_to :back
35
- when 5
36
- super(fallback_location: root_path)
37
- end
38
- end
39
-
40
31
  private
41
32
 
42
33
  def engine_wrapper
@@ -47,12 +38,20 @@ module Godmin
47
38
  append_view_path Godmin::Resolver.resolvers(controller_path, engine_wrapper)
48
39
  end
49
40
 
41
+ def disable_authentication
42
+ @_disable_authentication = true
43
+ end
44
+
45
+ def disable_authorization
46
+ @_disable_authorization = true
47
+ end
48
+
50
49
  def authentication_enabled?
51
- singleton_class.include?(Godmin::Authentication)
50
+ !@_disable_authentication && singleton_class.include?(Godmin::Authentication)
52
51
  end
53
52
 
54
53
  def authorization_enabled?
55
- singleton_class.include?(Godmin::Authorization)
54
+ !@_disable_authorization && singleton_class.include?(Godmin::Authorization)
56
55
  end
57
56
  end
58
57
  end
@@ -6,26 +6,26 @@ module Godmin
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  included do
9
- before_action :authenticate_admin_user
9
+ before_action :authenticate
10
10
 
11
11
  helper_method :admin_user
12
12
  helper_method :admin_user_signed_in?
13
13
  end
14
14
 
15
- def authenticate_admin_user
16
- unless admin_user_signed_in? || controller_name == "sessions"
17
- redirect_to new_session_path, alert: "Authentication needed"
18
- end
19
- end
15
+ def authenticate
16
+ return unless authentication_enabled?
17
+ return if admin_user_signed_in?
20
18
 
21
- def admin_user_class
22
- raise NotImplementedError, "Must define the admin user class"
19
+ redirect_to new_session_path
23
20
  end
24
21
 
22
+ def admin_user_class; end
23
+
25
24
  def admin_user
26
- if session[:admin_user_id]
27
- @admin_user ||= admin_user_class.find_by(id: session[:admin_user_id])
28
- end
25
+ return unless admin_user_class
26
+ return unless session[:admin_user_id]
27
+
28
+ @_admin_user ||= admin_user_class.find_by(id: session[:admin_user_id])
29
29
  end
30
30
 
31
31
  def admin_user_signed_in?
@@ -5,6 +5,7 @@ module Godmin
5
5
 
6
6
  included do
7
7
  layout "godmin/login"
8
+ prepend_before_action :disable_authentication
8
9
  end
9
10
 
10
11
  def new
@@ -34,7 +35,7 @@ module Godmin
34
35
  end
35
36
 
36
37
  def admin_user_params
37
- params.require(:admin_user).permit(
38
+ params.require(admin_user_class.model_name.param_key.to_sym).permit(
38
39
  admin_user_class.login_column,
39
40
  :password,
40
41
  :password_confirm
@@ -1,34 +1,20 @@
1
+ require "pundit"
1
2
  require "godmin/authorization/policy"
2
- require "godmin/authorization/policy_finder"
3
3
 
4
4
  module Godmin
5
5
  module Authorization
6
6
  extend ActiveSupport::Concern
7
7
 
8
- included do
9
- helper_method :policy
8
+ include Pundit
10
9
 
11
- rescue_from NotAuthorizedError do
10
+ included do
11
+ rescue_from Pundit::NotAuthorizedError do
12
12
  render plain: "You are not authorized to do this", status: 403, layout: "godmin/login"
13
13
  end
14
14
  end
15
15
 
16
- def authorize(record, query = nil)
17
- policy = policy(record)
18
-
19
- unless policy.public_send(query || action_name + "?")
20
- fail NotAuthorizedError
21
- end
16
+ def pundit_user
17
+ admin_user
22
18
  end
23
-
24
- def policy(record)
25
- policies[record] ||= PolicyFinder.find(record, engine_wrapper.namespace).new(admin_user, record)
26
- end
27
-
28
- def policies
29
- @_policies ||= {}
30
- end
31
-
32
- class NotAuthorizedError < StandardError; end
33
19
  end
34
20
  end