godmin 0.10.3 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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