godmin 1.3.1 → 2.2.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 (90) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +0 -2
  3. data/.gitignore +1 -0
  4. data/.travis.yml +9 -10
  5. data/Appraisals +4 -4
  6. data/CHANGELOG.md +84 -2
  7. data/Gemfile +1 -2
  8. data/README.md +119 -10
  9. data/Rakefile +2 -2
  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/_pagination.html.erb +4 -4
  14. data/app/views/godmin/resource/_table.html.erb +3 -0
  15. data/app/views/godmin/resource/columns/_actions.html.erb +4 -4
  16. data/app/views/godmin/resource/show.html.erb +1 -1
  17. data/config/locales/en.yml +2 -0
  18. data/config/locales/pt-BR.yml +2 -0
  19. data/config/locales/sv.yml +2 -0
  20. data/gemfiles/rails_5.gemfile +3 -4
  21. data/gemfiles/rails_6.gemfile +8 -0
  22. data/godmin.gemspec +18 -16
  23. data/lib/generators/godmin/resource/resource_generator.rb +7 -1
  24. data/lib/generators/godmin/resource/templates/resource_model.rb +4 -0
  25. data/lib/godmin/application_controller.rb +10 -11
  26. data/lib/godmin/authentication.rb +11 -11
  27. data/lib/godmin/authentication/sessions_controller.rb +2 -1
  28. data/lib/godmin/authorization.rb +34 -14
  29. data/lib/godmin/engine_wrapper.rb +10 -1
  30. data/lib/godmin/generators/base.rb +4 -4
  31. data/lib/godmin/generators/named_base.rb +4 -4
  32. data/lib/godmin/helpers/application.rb +3 -3
  33. data/lib/godmin/helpers/batch_actions.rb +1 -1
  34. data/lib/godmin/helpers/forms.rb +5 -1
  35. data/lib/godmin/paginator.rb +12 -4
  36. data/lib/godmin/resolver.rb +20 -5
  37. data/lib/godmin/resources/resource_controller.rb +24 -5
  38. data/lib/godmin/resources/resource_controller/batch_actions.rb +1 -1
  39. data/lib/godmin/resources/resource_service.rb +8 -7
  40. data/lib/godmin/resources/resource_service/associations.rb +23 -0
  41. data/lib/godmin/version.rb +1 -1
  42. data/template.rb +17 -3
  43. data/test/dummy/admin/app/controllers/admin/authorized_articles_controller.rb +29 -0
  44. data/test/dummy/admin/app/models/admin/article.rb +4 -0
  45. data/test/dummy/admin/app/models/admin/magazine.rb +4 -0
  46. data/test/dummy/admin/app/policies/admin/article_policy.rb +11 -0
  47. data/test/dummy/admin/app/policies/admin/magazine_policy.rb +4 -0
  48. data/test/dummy/admin/app/views/admin/shared/_navigation.html.erb +5 -0
  49. data/test/dummy/admin/config/routes.rb +1 -0
  50. data/test/dummy/app/assets/config/manifest.js +4 -0
  51. data/test/dummy/app/controllers/another_admin_sessions_controller.rb +8 -0
  52. data/test/dummy/app/controllers/comments_controller.rb +3 -0
  53. data/test/dummy/app/models/another_admin_user.rb +7 -0
  54. data/test/dummy/app/models/article.rb +1 -0
  55. data/test/dummy/app/models/comment.rb +7 -0
  56. data/test/dummy/app/models/magazine.rb +2 -0
  57. data/test/dummy/app/services/article_service.rb +2 -0
  58. data/test/dummy/app/services/comment_service.rb +7 -0
  59. data/test/dummy/bin/rails +1 -1
  60. data/test/dummy/config/application.rb +2 -14
  61. data/test/dummy/config/locales/en.yml +9 -0
  62. data/test/dummy/config/routes.rb +6 -1
  63. data/test/dummy/db/migrate/20150717121532_create_articles.rb +1 -1
  64. data/test/dummy/db/migrate/20150907133753_create_admin_users.rb +1 -1
  65. data/test/dummy/db/migrate/20160713134238_create_comment.rb +9 -0
  66. data/test/dummy/db/migrate/20170207081043_create_another_admin_user.rb +10 -0
  67. data/test/dummy/db/migrate/20210519215502_create_magazines.rb +9 -0
  68. data/test/dummy/db/schema.rb +38 -16
  69. data/test/fakes/article.rb +1 -1
  70. data/test/fakes/article_service.rb +3 -7
  71. data/test/generators/resource_generator_test.rb +78 -0
  72. data/test/integration/authentication_test.rb +8 -0
  73. data/test/integration/authorization_test.rb +13 -0
  74. data/test/integration/nested_resources_test.rb +47 -0
  75. data/test/test_helper.rb +1 -4
  76. data/test/{lib/godmin → unit}/engine_wrapper_test.rb +1 -1
  77. data/test/{lib/godmin → unit}/helpers/filters_test.rb +0 -0
  78. data/test/{lib/godmin → unit}/paginator_test.rb +11 -0
  79. data/test/{lib/godmin → unit}/resolver_test.rb +0 -0
  80. data/test/{lib/godmin → unit}/resources/resource_service/batch_actions_test.rb +1 -1
  81. data/test/{lib/godmin → unit}/resources/resource_service/filters_test.rb +1 -1
  82. data/test/{lib/godmin → unit}/resources/resource_service/ordering_test.rb +1 -1
  83. data/test/{lib/godmin → unit}/resources/resource_service/pagination_test.rb +0 -0
  84. data/test/{lib/godmin → unit}/resources/resource_service/scopes_test.rb +0 -0
  85. data/test/{lib/godmin → unit}/resources/resource_service_test.rb +0 -0
  86. metadata +175 -108
  87. data/gemfiles/rails_4.gemfile +0 -9
  88. data/lib/godmin/authorization/policy_finder.rb +0 -31
  89. data/lib/tasks/godmin_tasks.rake +0 -4
  90. data/test/lib/godmin/policy_finder_test.rb +0 -55
