padrino-admin 0.16.2 → 0.18.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 (129) hide show
  1. checksums.yaml +4 -4
  2. data/README.rdoc +3 -3
  3. data/Rakefile +0 -21
  4. data/lib/padrino-admin/access_control.rb +17 -4
  5. data/lib/padrino-admin/generators/actions.rb +1 -1
  6. data/lib/padrino-admin/generators/admin_app.rb +9 -11
  7. data/lib/padrino-admin/generators/admin_page.rb +12 -2
  8. data/lib/padrino-admin/generators/orm.rb +30 -47
  9. data/lib/padrino-admin/generators/templates/account/seeds.rb.tt +7 -2
  10. data/lib/padrino-admin/generators/templates/app/controllers/sessions.rb.tt +0 -4
  11. data/lib/padrino-admin/generators/templates/app.rb.tt +4 -1
  12. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/affix.js +63 -36
  13. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/alert.js +18 -11
  14. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/bootstrap.min.js +4 -4
  15. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/button.js +41 -23
  16. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/carousel.js +90 -49
  17. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/collapse.js +86 -44
  18. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/dropdown.js +66 -48
  19. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/modal.js +167 -52
  20. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/popover.js +33 -20
  21. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/scrollspy.js +58 -39
  22. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/tab.js +55 -25
  23. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/tooltip.js +370 -92
  24. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/transition.js +22 -11
  25. data/lib/padrino-admin/generators/templates/assets/javascripts/jquery-3.7.1.min.js +2 -0
  26. data/lib/padrino-admin/generators/templates/assets/stylesheets/application.css +14 -0
  27. data/lib/padrino-admin/generators/templates/assets/stylesheets/bootstrap.css +6 -4
  28. data/lib/padrino-admin/generators/templates/erb/app/base/index.erb.tt +1 -1
  29. data/lib/padrino-admin/generators/templates/erb/app/layouts/application.erb.tt +1 -1
  30. data/lib/padrino-admin/generators/templates/erb/app/sessions/new.erb.tt +1 -1
  31. data/lib/padrino-admin/generators/templates/erb/page/index.erb.tt +2 -2
  32. data/lib/padrino-admin/generators/templates/haml/app/base/index.haml.tt +1 -1
  33. data/lib/padrino-admin/generators/templates/haml/app/layouts/application.haml.tt +1 -1
  34. data/lib/padrino-admin/generators/templates/haml/app/sessions/new.haml.tt +1 -1
  35. data/lib/padrino-admin/generators/templates/slim/app/base/index.slim.tt +1 -1
  36. data/lib/padrino-admin/generators/templates/slim/app/layouts/application.slim.tt +1 -1
  37. data/lib/padrino-admin/generators/templates/slim/app/sessions/new.slim.tt +1 -1
  38. data/lib/padrino-admin/generators/templates/slim/page/index.slim.tt +2 -2
  39. data/lib/padrino-admin/helpers/authentication_helpers.rb +1 -1
  40. data/lib/padrino-admin/helpers/view_helpers.rb +3 -3
  41. data/lib/padrino-admin/locale/orm/pl.yml +0 -11
  42. data/lib/padrino-admin.rb +1 -1
  43. data/padrino-admin.gemspec +0 -2
  44. data/test/generators/test_account_model_generator.rb +1 -60
  45. data/test/generators/test_admin_app_generator.rb +159 -25
  46. data/test/generators/test_admin_page_generator.rb +110 -9
  47. data/test/test_admin_application.rb +123 -0
  48. metadata +9 -124
  49. data/lib/padrino-admin/bootstrap-less/alerts.less +0 -67
  50. data/lib/padrino-admin/bootstrap-less/badges.less +0 -55
  51. data/lib/padrino-admin/bootstrap-less/bootstrap.less +0 -49
  52. data/lib/padrino-admin/bootstrap-less/breadcrumbs.less +0 -26
  53. data/lib/padrino-admin/bootstrap-less/button-groups.less +0 -226
  54. data/lib/padrino-admin/bootstrap-less/buttons.less +0 -155
  55. data/lib/padrino-admin/bootstrap-less/carousel.less +0 -232
  56. data/lib/padrino-admin/bootstrap-less/close.less +0 -33
  57. data/lib/padrino-admin/bootstrap-less/code.less +0 -63
  58. data/lib/padrino-admin/bootstrap-less/component-animations.less +0 -29
  59. data/lib/padrino-admin/bootstrap-less/dropdowns.less +0 -213
  60. data/lib/padrino-admin/bootstrap-less/font-awesome/bordered-pulled.less +0 -16
  61. data/lib/padrino-admin/bootstrap-less/font-awesome/core.less +0 -12
  62. data/lib/padrino-admin/bootstrap-less/font-awesome/fixed-width.less +0 -6
  63. data/lib/padrino-admin/bootstrap-less/font-awesome/font-awesome.less +0 -17
  64. data/lib/padrino-admin/bootstrap-less/font-awesome/icons.less +0 -412
  65. data/lib/padrino-admin/bootstrap-less/font-awesome/larger.less +0 -13
  66. data/lib/padrino-admin/bootstrap-less/font-awesome/list.less +0 -19
  67. data/lib/padrino-admin/bootstrap-less/font-awesome/mixins.less +0 -20
  68. data/lib/padrino-admin/bootstrap-less/font-awesome/path.less +0 -14
  69. data/lib/padrino-admin/bootstrap-less/font-awesome/rotated-flipped.less +0 -9
  70. data/lib/padrino-admin/bootstrap-less/font-awesome/spinning.less +0 -30
  71. data/lib/padrino-admin/bootstrap-less/font-awesome/stacked.less +0 -20
  72. data/lib/padrino-admin/bootstrap-less/font-awesome/variables.less +0 -381
  73. data/lib/padrino-admin/bootstrap-less/forms.less +0 -419
  74. data/lib/padrino-admin/bootstrap-less/glyphicons.less +0 -233
  75. data/lib/padrino-admin/bootstrap-less/grid.less +0 -100
  76. data/lib/padrino-admin/bootstrap-less/input-groups.less +0 -157
  77. data/lib/padrino-admin/bootstrap-less/jumbotron.less +0 -44
  78. data/lib/padrino-admin/bootstrap-less/labels.less +0 -64
  79. data/lib/padrino-admin/bootstrap-less/list-group.less +0 -110
  80. data/lib/padrino-admin/bootstrap-less/media.less +0 -56
  81. data/lib/padrino-admin/bootstrap-less/mixins.less +0 -926
  82. data/lib/padrino-admin/bootstrap-less/modals.less +0 -138
  83. data/lib/padrino-admin/bootstrap-less/navbar.less +0 -616
  84. data/lib/padrino-admin/bootstrap-less/navs.less +0 -242
  85. data/lib/padrino-admin/bootstrap-less/normalize.less +0 -423
  86. data/lib/padrino-admin/bootstrap-less/padrino-admin.less +0 -18
  87. data/lib/padrino-admin/bootstrap-less/pager.less +0 -55
  88. data/lib/padrino-admin/bootstrap-less/pagination.less +0 -88
  89. data/lib/padrino-admin/bootstrap-less/panels.less +0 -230
  90. data/lib/padrino-admin/bootstrap-less/popovers.less +0 -133
  91. data/lib/padrino-admin/bootstrap-less/print.less +0 -101
  92. data/lib/padrino-admin/bootstrap-less/progress-bars.less +0 -80
  93. data/lib/padrino-admin/bootstrap-less/responsive-utilities.less +0 -93
  94. data/lib/padrino-admin/bootstrap-less/scaffolding.less +0 -134
  95. data/lib/padrino-admin/bootstrap-less/tables.less +0 -233
  96. data/lib/padrino-admin/bootstrap-less/theme.less +0 -247
  97. data/lib/padrino-admin/bootstrap-less/thumbnails.less +0 -36
  98. data/lib/padrino-admin/bootstrap-less/tooltip.less +0 -95
  99. data/lib/padrino-admin/bootstrap-less/type.less +0 -296
  100. data/lib/padrino-admin/bootstrap-less/utilities.less +0 -56
  101. data/lib/padrino-admin/bootstrap-less/variables.less +0 -827
  102. data/lib/padrino-admin/bootstrap-less/wells.less +0 -29
  103. data/lib/padrino-admin/generators/templates/account/couchrest.rb.tt +0 -67
  104. data/lib/padrino-admin/generators/templates/account/datamapper.rb.tt +0 -61
  105. data/lib/padrino-admin/generators/templates/account/dynamoid.rb.tt +0 -55
  106. data/lib/padrino-admin/generators/templates/account/minirecord.rb.tt +0 -44
  107. data/lib/padrino-admin/generators/templates/account/mongomapper.rb.tt +0 -47
  108. data/lib/padrino-admin/generators/templates/account/ohm.rb.tt +0 -70
  109. data/lib/padrino-admin/generators/templates/assets/javascripts/jquery-1.11.0.min.js +0 -4
  110. data/lib/padrino-admin/locale/orm/cs.yml +0 -12
  111. data/lib/padrino-admin/locale/orm/da.yml +0 -12
  112. data/lib/padrino-admin/locale/orm/de.yml +0 -12
  113. data/lib/padrino-admin/locale/orm/en.yml +0 -12
  114. data/lib/padrino-admin/locale/orm/es.yml +0 -12
  115. data/lib/padrino-admin/locale/orm/fr.yml +0 -12
  116. data/lib/padrino-admin/locale/orm/hu.yml +0 -12
  117. data/lib/padrino-admin/locale/orm/it.yml +0 -12
  118. data/lib/padrino-admin/locale/orm/ja.yml +0 -12
  119. data/lib/padrino-admin/locale/orm/lv.yml +0 -12
  120. data/lib/padrino-admin/locale/orm/nl.yml +0 -12
  121. data/lib/padrino-admin/locale/orm/no.yml +0 -12
  122. data/lib/padrino-admin/locale/orm/pt_br.yml +0 -12
  123. data/lib/padrino-admin/locale/orm/ro.yml +0 -12
  124. data/lib/padrino-admin/locale/orm/ru.yml +0 -12
  125. data/lib/padrino-admin/locale/orm/sv.yml +0 -12
  126. data/lib/padrino-admin/locale/orm/tr.yml +0 -12
  127. data/lib/padrino-admin/locale/orm/uk.yml +0 -12
  128. data/lib/padrino-admin/locale/orm/zh_cn.yml +0 -12
  129. data/lib/padrino-admin/locale/orm/zh_tw.yml +0 -12
