godmin 0.10.3 → 0.11.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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +8 -0
  4. data/README.md +146 -81
  5. data/app/assets/javascripts/godmin/batch-actions.js +18 -13
  6. data/app/assets/stylesheets/godmin/index.css.scss +15 -8
  7. data/app/views/godmin/resource/_batch_actions.html.erb +2 -4
  8. data/app/views/godmin/resource/_breadcrumb.html.erb +0 -3
  9. data/app/views/godmin/resource/_button_actions.html.erb +2 -2
  10. data/app/views/godmin/resource/_filters.html.erb +17 -18
  11. data/app/views/godmin/resource/_form.html.erb +1 -1
  12. data/app/views/godmin/resource/_pagination.html.erb +11 -11
  13. data/app/views/godmin/resource/_scopes.html.erb +4 -4
  14. data/app/views/godmin/resource/_table.html.erb +30 -30
  15. data/app/views/godmin/resource/index.html.erb +3 -10
  16. data/godmin.gemspec +4 -1
  17. data/lib/generators/godmin/authentication/templates/sessions_controller.rb +1 -1
  18. data/lib/generators/godmin/install/install_generator.rb +1 -1
  19. data/lib/generators/godmin/resource/resource_generator.rb +4 -0
  20. data/lib/generators/godmin/resource/templates/resource_controller.rb +1 -9
  21. data/lib/generators/godmin/resource/templates/resource_service.rb +8 -0
  22. data/lib/godmin.rb +4 -2
  23. data/lib/godmin/{application.rb → application_controller.rb} +1 -1
  24. data/lib/godmin/authentication.rb +1 -1
  25. data/lib/godmin/authentication/{sessions.rb → sessions_controller.rb} +1 -1
  26. data/lib/godmin/authorization.rb +1 -1
  27. data/lib/godmin/authorization/policy_finder.rb +3 -1
  28. data/lib/godmin/helpers/application.rb +10 -0
  29. data/lib/godmin/helpers/batch_actions.rb +7 -4
  30. data/lib/godmin/helpers/filters.rb +72 -73
  31. data/lib/godmin/helpers/tables.rb +1 -3
  32. data/lib/godmin/paginator.rb +47 -0
  33. data/lib/godmin/rails.rb +1 -6
  34. data/lib/godmin/resolver.rb +7 -2
  35. data/lib/godmin/resources/resource_controller.rb +170 -0
  36. data/lib/godmin/resources/resource_service.rb +82 -0
  37. data/lib/godmin/resources/resource_service/batch_actions.rb +38 -0
  38. data/lib/godmin/resources/resource_service/filters.rb +37 -0
  39. data/lib/godmin/resources/resource_service/ordering.rb +27 -0
  40. data/lib/godmin/resources/resource_service/pagination.rb +22 -0
  41. data/lib/godmin/resources/resource_service/scopes.rb +61 -0
  42. data/lib/godmin/version.rb +1 -1
  43. data/test/dummy/config/environments/production.rb +1 -1
  44. data/test/dummy/config/environments/test.rb +1 -1
  45. data/test/dummy/db/schema.rb +16 -0
  46. data/test/lib/godmin/helpers/filters_test.rb +26 -0
  47. data/test/lib/godmin/paginator_test.rb +84 -0
  48. data/test/lib/godmin/policy_finder_test.rb +35 -6
  49. data/test/lib/godmin/resolver_test.rb +6 -0
  50. data/test/lib/godmin/resources/resource_service/batch_actions_test.rb +45 -0
  51. data/test/lib/godmin/resources/resource_service/filters_test.rb +32 -0
  52. data/test/lib/godmin/resources/resource_service/ordering_test.rb +37 -0
  53. data/test/lib/godmin/resources/resource_service/pagination_test.rb +31 -0
  54. data/test/lib/godmin/resources/resource_service/scopes_test.rb +57 -0
  55. data/test/lib/godmin/resources/resource_service_test.rb +21 -0
  56. data/test/test_helper.rb +62 -0
  57. metadata +75 -17
  58. data/.hound.yml +0 -3
  59. data/lib/godmin/resource.rb +0 -177
  60. data/lib/godmin/resource/batch_actions.rb +0 -45
  61. data/lib/godmin/resource/filters.rb +0 -41
  62. data/lib/godmin/resource/ordering.rb +0 -25
  63. data/lib/godmin/resource/pagination.rb +0 -64
  64. data/lib/godmin/resource/scopes.rb +0 -54
  65. data/test/dummy/db/test.sqlite3 +0 -0