@@ -0,0 +1,4 @@
1
+ module Admin
2
+ class MagazinePolicy < Godmin::Authorization::Policy
3
+ end
4
+ end
@@ -1 +1,6 @@
1
1
  <%= navbar_item Article %>
2
+ <% if policy(Article).index? %>
3
+ Can index
4
+ <% else %>
5
+ Can't index
6
+ <% end %>
@@ -1,4 +1,5 @@
1
1
  Admin::Engine.routes.draw do
2
2
  resources :articles
3
+ resources :authorized_articles
3
4
  root to: "application#welcome"
4
5
  end
@@ -0,0 +1,4 @@
1
+ //= link application.css
2
+ //= link application.js
3
+ //= link admin/application.css
4
+ //= link admin/application.js
@@ -0,0 +1,8 @@
1
+ class AnotherAdminSessionsController < ApplicationController
2
+ include Godmin::Authentication::SessionsController
3
+ include Godmin::Authentication
4
+
5
+ def admin_user_class
6
+ AnotherAdminUser
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ class CommentsController < ApplicationController
2
+ include Godmin::Resources::ResourceController
3
+ end
@@ -0,0 +1,7 @@
1
+ class AnotherAdminUser < ActiveRecord::Base
2
+ include Godmin::Authentication::User
3
+
4
+ def self.login_column
5
+ :email
6
+ end
7
+ end
@@ -1,5 +1,6 @@
1
1
  class Article < ActiveRecord::Base
2
2
  belongs_to :admin_user
3
+ has_many :comments
3
4
 
4
5
  def non_orderable_column
5
6
  "Not orderable"
@@ -0,0 +1,7 @@
1
+ class Comment < ActiveRecord::Base
2
+ belongs_to :article
3
+
4
+ def to_s
5
+ title
6
+ end
7
+ end
@@ -0,0 +1,2 @@
1
+ class Magazine < ActiveRecord::Base
2
+ end
@@ -5,6 +5,8 @@ class ArticleService
5
5
  attrs_for_show :id, :title, :body, :admin_user, :published
6
6
  attrs_for_form :title, :body, :admin_user, :published
7
7
 
8
+ has_many :comments
9
+
8
10
  def order_by_admin_user(resources, direction)
9
11
  resources.joins(:admin_users).order("admin_users.email #{direction}")
10
12
  end
@@ -0,0 +1,7 @@
1
+ class CommentService
2
+ include Godmin::Resources::ResourceService
3
+
4
+ attrs_for_index :id, :title
5
+ attrs_for_show :id, :title, :body
6
+ attrs_for_form :title, :body
7
+ end
data/test/dummy/bin/rails CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- APP_PATH = File.expand_path('../../config/application', __FILE__)
2
+ APP_PATH = File.expand_path('../config/application', __dir__)
3
3
  require_relative '../config/boot'