@@ -1,5 +1,6 @@
1
1
  require_relative '../helper'
2
2
  require_relative '../fixtures/sequel'
3
+ require 'nokogiri'
3
4
 
4
5
  describe 'AdminPageGenerator' do
5
6
  before do
@@ -13,21 +14,99 @@ describe 'AdminPageGenerator' do
13
14
 
14
15
  describe 'the admin page generator' do
15
16
  it 'should fail outside app root' do
16
- out, = capture_io { generate(:admin_page, 'foo', "-r=#{@apptmp}/sample_project") }
17
+ out, = capture_io { assert_equal 1, assert_raises(SystemExit) { generate(:admin_page, 'foo', "-r=#{@apptmp}/sample_project") }.status }
17
18
  assert_match(/not at the root/, out)
18
19
  assert_no_file_exists("#{@apptmp}/admin")
19
20
  end
20
21
 
22
+ it 'should fail when the admin app does not exist' do
23
+ capture_io { generate(:project, 'sample_project', '-e=slim', "--root=#{@apptmp}", '-d=sequel') }
24
+ out, = capture_io { assert_equal 1, assert_raises(SystemExit) { generate(:admin_page, 'friend', "-r=#{@apptmp}/sample_project") }.status }
25
+ assert_match(/Unable to locate 'Admin' application/, out)
26
+ assert_no_dir_exists("#{@apptmp}/sample_project/admin")
27
+ end
28
+
29
+ %w[minirecord ohm].each do |removed_orm|
30
+ it "should fail without writing anything when the project orm is no longer supported (#{removed_orm})" do
31
+ capture_io { generate(:project, 'sample_project', '-e=slim', "--root=#{@apptmp}", '-d=activerecord') }
32
+ capture_io { generate(:admin_app, "--root=#{@apptmp}/sample_project") }
33
+ components = "#{@apptmp}/sample_project/.components"
34
+ File.write(components, File.read(components).sub(':orm: activerecord', ":orm: #{removed_orm}"))
35
+ out, = capture_io { assert_equal 1, assert_raises(SystemExit) { generate(:admin_page, 'friend', "-r=#{@apptmp}/sample_project") }.status }
36
+ assert_match(/only supports activerecord or mongoid or sequel\. Sorry!/, out)
37
+ assert_no_dir_exists("#{@apptmp}/sample_project/admin/views/friends")
38
+ end
39
+ end
40
+
21
41
  it 'should fail without an existent model' do
