tiny_admin 0.9.0 → 0.10.1

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: de3ed265839998db96c8e220f1b66576a8a37325e0726f3597e0b1ef315087a4
4
- data.tar.gz: 828309ff8139a11c3e73fcbeb82ffea7f752191e5c4e99e9dc19fbaa29a2180e
3
+ metadata.gz: 78ceeba34bc5a1b4fffa887569b3ac5100a0465c5acad499a0c6ffd2c400694b
4
+ data.tar.gz: dc60d171c117f7f480895838e4b70b89439d7ab650c15ed27425c08468f92f79
5
5
  SHA512:
6
- metadata.gz: 3648b175fd028a82bc7c3ae35fc51d3380a4d22fc6dd38dfd5da5ed375d94b4b45358b36c17c955482574756700bd2889ba57348e4ed3453491e2112c9d1471f
7
- data.tar.gz: 4ea2a1301b70a3b88e07829e5755976482d22b2f18c1752ab7b7626e93b19b20527a7944c9da634fdf92a4bed53cf20d56c1e7e6738bc8c3b519de4147cd810b
6
+ metadata.gz: 2d1c6fd794ae0e1662cfc6dbe8a5d2c6881213681755fabccc52a88b74ac8109c74d72db5bb172e22f530523f2ec151c998f628c2c53d59163c429fde83af9ee
7
+ data.tar.gz: 0f3fb8db4c1dda2cac93f3bda4fa2cbbac3fa0b8ee4b7b31cd09b2ce0ccbe8ed25f8d2e55315673973a9d6e8fc25571ad30eba70bfbdc13aff51f41ed12d981e
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/tiny_admin.svg)](https://badge.fury.io/rb/tiny_admin)
4
4
  [![Gem Downloads](https://badgen.net/rubygems/dt/tiny_admin)](https://rubygems.org/gems/tiny_admin)
5
5
  [![Linters](https://github.com/blocknotes/tiny_admin/actions/workflows/linters.yml/badge.svg)](https://github.com/blocknotes/tiny_admin/actions/workflows/linters.yml)
6
- [![Specs](https://github.com/blocknotes/tiny_admin/actions/workflows/specs.yml/badge.svg)](https://github.com/blocknotes/tiny_admin/actions/workflows/specs.yml)
6
+ [![Specs](https://github.com/blocknotes/tiny_admin/actions/workflows/tests.yml/badge.svg)](https://github.com/blocknotes/tiny_admin/actions/workflows/tests.yml)
7
7
 
8
8
  A compact and composable dashboard component for Ruby.
9
9
 
@@ -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.9'`
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;
@@ -58,12 +58,12 @@ 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
65
  attributes = { current: current_page, pages: pages, query_string: query_string, total_count: total_count }
66
- page.pagination_component = pagination_component_class.new
66
+ page.pagination_component = pagination_component.new
67
67
  page.pagination_component.update_attributes(attributes)
68
68
  end
69
69
  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,37 +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
- attributes = TinyAdmin.settings.root.slice(:content, :title, :widgets)
62
- render_page prepare_page(page_class, attributes: attributes, params: request.params)
66
+ render_page prepare_page(TinyAdmin.settings.page_not_allowed)
63
67
  end
64
68
  end
65
69
 
66
- def setup_page_route(router, slug, page_data)
67
- router.get slug do
68
- attributes = page_data.slice(:content, :title, :widgets)
69
- render_page prepare_page(page_data[:class], slug: slug, attributes: attributes, params: request.params)
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
70
78
  end
71
79
  end
72
80
 
73
- def setup_resource_routes(router, slug, options:)
74
- router.on slug do
75
- setup_collection_routes(router, slug, options: options)
76
- 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)
77
85
  end
78
86
  end
79
87
 
80
- def setup_collection_routes(router, slug, options:)
88
+ def setup_collection_routes(req, slug, options:)
81
89
  repository = options[:repository].new(options[:model])
82
90
  action_options = options[:index] || {}
83
91
 
84
92
  # Custom actions
85
93
  custom_actions = setup_custom_actions(
86
- router,
94
+ req,
87
95
  options[:collection_actions],
88
96
  options: action_options,
89
97
  repository: repository,
@@ -92,28 +100,32 @@ module TinyAdmin
92
100
 
93
101
  # Index
94
102
  if options[:only].include?(:index) || options[:only].include?('index')
95
- router.is do
96
- context = Context.new(
97
- actions: custom_actions,
98
- repository: repository,
99
- request: request,
100
- router: router,
101
- slug: slug
102
- )
103
- index_action = TinyAdmin::Actions::Index.new
104
- 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
105
117
  end
106
118
  end
107
119
  end
108
120
 
109
- def setup_member_routes(router, slug, options:)
121
+ def setup_member_routes(req, slug, options:)
110
122
  repository = options[:repository].new(options[:model])
111
123
  action_options = (options[:show] || {}).merge(record_not_found_page: TinyAdmin.settings.record_not_found)
112
124
 
113
- router.on String do |reference|
125
+ req.on String do |reference|
114
126
  # Custom actions
115
127
  custom_actions = setup_custom_actions(
116
- router,
128
+ req,
117
129
  options[:member_actions],
118
130
  options: action_options,
119
131
  repository: repository,
@@ -123,42 +135,54 @@ module TinyAdmin
123
135
 
124
136
  # Show
125
137
  if options[:only].include?(:show) || options[:only].include?('show')
126
- router.is do
127
- context = Context.new(
128
- actions: custom_actions,
129
- reference: reference,
130
- repository: repository,
131
- request: request,
132
- router: router,
133
- slug: slug
134
- )
135
- show_action = TinyAdmin::Actions::Show.new
136
- 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
137
153
  end
138
154
  end
139
155
  end
140
156
  end
141
157
 
142
- 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)
143
159
  (custom_actions || []).each_with_object({}) do |custom_action, result|
144
160
  action_slug, action = custom_action.first
145
161
  action_class = to_class(action)
146
162
 
147
- router.get action_slug.to_s do
148
- context = Context.new(
149
- actions: {},
150
- reference: reference,
151
- repository: repository,
152
- request: request,
153
- router: router,
154
- slug: slug
155
- )
156
- custom_action = action_class.new
157
- 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
158
178
  end
159
179
 
160
180
  result[action_slug.to_s] = action_class
161
181
  end
162
182
  end
183
+
184
+ def authorization
185
+ TinyAdmin.settings.authorization_class
186
+ end
163
187
  end
164
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinyAdmin
4
- VERSION = '0.9.0'
4
+ VERSION = '0.10.1'
5
5
  end
@@ -4,9 +4,16 @@ 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
- def template
16
+ def view_template
10
17
  super do
11
18
  div(class: 'index') {
12
19
  div(class: 'row') {
@@ -4,9 +4,14 @@ 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
- def template
14
+ def view_template
10
15
  super do
11
16
  div(class: 'show') {
12
17
  div(class: 'row') {
@@ -12,7 +12,7 @@ module TinyAdmin
12
12
  @record = record
13
13
  end
14
14
 
15
- def template
15
+ def view_template
16
16
  translated_value = field.translate_value(value)
17
17
  value_class = field.options[:options]&.include?('value_class') ? "value-#{value}" : nil
18
18
  if field.options[:link_to]
@@ -6,7 +6,7 @@ module TinyAdmin
6
6
  class FiltersForm < BasicComponent
7
7
  attr_accessor :filters, :section_path
8
8
 
9
- def template
9
+ def view_template
10
10
  form(class: 'form_filters', method: 'get') {
11
11
  filters.each do |field, filter|
12
12
  name = field.name
@@ -6,7 +6,7 @@ module TinyAdmin
6
6
  class Flash < BasicComponent
7
7
  attr_accessor :messages
8
8
 
9
- def template
9
+ def view_template
10
10
  @messages ||= {}
11
11
  notices = messages[:notices]
12
12
  warnings = messages[:warnings]
@@ -6,7 +6,7 @@ module TinyAdmin
6
6
  class Head < BasicComponent
7
7
  attr_accessor :extra_styles, :page_title, :style_links
8
8
 
9
- def template
9
+ def view_template
10
10
  head {
11
11
  meta charset: 'utf-8'
12
12
  meta name: 'viewport', content: 'width=device-width, initial-scale=1'
@@ -6,7 +6,7 @@ module TinyAdmin
6
6
  class Navbar < BasicComponent
7
7
  attr_accessor :current_slug, :items, :root_path, :root_title
8
8
 
9
- def template
9
+ def view_template
10
10
  nav(class: 'navbar navbar-expand-lg') {
11
11
  div(class: 'container') {
12
12
  a(class: 'navbar-brand', href: root_path) { root_title }
@@ -6,7 +6,7 @@ module TinyAdmin
6
6
  class Pagination < BasicComponent
7
7
  attr_accessor :current, :pages, :query_string, :total_count
8
8
 
9
- def template
9
+ def view_template
10
10
  div(class: 'container') {
11
11
  div(class: 'row') {
12
12
  div(class: 'col total-count') {
@@ -8,7 +8,7 @@ module TinyAdmin
8
8
  @widgets = widgets
9
9
  end
10
10
 
11
- def template
11
+ def view_template
12
12
  return if @widgets.nil? || @widgets.empty?
13
13
 
14
14
  div(class: 'container widgets') {
@@ -5,7 +5,7 @@ module TinyAdmin
5
5
  class DefaultLayout < BasicLayout
6
6
  attr_accessor :flash_component, :head_component, :messages, :navbar_component, :options, :title
7
7
 
8
- def template(&block)
8
+ def view_template(&block)
9
9
  extra_styles = TinyAdmin.settings.extra_styles
10
10
  flash_component&.messages = messages
11
11
  head_component&.update_attributes(page_title: title, style_links: style_links, extra_styles: extra_styles)
@@ -4,7 +4,7 @@ module TinyAdmin
4
4
  module Views
5
5
  module Pages
6
6
  class Content < DefaultLayout
7
- def template
7
+ def view_template
8
8
  super do
9
9
  div(class: 'content') {
10
10
  div(class: 'content-data') {
@@ -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 view_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
@@ -4,7 +4,7 @@ module TinyAdmin
4
4
  module Views
5
5
  module Pages
6
6
  class PageNotFound < DefaultLayout
7
- def template
7
+ def view_template
8
8
  super do
9
9
  div(class: 'page_not_found') {
10
10
  h1(class: 'title') { title }
@@ -4,7 +4,7 @@ module TinyAdmin
4
4
  module Views
5
5
  module Pages
6
6
  class RecordNotFound < DefaultLayout
7
- def template
7
+ def view_template
8
8
  super do
9
9
  div(class: 'record_not_found') {
10
10
  h1(class: 'title') { title }
@@ -4,7 +4,7 @@ module TinyAdmin
4
4
  module Views
5
5
  module Pages
6
6
  class Root < DefaultLayout
7
- def template
7
+ def view_template
8
8
  super do
9
9
  div(class: 'root') {
10
10
  render TinyAdmin::Views::Components::Widgets.new(widgets)
@@ -4,7 +4,7 @@ module TinyAdmin
4
4
  module Views
5
5
  module Pages
6
6
  class SimpleAuthLogin < DefaultLayout
7
- def template
7
+ def view_template
8
8
  super do
9
9
  div(class: 'simple_auth_login') {
10
10
  h1(class: 'title') { title }
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.9.0
4
+ version: 0.10.1
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-16 00:00:00.000000000 Z
11
+ date: 2024-04-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: phlex
@@ -17,6 +17,9 @@ dependencies:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.10.0
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -24,6 +27,9 @@ dependencies:
24
27
  - - "~>"
25
28
  - !ruby/object:Gem::Version
26
29
  version: '1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.10.0
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: roda
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -83,6 +89,7 @@ files:
83
89
  - lib/tiny_admin/context.rb
84
90
  - lib/tiny_admin/field.rb
85
91
  - lib/tiny_admin/plugins/active_record_repository.rb
92
+ - lib/tiny_admin/plugins/authorization.rb
86
93
  - lib/tiny_admin/plugins/base_repository.rb
87
94
  - lib/tiny_admin/plugins/no_auth.rb
88
95
  - lib/tiny_admin/plugins/simple_auth.rb
@@ -107,6 +114,7 @@ files:
107
114
  - lib/tiny_admin/views/components/widgets.rb
108
115
  - lib/tiny_admin/views/default_layout.rb
109
116
  - lib/tiny_admin/views/pages/content.rb
117
+ - lib/tiny_admin/views/pages/page_not_allowed.rb
110
118
  - lib/tiny_admin/views/pages/page_not_found.rb
111
119
  - lib/tiny_admin/views/pages/record_not_found.rb
112
120
  - lib/tiny_admin/views/pages/root.rb
@@ -134,7 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
142
  - !ruby/object:Gem::Version
135
143
  version: '0'
136
144
  requirements: []
137
- rubygems_version: 3.3.26
145
+ rubygems_version: 3.4.19
138
146
  signing_key:
139
147
  specification_version: 4
140
148
  summary: Tiny Admin