4
4
  require 'rails/commands'
@@ -1,23 +1,11 @@
1
- require File.expand_path('../boot', __FILE__)
1
+ require File.expand_path("../boot", __FILE__)
2
2
 
3
- require 'rails/all'
3
+ require "rails/all"
4
4
 
5
5
  Bundler.require(*Rails.groups)
6
6
  require "godmin"
7
7
 
8
8
  module Dummy
9
9
  class Application < Rails::Application
10
- # Settings in config/environments/* take precedence over those specified here.
11
- # Application configuration should go into files in config/initializers
12
- # -- all .rb files in that directory are automatically loaded.
13
-
14
- # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
15
- # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
16
- # config.time_zone = 'Central Time (US & Canada)'
17
-
18
- # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
19
- # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
20
- # config.i18n.default_locale = :de
21
10
  end
22
11
  end
23
-
@@ -0,0 +1,9 @@
1
+ en:
2
+ activerecord:
3
+ models:
4
+ article:
5
+ one: Article
6
+ other: Articles
7
+ comment:
8
+ one: Comment
9
+ other: Comments
@@ -1,8 +1,13 @@
1
1
  Rails.application.routes.draw do
2
- resources :articles
2
+ resources :articles do
3
+ resources :comments
4
+ end
3
5
  resources :authenticated_articles
4
6
  resources :authorized_articles
5
7
  resource :session, only: [:new, :create, :destroy]
8
+
9
+ resource :another_admin_session, only: [:create]
10
+
6
11
  root to: "application#welcome"
7
12
  mount Admin::Engine, at: "admin"
8
13
  end
@@ -1,4 +1,4 @@
1
- class CreateArticles < ActiveRecord::Migration
1
+ class CreateArticles < ActiveRecord::Migration[5.0]
2
2
  def change
3
3
  create_table :articles do |t|
4
4
  t.string :title
@@ -1,4 +1,4 @@
1
- class CreateAdminUsers < ActiveRecord::Migration
1
+ class CreateAdminUsers < ActiveRecord::Migration[5.0]
2
2
  def change
3
3
  create_table :admin_users do |t|
4
4
  t.string :email
@@ -0,0 +1,9 @@
1
+ class CreateComment < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :comments do |t|
4
+ t.references :article, index: true, foreign_key: true
5
+ t.string :title
6
+ t.text :body
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ class CreateAnotherAdminUser < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :another_admin_users do |t|
4
+ t.string :email
5
+ t.text :password_digest
6
+
7
+ t.timestamps null: false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ class CreateMagazines < ActiveRecord::Migration[6.1]
2
+ def change
3
+ create_table :magazines do |t|
4
+ t.string :name
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -2,30 +2,52 @@
2
2
  # of editing this file, please use the migrations feature of Active Record to
3
3
  # incrementally modify your database, and then regenerate this schema definition.
4
4
  #
5
- # Note that this schema.rb definition is the authoritative source for your
6
- # database schema. If you need to create the application database on another
7
- # system, you should be using db:schema:load, not running all the migrations
8
- # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9
- # you'll amass, the slower it'll run and the greater likelihood for issues).
5
+ # This file is the source Rails uses to define your schema when running `bin/rails
6
+ # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
7
+ # be faster and is potentially less error prone than running all of your
8
+ # migrations from scratch. Old migrations may fail to apply correctly if those
9
+ # migrations use external dependencies or application code.
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 20150907133753) do
13
+ ActiveRecord::Schema.define(version: 2021_05_19_215502) do
14
14
 
15
15
  create_table "admin_users", force: :cascade do |t|
16
- t.string "email"
17
- t.text "password_digest"
18
- t.datetime "created_at", null: false
19
- t.datetime "updated_at", null: false
16
+ t.string "email"
17
+ t.text "password_digest"
18
+ t.datetime "created_at", null: false
19
+ t.datetime "updated_at", null: false
20
+ end
21
+
22
+ create_table "another_admin_users", force: :cascade do |t|
23
+ t.string "email"
24
+ t.text "password_digest"
25
+ t.datetime "created_at", null: false
26
+ t.datetime "updated_at", null: false
20
27
  end