22
42
  capture_io { generate(:project, 'sample_project', '-e=slim', "--root=#{@apptmp}", '-d=activerecord') }
23
43
  capture_io { generate(:admin_app, "--root=#{@apptmp}/sample_project") }
24
- assert_raises(Padrino::Admin::Generators::OrmError) { generate(:admin_page, 'foo', "-r=#{@apptmp}/sample_project") }
44
+ _, err = capture_io { assert_equal 1, assert_raises(SystemExit) { generate(:admin_page, 'foo', "-r=#{@apptmp}/sample_project") }.status }
45
+ assert_match(/Model 'Foo' could not be found/, err)
46
+ assert_no_dir_exists("#{@apptmp}/sample_project/admin/views/foos")
47
+ assert_no_file_exists("#{@apptmp}/sample_project/admin/controllers/foos.rb")
48
+ assert_no_match_in_file(/project_module :foos/, "#{@apptmp}/sample_project/admin/app.rb")
49
+ end
50
+
51
+ %w[erb haml slim].each do |renderer|
52
+ it "should destroy pages whose models were already removed (#{renderer})" do
53
+ Object.const_set(:GoneWidget, Class.new(Sequel::Model(:friends)))
54
+ Object.const_set(:GoneGadget, Class.new(Sequel::Model(:pages)))
55
+ capture_io { generate(:project, 'sample_project', "--root=#{@apptmp}", '-d=sequel', "-e=#{renderer}") }
56
+ capture_io { generate(:admin_app, "--root=#{@apptmp}/sample_project") }
57
+ capture_io { generate(:admin_page, 'gone_widget', 'gone_gadget', "--root=#{@apptmp}/sample_project") }
58
+ admin = "#{@apptmp}/sample_project/admin"
59
+ assert_file_exists("#{admin}/views/gone_widgets/index.#{renderer}")
60
+ assert_match_in_file("role.project_module :gone_gadgets, '/gone_gadgets'", "#{admin}/app.rb")
61
+
62
+ Object.send(:remove_const, :GoneWidget)
63
+ Object.send(:remove_const, :GoneGadget)
64
+ status = nil
65
+ _, err = capture_io do
66
+ generate(:admin_page, 'gone_widget', 'gone_gadget', "--root=#{@apptmp}/sample_project", '-d')
67
+ rescue SystemExit => e
68
+ status = e.status
69
+ end
70
+ assert_nil status, err
71
+ %w[gone_widgets gone_gadgets].each do |page|
72
+ assert_no_file_exists("#{admin}/controllers/#{page}.rb")
73
+ assert_no_dir_exists("#{admin}/views/#{page}")
74
+ assert_no_match_in_file(/project_module :#{page}/, "#{admin}/app.rb")
75
+ end
76
+ assert_match_in_file("role.project_module :accounts, '/accounts'", "#{admin}/app.rb")
77
+ ensure
78
+ Object.send(:remove_const, :GoneWidget) if Object.const_defined?(:GoneWidget, false)
79
+ Object.send(:remove_const, :GoneGadget) if Object.const_defined?(:GoneGadget, false)
80
+ end
81
+ end
82
+
83
+ it 'should fail when the model does not match the project orm' do
84
+ capture_io { generate(:project, 'sample_project', '-e=slim', "--root=#{@apptmp}", '-d=activerecord') }
85
+ capture_io { generate(:admin_app, "--root=#{@apptmp}/sample_project") }
86
+ _, err = capture_io { assert_equal 1, assert_raises(SystemExit) { generate(:admin_page, 'friend', "-r=#{@apptmp}/sample_project") }.status }
87
+ assert_match(/Friend.*activerecord/m, err)
88
+ end
89
+
90
+ it 'should destroy a page even when the model does not match the project orm' do
91
+ capture_io { generate(:project, 'sample_project', '-e=slim', "--root=#{@apptmp}", '-d=activerecord') }
92
+ capture_io { generate(:admin_app, "--root=#{@apptmp}/sample_project") }
93
+ FileUtils.mkdir_p("#{@apptmp}/sample_project/admin/views/friends")
94
+ capture_io { generate(:admin_page, 'friend', "-r=#{@apptmp}/sample_project", '-d') }
95
+ assert_no_dir_exists("#{@apptmp}/sample_project/admin/views/friends")
96
+ end
97
+
98
+ it 'should fail when the project has no orm and the model is not activerecord' do
99
+ capture_io { generate(:project, 'sample_project', '-e=slim', "--root=#{@apptmp}", '-d=sequel') }
100
+ capture_io { generate(:admin_app, "--root=#{@apptmp}/sample_project") }
101
+ components = "#{@apptmp}/sample_project/.components"
102
+ File.write(components, File.read(components).sub(/^:orm:.*\n/, ''))
103
+ _, err = capture_io { assert_equal 1, assert_raises(SystemExit) { generate(:admin_page, 'friend', "-r=#{@apptmp}/sample_project") }.status }
104
+ assert_match(/not based on/, err)
25
105
  end
26
106
 
27
107
  it 'should correctly generate a new page' do
28
108
  capture_io { generate(:project, 'sample_project', '-e=slim', "--root=#{@apptmp}", '-d=sequel', '-e=haml') }
29
109
  capture_io { generate(:admin_app, "--root=#{@apptmp}/sample_project") }
30
- capture_io { generate(:model, 'friend', 'name:string', 'age:integer', 'email:string', "--root=#{@apptmp}/sample_project") }
31
110
  capture_io { generate(:admin_page, 'friend', "--root=#{@apptmp}/sample_project") }
32
111
  assert_file_exists "#{@apptmp}/sample_project/admin/controllers/friends.rb"
33
112
  assert_match_in_file 'SampleProject::Admin.controllers :friends do', "#{@apptmp}/sample_project/admin/controllers/friends.rb"
@@ -41,7 +120,6 @@ describe 'AdminPageGenerator' do
41
120
  custom_template_path = "#{@apptmp}/sample_project/generators/templates/haml/page/"
42
121
  `mkdir -p #{custom_template_path} && echo "%h1= 'Hello, custom generator' " > #{custom_template_path}index.haml.tt`
43
122
  capture_io { generate(:admin_app, "--root=#{@apptmp}/sample_project") }
44
- capture_io { generate(:model, 'friend', 'name:string', 'age:integer', 'email:string', "--root=#{@apptmp}/sample_project") }
45
123
  capture_io { generate(:admin_page, 'friend', "--root=#{@apptmp}/sample_project") }
46
124
  assert_match_in_file(/Hello, custom generator/, "#{@apptmp}/sample_project/admin/views/friends/index.haml")
47
125
  end
@@ -50,7 +128,6 @@ describe 'AdminPageGenerator' do
50
128
  it 'should correctly generate a new page with haml' do
51
129
  capture_io { generate(:project, 'sample_project', '-e=slim', "--root=#{@apptmp}", '-d=sequel', '-e=haml') }
52
130
  capture_io { generate(:admin_app, "--root=#{@apptmp}/sample_project") }
53
- capture_io { generate(:model, 'friend', 'name:string', 'age:integer', 'email:string', "--root=#{@apptmp}/sample_project") }
54
131
  capture_io { generate(:admin_page, 'friend', "--root=#{@apptmp}/sample_project") }
55
132
  assert_file_exists "#{@apptmp}/sample_project/admin/views/friends/_form.haml"
56
133
  assert_file_exists "#{@apptmp}/sample_project/admin/views/friends/edit.haml"
@@ -66,7 +143,6 @@ describe 'AdminPageGenerator' do
66
143
  it 'should correctly generate a new page with erb' do
67
144
  capture_io { generate(:project, 'sample_project', '-e=slim', "--root=#{@apptmp}", '-d=sequel', '-e=erb') }
68
145
  capture_io { generate(:admin_app, "--root=#{@apptmp}/sample_project") }
69
- capture_io { generate(:model, 'friend', 'name:string', 'age:integer', 'email:string', "--root=#{@apptmp}/sample_project") }
70
146
  capture_io { generate(:admin_page, 'friend', "--root=#{@apptmp}/sample_project") }
71
147
  assert_file_exists "#{@apptmp}/sample_project/admin/views/friends/_form.erb"
72
148
  assert_file_exists "#{@apptmp}/sample_project/admin/views/friends/edit.erb"
@@ -82,7 +158,6 @@ describe 'AdminPageGenerator' do
82
158
  it 'should correctly generate a new page with slim' do
83
159
  capture_io { generate(:project, 'sample_project', '-e=slim', "--root=#{@apptmp}", '-d=sequel', '-e=slim') }
84
160
  capture_io { generate(:admin_app, "--root=#{@apptmp}/sample_project") }
85
- capture_io { generate(:model, 'friend', 'name:string', 'age:integer', 'email:string', "--root=#{@apptmp}/sample_project") }
86
161
  capture_io { generate(:admin_page, 'friend', "--root=#{@apptmp}/sample_project") }
87
162
  assert_file_exists "#{@apptmp}/sample_project/admin/views/friends/_form.slim"
88
163
  assert_file_exists "#{@apptmp}/sample_project/admin/views/friends/edit.slim"
@@ -96,11 +171,37 @@ describe 'AdminPageGenerator' do
96
171
  end
97
172
  end
98
173
 
174
+ %w[erb haml slim].each do |renderer|
175
+ it "should render the list menu with the same classes as the stylesheet and script expect (#{renderer})" do
176
+ capture_io { generate(:project, 'sample_project', "--root=#{@apptmp}", '-d=sequel', "-e=#{renderer}") }
177
+ capture_io { generate(:admin_app, "--root=#{@apptmp}/sample_project") }
178
+ capture_io { generate(:admin_page, 'friend', "--root=#{@apptmp}/sample_project") }
179
+ views = "#{@apptmp}/sample_project/admin/views"
180
+ mock_app do
181
+ set :views, views
182
+ helpers Padrino::Admin::Helpers::ViewHelpers
183
+ controllers :friends do
184
+ get(:index) { @friends = []; render 'friends/index', layout: false }
185
+ get(:new) {}
186
+ delete(:destroy_many) {}
187
+ end
188
+ end
189
+ get '/friends'
190
+ assert_equal 200, last_response.status
191
+ page = Nokogiri::HTML(last_response.body)
192
+ classes = ->(node) { node['class'].split }
193
+ assert_equal %w[list-menu-toggle dropdown-toggle], classes.call(page.at_css('[data-toggle=dropdown]'))
194
+ assert_equal 'menu', page.at_css('ul.dropdown-menu')['role']
195
+ assert_equal %w[list-menu-wrapper], classes.call(page.at_css('#select-all').parent)
196
+ %w[#deselect-all #delete-selected].each do |link|
197
+ assert_equal %w[list-menu-wrapper list-menu-wrapper-disabled], classes.call(page.at_css(link).parent)
198
+ end
199
+ end
200
+ end
201
+
99
202
  it 'should correctly generate a new padrino admin application with multiple models at the same time' do
100
203
  capture_io { generate(:project, 'sample_project', '-e=slim', "--root=#{@apptmp}", '-d=sequel', '-e=haml') }
101
204
  capture_io { generate(:admin_app, "--root=#{@apptmp}/sample_project") }
102
- capture_io { generate(:model, 'friend', 'name:string', 'age:integer', 'email:string', "-root=#{@apptmp}/sample_project") }
103
- capture_io { generate(:model, 'page', 'name:string', 'body:string', "-root=#{@apptmp}/sample_project") }
104
205
  capture_io { generate(:admin_page, 'friend', 'page', "--root=#{@apptmp}/sample_project") }
105
206
  # For Friend
106
207
  assert_file_exists "#{@apptmp}/sample_project/admin/controllers/friends.rb"
@@ -163,6 +163,118 @@ describe 'AdminApplication' do
163
163
  assert_equal 'posts', body
164
164
  end
165
165
 
166
+ it 'should match paths literally without regex metacharacter interpretation' do
167
+ mock_app do
168
+ register Padrino::Admin::AccessControl
169
+ enable :sessions
170
+
171
+ access_control.roles_for :any do |role|
172
+ role.protect '/'
173
+ role.allow '/accounts.json'
174
+ end
175
+ end
176
+
177
+ # Without authentication, /accounts.json should be allowed
178
+ assert @app.access_control.allowed?(nil, '/accounts.json')
179
+ # /accountsXjson must NOT match - the dot in .json is literal, not a regex wildcard
180
+ refute @app.access_control.allowed?(nil, '/accountsXjson')
181
+ end
182
+
183
+ it 'should not allow paths that merely start with an allowed path' do
184
+ mock_app do
185
+ register Padrino::Admin::AccessControl
186
+ enable :sessions
187
+
188
+ access_control.roles_for :any do |role|
189
+ role.protect '/'
190
+ role.allow '/sessions'
191
+ end
192
+
193
+ access_control.roles_for :editor do |role|
194
+ role.project_module :posts, '/posts'
195
+ end
196
+
197
+ access_control.roles_for :admin do |role|
198
+ role.project_module :post_admin, '/posts_admin'
199
+ end
200
+ end
201
+
202
+ assert @app.access_control.allowed?(nil, '/sessions')
203
+ assert @app.access_control.allowed?(nil, '/sessions/new')
204
+ assert @app.access_control.allowed?(nil, '/sessions.json')
205
+ refute @app.access_control.allowed?(nil, '/sessions_admin')
206
+ refute @app.access_control.allowed?(nil, '/sessionsX')
207
+
208
+ # An editor's '/posts' must not reach the admin-only '/posts_admin' module.
209
+ assert @app.access_control.allowed?(Account.editor, '/posts')
210
+ assert @app.access_control.allowed?(Account.editor, '/posts/1/edit')
211
+ refute @app.access_control.allowed?(Account.editor, '/posts_admin')
212
+ assert @app.access_control.allowed?(Account.admin, '/posts_admin')
213
+
214
+ # Paths are compared after percent-decoding.
215
+ refute @app.access_control.allowed?(Account.editor, '/%70osts_admin')
216
+ assert @app.access_control.allowed?(Account.editor, '/%70osts')
217
+ end
218
+
219
+ it 'should allow decoded non-ASCII paths and prefixes ending in a dot' do
220
+ mock_app do
221
+ register Padrino::Admin::AccessControl
222
+ enable :sessions
223
+
224
+ access_control.roles_for :any do |role|
225
+ role.protect '/'
226
+ role.allow '/café'
227
+ role.allow '/v1.'
228
+ end
229
+ end
230
+
231
+ assert @app.access_control.allowed?(nil, '/caf%C3%A9'.b)
232
+ assert @app.access_control.allowed?(nil, '/café')
233
+ assert @app.access_control.allowed?(nil, '/v1.json')
234
+ refute @app.access_control.allowed?(nil, '/v2.json')
235
+ end
236
+
237
+ it 'should match Regexp paths at the start of the path' do
238
+ mock_app do
239
+ register Padrino::Admin::AccessControl
240
+ enable :sessions
241
+
242
+ access_control.roles_for :any do |role|
243
+ role.protect %r{\A/secret}
244
+ role.allow %r{\A/reports/\d+\z}
245
+ end
246
+
247
+ access_control.roles_for :admin do |role|
248
+ role.allow %r{\A/stats}
249
+ role.project_module :posts, '/posts'
250
+ end
251
+ end
252
+
253
+ assert @app.access_control.allowed?(nil, '/reports/1')
254
+ refute @app.access_control.allowed?(nil, '/secret/x')
255
+ assert @app.access_control.allowed?(Account.admin, '/stats/today')
256
+ assert @app.access_control.allowed?(Account.admin, '/posts')
257
+ refute @app.access_control.allowed?(Account.editor, '/stats')
258
+ end
259
+
260
+ it 'should check paths that are not valid UTF-8 once decoded' do
261
+ mock_app do
262
+ register Padrino::Admin::AccessControl
263
+ enable :sessions
264
+
265
+ access_control.roles_for :any do |role|
266
+ role.protect %r{\A/secret}
267
+ role.protect '/reports'
268
+ role.allow %r{\A/reports/\d+\z}
269
+ end
270
+ end
271
+
272
+ refute @app.access_control.allowed?(nil, '/secret%ff')
273
+ refute @app.access_control.allowed?(nil, '/reports/%c0%ae')
274
+ assert @app.access_control.allowed?(nil, '/reports/1')
275
+ assert @app.access_control.allowed?(nil, '/public/%ff')
276
+ end
277
+
166
278
  it 'should emulate an ecommerce app' do
167
279
  mock_app do
168
280
  register Padrino::Admin::AccessControl
@@ -282,4 +394,15 @@ describe 'AdminApplication' do
282
394
  assert_equal '/foo', app1.access_control.project_modules(:any).first.path
283
395
  assert_equal '/bar', app2.access_control.project_modules(:any).first.path
284
396
  end
397
+
398
+ it 'should raise AccessControlError for invalid roles' do
399
+ access_control = Padrino::Admin::AccessControl::Base.new
400
+ error = assert_raises(Padrino::Admin::AccessControlError) { access_control.roles_for('admin') }
401
+ assert_match(/"admin"/, error.message)
402
+ assert_raises(Padrino::Admin::AccessControlError) { access_control.roles_for }
403
+ end
404
+
405
+ it 'should humanize project module names without ActiveSupport' do
406
+ assert_equal 'Blog posts', Padrino::Admin::AccessControl::ProjectModule.new(:blog_posts, '/blog_posts').human_name
407
+ end
285
408
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: padrino-admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.2
4
+ version: 0.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Padrino Team
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2026-10-14 00:00:00.000000000 Z
14
+ date: 2026-10-31 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: padrino-core
@@ -19,56 +19,28 @@ dependencies:
19
19
  requirements:
20
20
  - - '='
21
21
  - !ruby/object:Gem::Version
22
- version: 0.16.2
22
+ version: 0.18.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - '='
28
28
  - !ruby/object:Gem::Version
29
- version: 0.16.2
29
+ version: 0.18.0
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: padrino-helpers
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  requirements:
34
34
  - - '='
35
35
  - !ruby/object:Gem::Version
36
- version: 0.16.2
36
+ version: 0.18.0
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - '='
42
42
  - !ruby/object:Gem::Version
43
- version: 0.16.2
44
- - !ruby/object:Gem::Dependency
45
- name: therubyracer
46
- requirement: !ruby/object:Gem::Requirement
47
- requirements:
48
- - - "~>"
49
- - !ruby/object:Gem::Version
50
- version: 0.11.1
51
- type: :development
52
- prerelease: false
53
- version_requirements: !ruby/object:Gem::Requirement
54
- requirements:
55
- - - "~>"
56
- - !ruby/object:Gem::Version
57
- version: 0.11.1
58
- - !ruby/object:Gem::Dependency
59
- name: less
60
- requirement: !ruby/object:Gem::Requirement
61
- requirements:
62
- - - "~>"
63
- - !ruby/object:Gem::Version
64
- version: 2.2.2
65
- type: :development
66
- prerelease: false
67
- version_requirements: !ruby/object:Gem::Requirement
68
- requirements:
69
- - - "~>"
70
- - !ruby/object:Gem::Version
71
- version: 2.2.2
43
+ version: 0.18.0
72
44
  description: Admin View for Padrino applications
73
45
  email: padrinorb@gmail.com
74
46
  executables: []
@@ -84,72 +56,12 @@ files:
84
56
  - Rakefile
85
57
  - lib/padrino-admin.rb
86
58
  - lib/padrino-admin/access_control.rb
87
- - lib/padrino-admin/bootstrap-less/alerts.less
88
- - lib/padrino-admin/bootstrap-less/badges.less
89
- - lib/padrino-admin/bootstrap-less/bootstrap.less
90
- - lib/padrino-admin/bootstrap-less/breadcrumbs.less
91
- - lib/padrino-admin/bootstrap-less/button-groups.less
92
- - lib/padrino-admin/bootstrap-less/buttons.less
93
- - lib/padrino-admin/bootstrap-less/carousel.less
94
- - lib/padrino-admin/bootstrap-less/close.less
95
- - lib/padrino-admin/bootstrap-less/code.less
96
- - lib/padrino-admin/bootstrap-less/component-animations.less
97
- - lib/padrino-admin/bootstrap-less/dropdowns.less
98
- - lib/padrino-admin/bootstrap-less/font-awesome/bordered-pulled.less
99
- - lib/padrino-admin/bootstrap-less/font-awesome/core.less
100
- - lib/padrino-admin/bootstrap-less/font-awesome/fixed-width.less
101
- - lib/padrino-admin/bootstrap-less/font-awesome/font-awesome.less
102
- - lib/padrino-admin/bootstrap-less/font-awesome/icons.less
103
- - lib/padrino-admin/bootstrap-less/font-awesome/larger.less
104
- - lib/padrino-admin/bootstrap-less/font-awesome/list.less
105
- - lib/padrino-admin/bootstrap-less/font-awesome/mixins.less
106
- - lib/padrino-admin/bootstrap-less/font-awesome/path.less
107
- - lib/padrino-admin/bootstrap-less/font-awesome/rotated-flipped.less
108
- - lib/padrino-admin/bootstrap-less/font-awesome/spinning.less
109
- - lib/padrino-admin/bootstrap-less/font-awesome/stacked.less
110
- - lib/padrino-admin/bootstrap-less/font-awesome/variables.less
111
- - lib/padrino-admin/bootstrap-less/forms.less
112
- - lib/padrino-admin/bootstrap-less/glyphicons.less
113
- - lib/padrino-admin/bootstrap-less/grid.less
114
- - lib/padrino-admin/bootstrap-less/input-groups.less
115
- - lib/padrino-admin/bootstrap-less/jumbotron.less
116
- - lib/padrino-admin/bootstrap-less/labels.less
117
- - lib/padrino-admin/bootstrap-less/list-group.less
118
- - lib/padrino-admin/bootstrap-less/media.less
119
- - lib/padrino-admin/bootstrap-less/mixins.less
120
- - lib/padrino-admin/bootstrap-less/modals.less
121
- - lib/padrino-admin/bootstrap-less/navbar.less
122
- - lib/padrino-admin/bootstrap-less/navs.less
123
- - lib/padrino-admin/bootstrap-less/normalize.less
124
- - lib/padrino-admin/bootstrap-less/padrino-admin.less
125
- - lib/padrino-admin/bootstrap-less/pager.less
126
- - lib/padrino-admin/bootstrap-less/pagination.less
127
- - lib/padrino-admin/bootstrap-less/panels.less
128
- - lib/padrino-admin/bootstrap-less/popovers.less
129
- - lib/padrino-admin/bootstrap-less/print.less
130
- - lib/padrino-admin/bootstrap-less/progress-bars.less
131
- - lib/padrino-admin/bootstrap-less/responsive-utilities.less
132
- - lib/padrino-admin/bootstrap-less/scaffolding.less
133
- - lib/padrino-admin/bootstrap-less/tables.less
134
- - lib/padrino-admin/bootstrap-less/theme.less
135
- - lib/padrino-admin/bootstrap-less/thumbnails.less
136
- - lib/padrino-admin/bootstrap-less/tooltip.less
137
- - lib/padrino-admin/bootstrap-less/type.less
138
- - lib/padrino-admin/bootstrap-less/utilities.less
139
- - lib/padrino-admin/bootstrap-less/variables.less
140
- - lib/padrino-admin/bootstrap-less/wells.less
141
59
  - lib/padrino-admin/generators/actions.rb
142
60
  - lib/padrino-admin/generators/admin_app.rb
143
61
  - lib/padrino-admin/generators/admin_page.rb
144
62
  - lib/padrino-admin/generators/orm.rb
145
63
  - lib/padrino-admin/generators/templates/account/activerecord.rb.tt
146
- - lib/padrino-admin/generators/templates/account/couchrest.rb.tt
147
- - lib/padrino-admin/generators/templates/account/datamapper.rb.tt
148
- - lib/padrino-admin/generators/templates/account/dynamoid.rb.tt
149
- - lib/padrino-admin/generators/templates/account/minirecord.rb.tt
150
64
  - lib/padrino-admin/generators/templates/account/mongoid.rb.tt
151
- - lib/padrino-admin/generators/templates/account/mongomapper.rb.tt
152
- - lib/padrino-admin/generators/templates/account/ohm.rb.tt
153
65
  - lib/padrino-admin/generators/templates/account/seeds.rb.tt
154
66
  - lib/padrino-admin/generators/templates/account/sequel.rb.tt
155
67
  - lib/padrino-admin/generators/templates/app.rb.tt
@@ -176,7 +88,7 @@ files:
176
88
  - lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/tab.js
177
89
  - lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/tooltip.js
178
90
  - lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/transition.js
179
- - lib/padrino-admin/generators/templates/assets/javascripts/jquery-1.11.0.min.js
91
+ - lib/padrino-admin/generators/templates/assets/javascripts/jquery-3.7.1.min.js
180
92
  - lib/padrino-admin/generators/templates/assets/stylesheets/application.css
181
93
  - lib/padrino-admin/generators/templates/assets/stylesheets/bootstrap.css
182
94
  - lib/padrino-admin/generators/templates/assets/stylesheets/fonts/FontAwesome.otf
@@ -241,27 +153,7 @@ files:
241
153
  - lib/padrino-admin/locale/admin/uk.yml
242
154
  - lib/padrino-admin/locale/admin/zh_cn.yml
243
155
  - lib/padrino-admin/locale/admin/zh_tw.yml
244
- - lib/padrino-admin/locale/orm/cs.yml
245
- - lib/padrino-admin/locale/orm/da.yml
246
- - lib/padrino-admin/locale/orm/de.yml
247
- - lib/padrino-admin/locale/orm/en.yml
248
- - lib/padrino-admin/locale/orm/es.yml
249
- - lib/padrino-admin/locale/orm/fr.yml
250
- - lib/padrino-admin/locale/orm/hu.yml
251
- - lib/padrino-admin/locale/orm/it.yml
252
- - lib/padrino-admin/locale/orm/ja.yml
253
- - lib/padrino-admin/locale/orm/lv.yml
254
- - lib/padrino-admin/locale/orm/nl.yml
255
- - lib/padrino-admin/locale/orm/no.yml
256
156
  - lib/padrino-admin/locale/orm/pl.yml
257
- - lib/padrino-admin/locale/orm/pt_br.yml
258
- - lib/padrino-admin/locale/orm/ro.yml
259
- - lib/padrino-admin/locale/orm/ru.yml
260
- - lib/padrino-admin/locale/orm/sv.yml
261
- - lib/padrino-admin/locale/orm/tr.yml
262
- - lib/padrino-admin/locale/orm/uk.yml
263
- - lib/padrino-admin/locale/orm/zh_cn.yml
264
- - lib/padrino-admin/locale/orm/zh_tw.yml
265
157
  - padrino-admin.gemspec
266
158
  - test/fixtures/sequel.rb
267
159
  - test/generators/test_account_model_generator.rb
@@ -290,15 +182,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
290
182
  - !ruby/object:Gem::Version
291
183
  version: 1.3.6
292
184
  requirements: []
293
- rubygems_version: 3.5.23
185
+ rubygems_version: 3.5.22
294
186
  signing_key:
295
187
  specification_version: 4
296
188
  summary: Admin Dashboard for Padrino
297
- test_files:
298
- - test/fixtures/sequel.rb
299
- - test/generators/test_account_model_generator.rb
300
- - test/generators/test_admin_app_generator.rb
301
- - test/generators/test_admin_page_generator.rb
302
- - test/helper.rb
303
- - test/test_admin_application.rb
304
- - test/test_locale.rb
189
+ test_files: []
@@ -1,67 +0,0 @@
1
- //
2
- // Alerts
3
- // --------------------------------------------------
4
-
5
-
6
- // Base styles
7
- // -------------------------
8
-
9
- .alert {
10
- padding: @alert-padding;
11
- margin-bottom: @line-height-computed;
12
- border: 1px solid transparent;
13
- border-radius: @alert-border-radius;
14
-
15
- // Headings for larger alerts
16
- h4 {
17
- margin-top: 0;
18
- // Specified for the h4 to prevent conflicts of changing @headings-color
19
- color: inherit;
20
- }
21
- // Provide class for links that match alerts
22
- .alert-link {
23
- font-weight: @alert-link-font-weight;
24
- }
25
-
26
- // Improve alignment and spacing of inner content
27
- > p,
28
- > ul {
29
- margin-bottom: 0;
30
- }
31
- > p + p {
32
- margin-top: 5px;
33
- }
34
- }
35
-
36
- // Dismissable alerts
37
- //
38
- // Expand the right padding and account for the close button's positioning.
39
-
40
- .alert-dismissable {
41
- padding-right: (@alert-padding + 20);
42
-
43
- // Adjust close link position
44
- .close {
45
- position: relative;
46
- top: -2px;
47
- right: -21px;
48
- color: inherit;
49
- }
50
- }
51
-
52
- // Alternate styles
53
- //
54
- // Generate contextual modifier classes for colorizing the alert.
55
-
56
- .alert-success {
57
- .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);
58
- }
59
- .alert-info {
60
- .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);
61
- }
62
- .alert-warning {
63
- .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);
64
- }
65
- .alert-danger {
66
- .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);
67
- }
@@ -1,55 +0,0 @@
1
- //
2
- // Badges
3
- // --------------------------------------------------
4
-
5
-
6
- // Base classes
7
- .badge {
8
- display: inline-block;
9
- min-width: 10px;
10
- padding: 3px 7px;
11
- font-size: @font-size-small;
12
- font-weight: @badge-font-weight;
13
- color: @badge-color;
14
- line-height: @badge-line-height;
15
- vertical-align: baseline;
16
- white-space: nowrap;
17
- text-align: center;
18
- background-color: @badge-bg;
19
- border-radius: @badge-border-radius;
20
-
21
- // Empty badges collapse automatically (not available in IE8)
22
- &:empty {
23
- display: none;
24
- }
25
-
26
- // Quick fix for badges in buttons
27
- .btn & {
28
- position: relative;
29
- top: -1px;
30
- }
31
- .btn-xs & {
32
- top: 0;
33
- padding: 1px 5px;
34
- }
35
- }
36
-
37
- // Hover state, but only for links
38
- a.badge {
39
- &:hover,
40
- &:focus {
41
- color: @badge-link-hover-color;
42
- text-decoration: none;
43
- cursor: pointer;
44
- }
45
- }
46
-
47
- // Account for counters in navs
48
- a.list-group-item.active > .badge,
49
- .nav-pills > .active > a > .badge {
50
- color: @badge-active-color;
51
- background-color: @badge-active-bg;
52
- }
53
- .nav-pills > li > a > .badge {
54
- margin-left: 3px;
55
- }