@@ -0,0 +1,82 @@
1
+ require "godmin/resources/resource_service/batch_actions"
2
+ require "godmin/resources/resource_service/filters"
3
+ require "godmin/resources/resource_service/ordering"
4
+ require "godmin/resources/resource_service/pagination"
5
+ require "godmin/resources/resource_service/scopes"
6
+
7
+ module Godmin
8
+ module Resources
9
+ module ResourceService
10
+ extend ActiveSupport::Concern
11
+
12
+ include BatchActions
13
+ include Filters
14
+ include Ordering
15
+ include Pagination
16
+ include Scopes
17
+
18
+ attr_reader :options
19
+
20
+ def initialize(options = {})
21
+ @options = options
22
+ end
23
+
24
+ # TODO: should this raise its own error?
25
+ def resource_class
26
+ @options[:resource_class] || self.class.name.demodulize.chomp("Service").constantize
27
+ end
28
+
29
+ def resources_relation
30
+ resource_class.all
31
+ end
32
+
33
+ def resources(params)
34
+ apply_pagination(params[:page],
35
+ apply_order(params[:order],
36
+ apply_filters(params[:filter],
37
+ apply_scope(params[:scope],
38
+ resources_relation
39
+ )
40
+ )
41
+ )
42
+ )
43
+ end
44
+
45
+ def find_resource(id)
46
+ resources_relation.find(id)
47
+ end
48
+
49
+ def build_resource(params)
50
+ resources_relation.new(params)
51
+ end
52
+
53
+ def create_resource(resource)
54
+ resource.save
55
+ end
56
+
57
+ def update_resource(resource, params)
58
+ resource.update(params)
59
+ end
60
+
61
+ def attrs_for_index
62
+ self.class.attrs_for_index
63
+ end
64
+
65
+ def attrs_for_form
66
+ self.class.attrs_for_form
67
+ end
68
+
69
+ module ClassMethods
70
+ def attrs_for_index(*attrs)
71
+ @attrs_for_index = attrs if attrs.present?
72
+ @attrs_for_index || []
73
+ end
74
+
75
+ def attrs_for_form(*attrs)
76
+ @attrs_for_form = attrs if attrs.present?
77
+ @attrs_for_form || []
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,38 @@
1
+ module Godmin
2
+ module Resources
3
+ module ResourceService
4
+ module BatchActions
5
+ extend ActiveSupport::Concern
6
+
7
+ delegate :batch_action_map, to: "self.class"
8
+
9
+ def batch_action(action, item_ids)
10
+ if batch_action?(action)
11
+ send("batch_action_#{action}", resource_class.find(item_ids))
12
+ true
13
+ else
14
+ false
15
+ end
16
+ end
17
+
18
+ def batch_action?(action)
19
+ batch_action_map.key?(action.to_sym)
20
+ end
21
+
22
+ module ClassMethods
23
+ def batch_action_map
24
+ @batch_action_map ||= {}
25
+ end
26
+
27
+ def batch_action(attr, options = {})
28
+ batch_action_map[attr] = {
29
+ only: nil,
30
+ except: nil,
31
+ confirm: false
32
+ }.merge(options)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,37 @@
1
+ module Godmin
2
+ module Resources
3
+ module ResourceService
4
+ module Filters
5
+ extend ActiveSupport::Concern
6
+
7
+ delegate :filter_map, to: "self.class"
8
+
9
+ def apply_filters(filter_params, resources)
10
+ if filter_params.present?
11
+ filter_params.each do |name, value|
12
+ if filter_map.key?(name.to_sym) && value.present?
13
+ resources = send("filter_#{name}", resources, value)
14
+ end
15
+ end
16
+ end
17
+ resources
18
+ end
19
+
20
+ module ClassMethods
21
+ def filter_map
22
+ @filter_map ||= {}
23
+ end
24
+
25
+ def filter(attr, options = {})
26
+ filter_map[attr] = {
27
+ as: :string,
28
+ option_text: "to_s",
29
+ option_value: "id",
30
+ collection: nil
31
+ }.merge(options)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,27 @@
1
+ module Godmin
2
+ module Resources
3
+ module ResourceService
4
+ module Ordering
5
+ extend ActiveSupport::Concern
6
+
7
+ def apply_order(order_param, resources)
8
+ if order_param.present?
9
+ resources.order("#{resource_class.table_name}.#{order_column(order_param)} #{order_direction(order_param)}")
10
+ else
11
+ resources
12
+ end
13
+ end
14
+
15
+ protected
16
+
17
+ def order_column(order_param)
18
+ order_param.rpartition("_").first
19
+ end
20
+
21
+ def order_direction(order_param)
22
+ order_param.rpartition("_").last
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ module Godmin
2
+ module Resources
3
+ module ResourceService
4
+ module Pagination
5
+ extend ActiveSupport::Concern
6
+
7
+ def apply_pagination(page_param, resources)
8
+ @paginator = Paginator.new(resources, per_page: per_page, current_page: page_param)
9
+ @paginator.paginate
10
+ end
11
+
12
+ def paginator
13
+ @paginator
14
+ end
15
+
16
+ def per_page
17
+ 25
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,61 @@
1
+ module Godmin
2
+ module Resources
3
+ module ResourceService
4
+ module Scopes
5
+ extend ActiveSupport::Concern
6
+
7
+ delegate :scope_map, to: "self.class"
8
+
9
+ def apply_scope(scope_param, resources)
10
+ return resources if scope_map.empty?
11
+
12
+ self.scope = scope_param
13
+
14
+ if scope && scope_map.key?(scope.to_sym)
15
+ send("scope_#{@scope}", resources)
16
+ else
17
+ fail NotImplementedError, "Scope #{@scope} not implemented"
18
+ end
19
+ end
20
+
21
+ def scope=(scope)
22
+ @scope = scope.blank? ? default_scope : scope
23
+ end
24
+
25
+ def scope
26
+ @scope
27
+ end
28
+
29
+ def scoped_by?(name)
30
+ @scope == name.to_s
31
+ end
32
+
33
+ def scope_count(scope)
34
+ send("scope_#{scope}", resources_relation).count
35
+ end
36
+
37
+ protected
38
+
39
+ def default_scope
40
+ scope = scope_map.find -> { scope_map.first } do |_key, value|
41
+ value[:default] == true
42
+ end
43
+
44
+ scope ? scope[0].to_s : nil
45
+ end
46
+
47
+ module ClassMethods
48
+ def scope_map
49
+ @scope_map ||= {}
50
+ end
51
+
52
+ def scope(attr, options = {})
53
+ scope_map[attr] = {
54
+ default: false
55
+ }.merge(options)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,3 +1,3 @@
1
1
  module Godmin