21
28
 
22
29
  create_table "articles", force: :cascade do |t|
23
- t.string "title"
24
- t.text "body"
25
- t.boolean "published", default: false
26
- t.integer "admin_user_id"
27
- t.datetime "created_at", null: false
28
- t.datetime "updated_at", null: false
30
+ t.string "title"
31
+ t.text "body"
32
+ t.boolean "published", default: false
33
+ t.integer "admin_user_id"
34
+ t.datetime "created_at", null: false
35
+ t.datetime "updated_at", null: false
36
+ t.index ["admin_user_id"], name: "index_articles_on_admin_user_id"
37
+ end
38
+
39
+ create_table "comments", force: :cascade do |t|
40
+ t.integer "article_id"
41
+ t.string "title"
42
+ t.text "body"
43
+ t.index ["article_id"], name: "index_comments_on_article_id"
44
+ end
45
+
46
+ create_table "magazines", force: :cascade do |t|
47
+ t.string "name"
48
+ t.datetime "created_at", precision: 6, null: false
49
+ t.datetime "updated_at", precision: 6, null: false
29
50
  end
30
51
 
52
+ add_foreign_key "comments", "articles"
31
53
  end
@@ -5,7 +5,7 @@ module Fakes
5
5
  end
6
6
 
7
7
  def self.column_names
8
- ["id", "title"]
8
+ %w[id title]
9
9
  end
10
10
  end
11
11
  end
@@ -13,8 +13,8 @@ module Fakes
13
13
  scope :published
14
14
 
15
15
  filter :title
16
- filter :country, as: :select, collection: %w(Sweden Canada)
17
- filter :tags, as: :multiselect, collection: %w(Apple Banana)
16
+ filter :country, as: :select, collection: %w[Sweden Canada]
17
+ filter :tags, as: :multiselect, collection: %w[Apple Banana]
18
18
 
19
19
  batch_action :unpublish
20
20
  batch_action :publish, confirm: true, only: [:unpublished], except: [:published]
@@ -24,12 +24,8 @@ module Fakes
24
24
  @called_methods = { scopes: {}, filters: {}, batch_actions: {}, ordering: {} }
25
25
  end
26
26
 
27
- def resource_class
28
- Fakes::Article
29
- end
30
-
31
27
  def resources_relation
32
- [:foo, :bar, :baz]
28
+ %i[foo bar baz]
33
29
  end
34
30
 
35
31
  def order_by_foobar(resources, direction)
@@ -0,0 +1,78 @@
1
+ require "test_helper"
2
+ require "generators/godmin/resource/resource_generator"
3
+
4
+ module Godmin
5
+ class ResourceGeneratorTest < ::Rails::Generators::TestCase
6
+ tests ResourceGenerator
7
+ destination File.expand_path("../../tmp", __FILE__)
8
+ setup :prepare_destination
9
+ teardown :prepare_destination
10
+
11
+ def test_resource_generator_in_standalone_install
12
+ system "cd #{destination_root} && rails new . --skip-test --skip-spring --skip-bundle --skip-git --quiet"
13
+ system "cd #{destination_root} && bin/rails generate godmin:install --quiet"
14
+ system "cd #{destination_root} && bin/rails generate godmin:resource foo bar --quiet"
15
+
16
+ assert_file "config/routes.rb", /resources :foos/
17
+ assert_file "app/views/shared/_navigation.html.erb", /<%= navbar_item Foo %>/
18
+
19
+ assert_file "app/controllers/foos_controller.rb" do |content|
20
+ expected_content = <<-CONTENT.strip_heredoc
21
+ class FoosController < ApplicationController
22
+ include Godmin::Resources::ResourceController
23
+ end
24
+ CONTENT
25
+ assert_match expected_content, content
26
+ end
27
+
28
+ assert_file "app/services/foo_service.rb" do |content|
29
+ expected_content = <<-CONTENT.strip_heredoc
30
+ class FooService
31
+ include Godmin::Resources::ResourceService
32
+
33
+ attrs_for_index :bar
34
+ attrs_for_show :bar
35
+ attrs_for_form :bar
36
+ end
37
+ CONTENT
38
+ assert_match expected_content, content
39
+ end
40
+ end
41
+
42
+ def test_resource_generator_in_engine_install
43
+ system "cd #{destination_root} && rails new . --skip-test --skip-spring --skip-bundle --skip-git --quiet"
44
+ system "cd #{destination_root} && bin/rails plugin new fakemin --mountable --quiet"
45
+ system "cd #{destination_root} && fakemin/bin/rails generate godmin:install --quiet"
46
+ system "cd #{destination_root} && fakemin/bin/rails generate godmin:resource foo bar --quiet"
47
+
48
+ assert_file "fakemin/config/routes.rb", /resources :foos/
49
+ assert_file "fakemin/app/views/fakemin/shared/_navigation.html.erb", /<%= navbar_item Foo %>/
50
+
51
+ assert_file "fakemin/app/controllers/fakemin/foos_controller.rb" do |content|
52
+ expected_content = <<-CONTENT.strip_heredoc
53
+ module Fakemin
54
+ class FoosController < ApplicationController
55
+ include Godmin::Resources::ResourceController
56
+ end
57
+ end
58
+ CONTENT
59
+ assert_match expected_content, content
60
+ end
61
+
62
+ assert_file "fakemin/app/services/fakemin/foo_service.rb" do |content|
63
+ expected_content = <<-CONTENT.strip_heredoc
64
+ module Fakemin
65
+ class FooService
66
+ include Godmin::Resources::ResourceService
67
+
68
+ attrs_for_index :bar
69
+ attrs_for_show :bar
70
+ attrs_for_form :bar
71
+ end
72
+ end
73
+ CONTENT
74
+ assert_match expected_content, content
75
+ end
76
+ end
77
+ end
78
+ end
@@ -14,4 +14,12 @@ class AuthenticationTest < ActionDispatch::IntegrationTest
14
14
  visit authenticated_articles_path
