tiny_admin 0.8.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 71d42ca63e3a410de95780d584cdfb61dd94feb95b503f5f55379efabec9477e
4
- data.tar.gz: 96c4b375cb65327635199296d11f54335e6c5266dacce39a7316e0eb2844046c
3
+ metadata.gz: 748ac60bbfef74485795f95728033866510e728572d391b2a3f381fde88434f6
4
+ data.tar.gz: 59c0a78183a960e28cb1670d4484be18e368ec48cf622bd8034087192385b7dd
5
5
  SHA512:
6
- metadata.gz: d377537524247253a871e016d3d5e688e47ab07d40c6d33814c5dfc0be761e734d3de3c8c23d3e3981d3f949ce15d230312b4c71fb2d7d6f33aeb45cc352223f
7
- data.tar.gz: 4ddb16c2f1fbfefced95deb426cf369d28201866f800eee1f4b14895bd938233f6f67bf51d784a7edf340b48d7a75230a86b679db9ec71c07f18b726c23971a4
6
+ metadata.gz: 8ba6531f80fbaab695c59a309e7249f071a1f4491fd7800edb2562571beb352d3f4faff625876cf6dc87e9cdcbf8d12d002f343076446c8ad82653c8d488ce78
7
+ data.tar.gz: 162637202396ce2106c9ad9c2117a22becc3ad99c3a4e0f72f850624089cb110e2eda4ae39aa66e6c4897bb6c5ad0789003d10711c94ba74f28616afa3e5e82a
data/README.md CHANGED
@@ -19,7 +19,7 @@ Please ⭐ if you like it.
19
19
 
20
20
  ## Install
21
21
 
22
- - Add to your Gemfile: `gem 'tiny_admin', '~> 0.8'`
22
+ - Add to your Gemfile: `gem 'tiny_admin', '~> 0.10'`
23
23
  - Mount the app in a route (check some examples with: Hanami, Rails, Roda and standalone in [extra](extra))
24
24
  + in Rails, update _config/routes.rb_: `mount TinyAdmin::Router => '/admin'`