2
- VERSION = "0.10.3"
2
+ VERSION = "0.11.0"
3
3
  end
@@ -20,7 +20,7 @@ Dummy::Application.configure do
20
20
  # config.action_dispatch.rack_cache = true
21
21
 
22
22
  # Disable Rails's static asset server (Apache or nginx will already do this).
23
- config.serve_static_assets = false
23
+ config.serve_static_files = false
24
24
 
25
25
  # Compress JavaScripts and CSS.
26
26
  config.assets.js_compressor = :uglifier
@@ -13,7 +13,7 @@ Dummy::Application.configure do
13
13
  config.eager_load = false
14
14
 
15
15
  # Configure static asset server for tests with Cache-Control for performance.
16
- config.serve_static_assets = true
16
+ config.serve_static_files = true
17
17
  config.static_cache_control = "public, max-age=3600"
18
18
 
19
19
  # Show full error reports and disable caching.
@@ -0,0 +1,16 @@
1
+ # encoding: UTF-8
2
+ # This file is auto-generated from the current state of the database. Instead
3
+ # of editing this file, please use the migrations feature of Active Record to
4
+ # incrementally modify your database, and then regenerate this schema definition.
5
+ #
6
+ # Note that this schema.rb definition is the authoritative source for your
7
+ # database schema. If you need to create the application database on another
8
+ # system, you should be using db:schema:load, not running all the migrations
9
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
11
+ #
12
+ # It's strongly recommended that you check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(version: 0) do
15
+
16
+ end
@@ -0,0 +1,26 @@
1
+ require "test_helper"
2
+
3
+ module Godmin
4
+ module Helpers
5
+ class FiltersTest < ActionView::TestCase
6
+ include BootstrapForm::Helper
7
+ include Godmin::Helpers::Filters
8
+ include Godmin::Helpers::Translations
9
+
10
+ def test_filter_form_is_a_bootstrap_form_builder
11
+ filter_form url: "/" do |f|
12
+ assert f.is_a? BootstrapForm::FormBuilder
13
+ end
14
+ end
15
+
16
+ # TODO: actually implement this test properly, apparently
17
+ # assert_select can be used if the helper output is parsed
18
+ # with HTML::Document first...
19
+ def test_string_filter_field
20
+ form = filter_form url: "/" do |f|
21
+ f.filter_field :foo, as: :string
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,84 @@
1
+ require "test_helper"
2
+
3
+ module Godmin
4
+ class PaginatorTest < ActiveSupport::TestCase
5
+ def setup
6
+ resources_class = Class.new do
7
+ attr_reader :limit_param
8
+ attr_reader :offset_param
9
+
10
+ def count
11
+ 50
12
+ end
13
+
14
+ def limit(limit_param)
15
+ @limit_param = limit_param
16
+ self
17
+ end
18
+
19
+ def offset(offset_param)
20
+ @offset_param = offset_param
21
+ self
22
+ end
23
+ end
24
+
25
+ @resources = resources_class.new
26
+ end
27
+
28
+ def test_paginate
29
+ paginator = Paginator.new(@resources, per_page: 10, current_page: 1)
30
+
31
+ assert_equal @resources, paginator.paginate
32
+ assert_equal 10, @resources.limit_param
33
+ assert_equal 0, @resources.offset_param
34
+ end
35
+
36
+ def test_paginate_with_offset
37
+ paginator = Paginator.new(@resources, per_page: 10, current_page: 2)
38
+
39
+ assert_equal @resources, paginator.paginate
40
+ assert_equal 10, @resources.limit_param
41
+ assert_equal 10, @resources.offset_param
42
+ end
43
+
44
+ def test_current_page
45
+ paginator = Paginator.new(nil, current_page: 2)
46
+ assert_equal 2, paginator.current_page
47
+ end
48
+
49
+ def test_current_page_when_no_page
50
+ paginator = Paginator.new(nil)
51
+ assert_equal 1, paginator.current_page
52
+ end
53
+
54
+ def test_pages_when_pages_all_fit
55
+ paginator = Paginator.new(@resources, per_page: 10, current_page: 1)
56
+ assert_equal [1, 2, 3, 4, 5], paginator.pages
57
+ end
58
+
59
+ def test_pages_when_pages_dont_fit_and_on_first_page
60
+ paginator = Paginator.new(@resources, per_page: 2, current_page: 1)
61
+ assert_equal [1, 2, 3, 4, 5, 6, 7], paginator.pages
62
+ end
63
+
64
+ def test_pages_when_pages_dont_fit_and_on_middle_page
65
+ paginator = Paginator.new(@resources, per_page: 2, current_page: 7)
66
+ assert_equal [4, 5, 6, 7, 8, 9, 10], paginator.pages
67
+ end
68
+
69
+ def test_pages_when_pages_dont_fit_and_on_last_page
70
+ paginator = Paginator.new(@resources, per_page: 2, current_page: 25)
71
+ assert_equal [19, 20, 21, 22, 23, 24, 25], paginator.pages
72
+ end
73
+
74
+ def test_total_pages
75
+ paginator = Paginator.new(@resources, per_page: 10)
76
+ assert_equal 5, paginator.total_pages
77
+ end
78
+
79
+ def test_total_resources
80
+ paginator = Paginator.new(@resources)
81
+ assert_equal 50, paginator.total_resources
82
+ end
83
+ end
84
+ end
@@ -1,28 +1,57 @@
1
1
  require "test_helper"