15
15
  assert_not_equal authenticated_articles_path, current_path
16
16
  end
17
+
18
+ def test_sign_in_with_non_default_user
19
+ AnotherAdminUser.create!(email: "another_admin@example.com", password: "password")
20
+ post another_admin_session_path, params: {
21
+ another_admin_user: { email: "another_admin@example.com", password: "password" }
22
+ }
23
+ assert_redirected_to root_path
24
+ end
17
25
  end
@@ -29,4 +29,17 @@ class AuthorizationTest < ActionDispatch::IntegrationTest
29
29
  page.driver.delete authorized_article_path(article)
30
30
  assert_equal 403, page.status_code
31
31
  end
32
+
33
+ def test_cannot_index_in_engine?
34
+ visit admin.authorized_articles_path
35
+ assert_equal 403, page.status_code
36
+ end
37
+
38
+ def test_uses_engine_policy_in_engine?
39
+ visit admin.new_authorized_article_path
40
+
41
+ assert_equal 200, page.status_code
42
+
43
+ assert page.has_content?("Can't index"), "when used in an engine, the `policy` method is using the policy from the main app, not the engine"
44
+ end
32
45
  end
@@ -0,0 +1,47 @@
1
+ require "test_helper"
2
+
3
+ class NestedResourcesTest < ActionDispatch::IntegrationTest
4
+ def test_list_nested_resources
5
+ article = Article.create! title: "foo", comments: [
6
+ Comment.new(title: "bar")
7
+ ]
8
+
9
+ visit articles_path
10
+ within "[data-resource-id='#{article.id}']" do
11
+ click_link "Show"
12
+ end
13
+ click_link "Comments"
14
+
15
+ assert_equal article_comments_path(article), current_path
16
+ assert page.has_content? "bar"
17
+ end
18
+
19
+ def test_list_nested_resources_scoping
20
+ article = Article.create! title: "foo", comments: [
21
+ Comment.new(title: "bar")
22
+ ]
23
+ Comment.create! title: "baz"
24
+
25
+ visit article_comments_path(article)
26
+
27
+ assert page.has_content? "bar"
28
+ assert page.has_no_content? "baz"
29
+ end
30
+
31
+ def test_create_nested_resource
32
+ article = Article.create! title: "foo"
33
+
34
+ visit new_article_comment_path(article)
35
+
36
+ fill_in "Title", with: "bar"
37
+ click_button "Create Comment"
38
+
39
+ assert_equal article_comment_path(article, Comment.last), current_path
40
+
41
+ within "#breadcrumb" do
42
+ click_link "Comments"
43
+ end
44
+
45
+ assert page.has_content? "bar"
46
+ end
47
+ end