tiny_admin 0.9.0 → 0.10.1

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.
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