25
25
  - Configure the dashboard using `TinyAdmin.configure` and/or `TinyAdmin.configure_from_file` with a YAML config file (see [configuration](#configuration) below):
@@ -43,6 +43,12 @@ Plugins available:
43
43
 
44
44
  - **NoAuth**: no authentication.
45
45
 
46
+ ### Authorization
47
+
48
+ Plugins available:
49
+
50
+ - **Authorization**: base class to provide an authorization per action, the host application should inherit from it and override the class method `allowed?`.
51
+
46
52
  ### Repository
47
53
 
48
54
  Plugin available:
@@ -134,6 +140,10 @@ authentication:
134
140
  password: 'f1891cea80fc05e433c943254c6bdabc159577a02a7395dfebbfbc4f7661d4af56f2d372131a45936de40160007368a56ef216a30cb202c66d3145fd24380906'
135
141
  ```
136
142
 
143
+ `authorization_class` (String): a plugin class to use;
144
+
145
+ > 📚 [Wiki Authentication page](https://github.com/blocknotes/tiny_admin/wiki/Authorization) available
146
+
137
147
  `sections` (Array of hashes): define the admin sections, properties:
138
148
 
139
149
  - `slug` (String): section reference identifier;
@@ -218,6 +228,8 @@ model: Post
218
228
 
219
229
  #### Resource index options
220
230
 
231
+ > 📚 [Wiki Resource index page](https://github.com/blocknotes/tiny_admin/wiki/Resource-index) available
232
+
221
233
  The Index hash supports the following options:
222
234
 
223
235
  - `attributes` (Array): fields to expose in the resource list page;
@@ -257,6 +269,8 @@ Example:
257
269
 
258
270
  #### Resource show options
259
271
 
272
+ > 📚 [Wiki Resource show page](https://github.com/blocknotes/tiny_admin/wiki/Resource-show) available
273
+
260
274
  The Show hash supports the following options:
261
275
 
262
276
  - `attributes` (Array): fields to expose in the resource details page.
@@ -58,12 +58,13 @@ module TinyAdmin
58
58
  end
59
59
  end
60
60
 
61
- def setup_pagination(page, pagination_component_class, total_count:)
61
+ def setup_pagination(page, pagination_component, total_count:)
62
62
  @pages = (total_count / pagination.to_f).ceil
63
- return if pages <= 1 || !pagination_component_class
63
+ return if pages <= 1 || !pagination_component
64
64
 
65
- page.pagination_component = pagination_component_class.new
66
- page.pagination_component.update_attributes(current: current_page, pages: pages, query_string: query_string)
65
+ attributes = { current: current_page, pages: pages, query_string: query_string, total_count: total_count }
66
+ page.pagination_component = pagination_component.new
67
+ page.pagination_component.update_attributes(attributes)
67
68
  end
68
69
  end
69
70
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinyAdmin
4
+ module Plugins
5
+ class Authorization
6
+ class << self
7
+ def allowed?(_user, _action, _param = nil)
8
+ true
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -53,36 +53,45 @@ module TinyAdmin
53
53
  render(inline: page.call)
54
54
  end
55
55
 
56
- def root_route(router)
57
- if TinyAdmin.settings.root[:redirect]
58
- router.redirect route_for(TinyAdmin.settings.root[:redirect])
56
+ def root_route(req)
57
+ if authorization.allowed?(current_user, :root)
58
+ if TinyAdmin.settings.root[:redirect]
59
+ req.redirect route_for(TinyAdmin.settings.root[:redirect])
60
+ else
61
+ page_class = to_class(TinyAdmin.settings.root[:page])
62
+ attributes = TinyAdmin.settings.root.slice(:content, :title, :widgets)
63
+ render_page prepare_page(page_class, attributes: attributes, params: request.params)
64
+ end
59
65
  else
60
- page_class = to_class(TinyAdmin.settings.root[:page])
61
- render_page prepare_page(page_class, attributes: TinyAdmin.settings.root.slice(:content, :title, :widgets))
66
+ render_page prepare_page(TinyAdmin.settings.page_not_allowed)
62
67
  end
63
68
  end
64
69
 
65
- def setup_page_route(router, slug, page_data)
66
- router.get slug do
67
- attributes = page_data.slice(:content, :title, :widgets)
68
- render_page prepare_page(page_data[:class], slug: slug, attributes: attributes)
70
+ def setup_page_route(req, slug, page_data)
71
+ req.get slug do
72
+ if authorization.allowed?(current_user, :page, slug)
73
+ attributes = page_data.slice(:content, :title, :widgets)
74
+ render_page prepare_page(page_data[:class], slug: slug, attributes: attributes, params: request.params)
75
+ else
76
+ render_page prepare_page(TinyAdmin.settings.page_not_allowed)
77
+ end
69
78
  end
70
79
  end
71
80
 
72
- def setup_resource_routes(router, slug, options:)
73
- router.on slug do
74
- setup_collection_routes(router, slug, options: options)
75
- setup_member_routes(router, slug, options: options)
81
+ def setup_resource_routes(req, slug, options:)
82
+ req.on slug do
83
+ setup_collection_routes(req, slug, options: options)
84
+ setup_member_routes(req, slug, options: options)
76
85
  end
77
86
  end
78
87
 
79
- def setup_collection_routes(router, slug, options:)
88
+ def setup_collection_routes(req, slug, options:)
80
89
  repository = options[:repository].new(options[:model])
81
90
  action_options = options[:index] || {}
82
91
 
83
92
  # Custom actions
84
93
  custom_actions = setup_custom_actions(
85
- router,
94
+ req,
86
95
  options[:collection_actions],
87
96
  options: action_options,
88
97
  repository: repository,
@@ -91,28 +100,32 @@ module TinyAdmin
91
100
 
92
101
  # Index
93
102
  if options[:only].include?(:index) || options[:only].include?('index')
94
- router.is do
95
- context = Context.new(
96
- actions: custom_actions,
97
- repository: repository,
98
- request: request,
99
- router: router,
100
- slug: slug
101
- )
102
- index_action = TinyAdmin::Actions::Index.new
103
- render_page index_action.call(app: self, context: context, options: action_options)
103
+ req.is do
104
+ if authorization.allowed?(current_user, :resource_index, slug)
105
+ context = Context.new(
106
+ actions: custom_actions,
107
+ repository: repository,
108
+ request: request,
109
+ router: req,
110
+ slug: slug
111
+ )
112
+ index_action = TinyAdmin::Actions::Index.new
113
+ render_page index_action.call(app: self, context: context, options: action_options)
114
+ else
115
+ render_page prepare_page(TinyAdmin.settings.page_not_allowed)
116
+ end
104
117
  end
105
118
  end
106
119
  end
107
120
 
108
- def setup_member_routes(router, slug, options:)
121
+ def setup_member_routes(req, slug, options:)
109
122
  repository = options[:repository].new(options[:model])
110
123
  action_options = (options[:show] || {}).merge(record_not_found_page: TinyAdmin.settings.record_not_found)
111
124
 
112
- router.on String do |reference|
125
+ req.on String do |reference|
113
126
  # Custom actions
114
127
  custom_actions = setup_custom_actions(
115
- router,
128
+ req,
116
129
  options[:member_actions],
117
130
  options: action_options,
118
131
  repository: repository,
@@ -122,42 +135,54 @@ module TinyAdmin
122
135
 
123
136
  # Show
124
137
  if options[:only].include?(:show) || options[:only].include?('show')
125
- router.is do
126
- context = Context.new(
127
- actions: custom_actions,
128
- reference: reference,
129
- repository: repository,
130
- request: request,
131
- router: router,
132
- slug: slug
133
- )
134
- show_action = TinyAdmin::Actions::Show.new
135
- render_page show_action.call(app: self, context: context, options: action_options)
138
+ req.is do
139
+ if authorization.allowed?(current_user, :resource_show, slug)
140
+ context = Context.new(
141
+ actions: custom_actions,
142
+ reference: reference,
143
+ repository: repository,
144
+ request: request,
145
+ router: req,
146
+ slug: slug
147
+ )
148
+ show_action = TinyAdmin::Actions::Show.new
149
+ render_page show_action.call(app: self, context: context, options: action_options)
150
+ else
151
+ render_page prepare_page(TinyAdmin.settings.page_not_allowed)
152
+ end
136
153
  end
137
154
  end
138
155
  end
139
156
  end
140
157
 
141
- def setup_custom_actions(router, custom_actions, options:, repository:, slug:, reference: nil)
158
+ def setup_custom_actions(req, custom_actions = nil, options:, repository:, slug:, reference: nil)
142
159
  (custom_actions || []).each_with_object({}) do |custom_action, result|
143
160
  action_slug, action = custom_action.first
144
161
  action_class = to_class(action)
145
162
 
146
- router.get action_slug.to_s do
147
- context = Context.new(
148
- actions: {},
149
- reference: reference,
150
- repository: repository,
151
- request: request,
152
- router: router,
153
- slug: slug
154
- )
155
- custom_action = action_class.new
156
- render_page custom_action.call(app: self, context: context, options: options)
163
+ req.get action_slug.to_s do
164
+ if authorization.allowed?(current_user, :custom_action, action_slug.to_s)
165
+ context = Context.new(
166
+ actions: {},
167
+ reference: reference,
168
+ repository: repository,
169
+ request: request,
170
+ router: req,
171
+ slug: slug
172
+ )
173
+ custom_action = action_class.new
174
+ render_page custom_action.call(app: self, context: context, options: options)
175
+ else
176
+ render_page prepare_page(TinyAdmin.settings.page_not_allowed)
177
+ end
157
178
  end
158
179
 
159
180
  result[action_slug.to_s] = action_class
160
181
  end
161
182
  end
183
+
184
+ def authorization
185
+ TinyAdmin.settings.authorization_class
186
+ end
162
187
  end
163
188
  end
@@ -7,6 +7,7 @@ module TinyAdmin
7
7
  DEFAULTS = {
8
8
  %i[authentication plugin] => Plugins::NoAuth,
9
9
  %i[authentication login] => Views::Pages::SimpleAuthLogin,
10
+ %i[authorization_class] => Plugins::Authorization,
10
11
  %i[components field_value] => Views::Components::FieldValue,
11
12
  %i[components flash] => Views::Components::Flash,
12
13
  %i[components head] => Views::Components::Head,
@@ -14,6 +15,7 @@ module TinyAdmin
14
15
  %i[components pagination] => Views::Components::Pagination,
15
16
  %i[content_page] => Views::Pages::Content,
16
17
  %i[helper_class] => Support,
18
+ %i[page_not_allowed] => Views::Pages::PageNotAllowed,
17
19
  %i[page_not_found] => Views::Pages::PageNotFound,
18
20
  %i[record_not_found] => Views::Pages::RecordNotFound,
19
21
  %i[repository] => Plugins::ActiveRecordRepository,
@@ -25,10 +27,12 @@ module TinyAdmin
25
27
 
26
28
  OPTIONS = %i[
27
29
  authentication
30
+ authorization_class
28
31
  components
29
32
  content_page
30
33
  extra_styles
31
34
  helper_class
35
+ page_not_allowed
32
36
  page_not_found
33
37
  record_not_found
34
38
  repository
@@ -14,7 +14,7 @@ module TinyAdmin
14
14
  list.join('&')
15
15
  end
16
16
 
17
- def prepare_page(page_class, slug: nil, attributes: nil, options: nil)
17
+ def prepare_page(page_class, slug: nil, attributes: nil, options: nil, params: nil)
18
18
  page_class.new.tap do |page|
19
19
  page.options = options
20
20
  page.head_component = TinyAdmin.settings.components[:head]&.new
@@ -27,9 +27,11 @@ module TinyAdmin
27
27
  items: options&.include?(:no_menu) ? [] : TinyAdmin.settings.store&.navbar
28
28
  )
29
29
  attrs = attributes || {}
30
+ attrs[:params] = params if params
30
31
  attrs[:widgets] = attrs[:widgets].map { to_class(_1) } if attrs[:widgets]
31
32
  page.update_attributes(attrs) unless attrs.empty?
32
33
  yield(page) if block_given?
34
+ page.setup if page.respond_to?(:setup)
33
35
  end
34
36
  end
35
37
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinyAdmin
4
- VERSION = '0.8.0'
4
+ VERSION = '0.10.0'
5
5
  end
@@ -4,7 +4,14 @@ module TinyAdmin
4
4
  module Views
5
5
  module Actions
6
6
  class Index < DefaultLayout
7
- attr_accessor :actions, :fields, :filters, :links, :pagination_component, :prepare_record, :records, :slug
7
+ attr_accessor :actions,
8
+ :fields,
9
+ :filters,
10
+ :links,
11
+ :pagination_component,
12
+ :prepare_record,
13
+ :records,
14
+ :slug
8
15
 
9
16
  def template
10
17
  super do
@@ -28,6 +35,8 @@ module TinyAdmin
28
35
 
29
36
  table_body
30
37
  }
38
+
39
+ render pagination_component if pagination_component
31
40
  }
32
41
 
33
42
  if filters&.any?
@@ -39,8 +48,6 @@ module TinyAdmin
39
48
  end
40
49
  }
41
50
 
42
- render pagination_component if pagination_component
43
-
44
51
  render TinyAdmin::Views::Components::Widgets.new(widgets)
45
52
  }
46
53
  end
@@ -4,7 +4,12 @@ module TinyAdmin
4
4
  module Views
5
5
  module Actions
6
6
  class Show < DefaultLayout
7
- attr_accessor :actions, :fields, :prepare_record, :record, :reference, :slug
7
+ attr_accessor :actions,
8
+ :fields,
9
+ :prepare_record,
10
+ :record,
11
+ :reference,
12
+ :slug
8
13
 
9
14
  def template
10
15
  super do
@@ -5,7 +5,7 @@ module TinyAdmin
5
5
  class BasicLayout < Phlex::HTML
6
6
  include Utils
7
7
 
8
- attr_accessor :content, :widgets
8
+ attr_accessor :content, :params, :widgets
9
9
 
10
10
  def label_for(value, options: [])
11
11
  TinyAdmin.settings.helper_class.label_for(value, options: options)
@@ -4,23 +4,31 @@ module TinyAdmin
4
4
  module Views
5
5
  module Components
6
6
  class Pagination < BasicComponent
7
- attr_accessor :current, :pages, :query_string
7
+ attr_accessor :current, :pages, :query_string, :total_count
8
8
 
9
9
  def template
10
- div(class: 'pagination-div') {
11
- nav('aria-label' => 'Pagination') {
12
- ul(class: 'pagination justify-content-center') {
13
- if pages <= 10
14
- pages_range(1..pages)
15
- elsif current <= 4 || current >= pages - 3
16
- pages_range(1..(current <= 4 ? current + 2 : 4), with_dots: true)
17
- pages_range((current > pages - 4 ? current - 2 : pages - 2)..pages)
18
- else
19
- pages_range(1..1, with_dots: true)
20
- pages_range(current - 2..current + 2, with_dots: true)
21
- pages_range(pages..pages)
22
- end
10
+ div(class: 'container') {
11
+ div(class: 'row') {
12
+ div(class: 'col total-count') {
13
+ "#{total_count} items"
23
14
  }
15
+ div(class: 'col col-6 text-center pagination-div') {
16
+ nav(class: 'd-inline-block', 'aria-label': 'Pagination') {
17
+ ul(class: 'pagination') {
18
+ if pages <= 10
19
+ pages_range(1..pages)
20
+ elsif current <= 4 || current >= pages - 3
21
+ pages_range(1..(current <= 4 ? current + 2 : 4), with_dots: true)
22
+ pages_range((current > pages - 4 ? current - 2 : pages - 2)..pages)
23
+ else
24
+ pages_range(1..1, with_dots: true)
25
+ pages_range(current - 2..current + 2, with_dots: true)
26
+ pages_range(pages..pages)
27
+ end
28
+ }
29
+ }
30
+ }
31
+ div(class: 'col')
24
32
  }
25
33
  }
26
34
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinyAdmin
4
+ module Views
5
+ module Pages
6
+ class PageNotAllowed < DefaultLayout
7
+ def template
8
+ super do
9
+ div(class: 'page_not_allowed') {
10
+ h1(class: 'title') { title }
11
+ }
12
+ end
13
+ end
14
+
15
+ def title
16
+ 'Page not allowed'
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tiny_admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mattia Roccoberton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-10 00:00:00.000000000 Z
11
+ date: 2023-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: phlex
@@ -83,6 +83,7 @@ files:
83
83
  - lib/tiny_admin/context.rb
84
84
  - lib/tiny_admin/field.rb
85
85
  - lib/tiny_admin/plugins/active_record_repository.rb
86
+ - lib/tiny_admin/plugins/authorization.rb
86
87
  - lib/tiny_admin/plugins/base_repository.rb
87
88
  - lib/tiny_admin/plugins/no_auth.rb
88
89
  - lib/tiny_admin/plugins/simple_auth.rb
@@ -107,6 +108,7 @@ files:
107
108
  - lib/tiny_admin/views/components/widgets.rb
108
109
  - lib/tiny_admin/views/default_layout.rb
109
110
  - lib/tiny_admin/views/pages/content.rb
111
+ - lib/tiny_admin/views/pages/page_not_allowed.rb
110
112
  - lib/tiny_admin/views/pages/page_not_found.rb
111
113
  - lib/tiny_admin/views/pages/record_not_found.rb
112
114
  - lib/tiny_admin/views/pages/root.rb
@@ -134,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
136
  - !ruby/object:Gem::Version
135
137
  version: '0'
136
138
  requirements: []
137
- rubygems_version: 3.3.26
139
+ rubygems_version: 3.4.10
138
140
  signing_key:
139
141
  specification_version: 4
140
142
  summary: Tiny Admin