2
2
 
3
- class Article; extend ActiveModel::Naming; end
3
+ module Namespace
4
+ class ArticlePolicyTestPolicy; end
5
+ class ObjectPolicy; end
6
+ end
7
+
8
+ class ArticlePolicyTest; extend ActiveModel::Naming; end
9
+ class OverriddenPolicyTest
10
+ extend ActiveModel::Naming
11
+ def self.policy_class
12
+ Namespace::ObjectPolicy
13
+ end
14
+
15
+ def policy_class
16
+ Namespace::ObjectPolicy
17
+ end
18
+ end
4
19
 
5
20
  module Godmin
6
21
  module Authorization
7
22
  class PolicyFinderTest < ActiveSupport::TestCase
8
23
  def test_find_by_model
9
24
  namespaced_as "namespace" do
10
- policy = PolicyFinder.find(Article)
11
- assert_equal "Namespace::ArticlePolicy", policy
25
+ policy = PolicyFinder.find(ArticlePolicyTest)
26
+ assert_equal Namespace::ArticlePolicyTestPolicy, policy
12
27
  end
13
28
  end
14
29
 
15
30
  def test_find_by_class
16
31
  namespaced_as "namespace" do
17
32
  policy = PolicyFinder.find(Object)
18
- assert_equal "Namespace::ObjectPolicy", policy
33
+ assert_equal Namespace::ObjectPolicy, policy
19
34
  end
20
35
  end
21
36
 
22
37
  def test_find_by_symbol
23
38
  namespaced_as "namespace" do
24
- policy = PolicyFinder.find(:article)
25
- assert_equal "Namespace::ArticlePolicy", policy
39
+ policy = PolicyFinder.find(:article_policy_test)
40
+ assert_equal Namespace::ArticlePolicyTestPolicy, policy
41
+ end
42
+ end
43
+
44
+ def test_override_policy_class_on_class
45
+ namespaced_as "namespace" do
46
+ policy = PolicyFinder.find(OverriddenPolicyTest)
47
+ assert_equal Namespace::ObjectPolicy, policy
48
+ end
49
+ end
50
+
51
+ def test_override_policy_class_on_instance
52
+ namespaced_as "namespace" do
53
+ policy = PolicyFinder.find(OverriddenPolicyTest.new)
54
+ assert_equal Namespace::ObjectPolicy, policy
26
55
  end
27
56
  end
28
57
  end