Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/linters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ jobs:
reviewdog:
name: Reviewdog
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write

steps:
- name: Checkout repository
Expand All @@ -19,7 +22,7 @@ jobs:
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.0'
ruby-version: '3.2'
bundler-cache: true

- name: Set up Reviewdog
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:

strategy:
matrix:
ruby: ['3.0', '3.1', '3.2', '3.3', '3.4', '4.0']
ruby: ['3.2', '3.3', '3.4', '4.0']

steps:
- name: Checkout repository
Expand Down
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ AllCops:
- vendor/**/*
NewCops: enable
SuggestExtensions: false
TargetRubyVersion: 3.0
TargetRubyVersion: 3.2

Lint/MissingSuper:
Exclude:
Expand Down
12 changes: 6 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
lint:
bin/rubocop
specs:
RUBYOPT='-rbundler/setup -rrbs/test/setup' RBS_TEST_TARGET='TinyAdmin::*' bin/rspec

test:
bin/rspec
server:
cd spec/dummy_rails/ && bin/rails s

test_rbs:
RUBYOPT='-rbundler/setup -rrbs/test/setup' RBS_TEST_TARGET='TinyAdmin::*' bin/rspec
seed:
cd spec/dummy_rails/ && bin/rails db:migrate && bin/rails db:seed
6 changes: 4 additions & 2 deletions lib/tiny_admin/basic_app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@ class BasicApp < Roda
include Utils

class << self
include Utils

def authentication_plugin
plugin = TinyAdmin.settings.authentication&.dig(:plugin)
plugin_class = plugin.is_a?(String) ? Object.const_get(plugin) : plugin
plugin_class = to_class(plugin) if plugin
plugin_class || TinyAdmin::Plugins::NoAuth
end
end

plugin :flash
plugin :not_found
plugin :render, engine: "html"
plugin :sessions, secret: SecureRandom.hex(64)
plugin :sessions, secret: ENV.fetch("TINY_ADMIN_SECRET") { SecureRandom.hex(64) }

plugin authentication_plugin, TinyAdmin.settings.authentication

Expand Down
3 changes: 1 addition & 2 deletions lib/tiny_admin/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ module TinyAdmin
:repository,
:request,
:router,
:slug,
keyword_init: true
:slug
)
end
5 changes: 3 additions & 2 deletions lib/tiny_admin/field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ def translate_value(value)
end

class << self
include Utils

def create_field(name:, title: nil, type: nil, options: {})
field_name = name.to_s
field_title = field_name.respond_to?(:humanize) ? field_name.humanize : field_name.tr("_", " ").capitalize
new(name: field_name, title: title || field_title, type: type || :string, options: options || {})
new(name: field_name, title: title || humanize(field_name), type: type || :string, options: options || {})
end
end
end
Expand Down
28 changes: 13 additions & 15 deletions lib/tiny_admin/router.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,26 +54,22 @@ def render_page(page)
end

def root_route(req)
if authorization.allowed?(current_user, :root)
authorize!(:root) do
if TinyAdmin.settings.root[:redirect]
req.redirect route_for(TinyAdmin.settings.root[:redirect])
else
page_class = to_class(TinyAdmin.settings.root[:page])
attributes = TinyAdmin.settings.root.slice(:content, :title, :widgets)
render_page prepare_page(page_class, attributes: attributes, params: request.params)
end
else
render_page prepare_page(TinyAdmin.settings.page_not_allowed)
end
end

def setup_page_route(req, slug, page_data)
req.get slug do
if authorization.allowed?(current_user, :page, slug)
authorize!(:page, slug) do
attributes = page_data.slice(:content, :title, :widgets)
render_page prepare_page(page_data[:class], slug: slug, attributes: attributes, params: request.params)
else
render_page prepare_page(TinyAdmin.settings.page_not_allowed)
end
end
end
Expand Down Expand Up @@ -101,7 +97,7 @@ def setup_collection_routes(req, slug, options:)
# Index
if options[:only].include?(:index) || options[:only].include?("index")
req.is do
if authorization.allowed?(current_user, :resource_index, slug)
authorize!(:resource_index, slug) do
context = Context.new(
actions: custom_actions,
repository: repository,
Expand All @@ -111,8 +107,6 @@ def setup_collection_routes(req, slug, options:)
)
index_action = TinyAdmin::Actions::Index.new
render_page index_action.call(app: self, context: context, options: action_options)
else
render_page prepare_page(TinyAdmin.settings.page_not_allowed)
end
end
end
Expand All @@ -136,7 +130,7 @@ def setup_member_routes(req, slug, options:)
# Show
if options[:only].include?(:show) || options[:only].include?("show")
req.is do
if authorization.allowed?(current_user, :resource_show, slug)
authorize!(:resource_show, slug) do
context = Context.new(
actions: custom_actions,
reference: reference,
Expand All @@ -147,8 +141,6 @@ def setup_member_routes(req, slug, options:)
)
show_action = TinyAdmin::Actions::Show.new
render_page show_action.call(app: self, context: context, options: action_options)
else
render_page prepare_page(TinyAdmin.settings.page_not_allowed)
end
end
end
Expand All @@ -161,7 +153,7 @@ def setup_custom_actions(req, custom_actions = nil, options:, repository:, slug:
action_class = to_class(action)

req.get action_slug.to_s do
if authorization.allowed?(current_user, :custom_action, action_slug.to_s)
authorize!(:custom_action, action_slug.to_s) do
context = Context.new(
actions: {},
reference: reference,
Expand All @@ -172,8 +164,6 @@ def setup_custom_actions(req, custom_actions = nil, options:, repository:, slug:
)
custom_action = action_class.new
render_page custom_action.call(app: self, context: context, options: options)
else
render_page prepare_page(TinyAdmin.settings.page_not_allowed)
end
end

Expand All @@ -184,5 +174,13 @@ def setup_custom_actions(req, custom_actions = nil, options:, repository:, slug:
def authorization
TinyAdmin.settings.authorization_class
end

def authorize!(action, param = nil)
if authorization.allowed?(current_user, action, param)
yield
else
render_page prepare_page(TinyAdmin.settings.page_not_allowed)
end
end
end
end
7 changes: 6 additions & 1 deletion lib/tiny_admin/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ def []=(*path, value)
end

def load_settings
return if @loaded

# default values
DEFAULTS.each do |(option, param), default|
if param
Expand All @@ -80,15 +82,18 @@ def load_settings
@store ||= TinyAdmin::Store.new(self)
self.root_path = "/" if root_path == ""

if authentication[:plugin] <= Plugins::SimpleAuth
if authentication[:plugin].is_a?(Module) && authentication[:plugin] <= Plugins::SimpleAuth
logout_path = "#{root_path}/auth/logout"
authentication[:logout] ||= TinyAdmin::Section.new(name: "logout", slug: "logout", path: logout_path)
end
store.prepare_sections(sections, logout: authentication[:logout])
@loaded = true
end

def reset!
@options = {}
@store = nil
@loaded = false
end

private
Expand Down
17 changes: 7 additions & 10 deletions lib/tiny_admin/store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,13 @@ def prepare_sections(sections, logout:)
end

slug = section[:slug].to_s
case section[:type]&.to_sym
when :content
list << add_content_section(slug, section)
when :page
list << add_page_section(slug, section)
when :resource
list << add_resource_section(slug, section)
when :url
list << add_url_section(slug, section)
end
item = case section[:type]&.to_sym
when :content then add_content_section(slug, section)
when :page then add_page_section(slug, section)
when :resource then add_resource_section(slug, section)
when :url then add_url_section(slug, section)
end
list << item if item
end
navbar << logout if logout
end
Expand Down
4 changes: 3 additions & 1 deletion lib/tiny_admin/support.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ def strftime(value, options: [])
end

def to_date(value, options: [])
value.to_date.to_s if value
value&.to_date&.to_s
rescue NoMethodError, ArgumentError
value&.to_s
end

def upcase(value, options: [])
Expand Down
6 changes: 4 additions & 2 deletions lib/tiny_admin/utils.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# frozen_string_literal: true

require "cgi"

module TinyAdmin
module Utils
def params_to_s(params)
list = params.each_with_object([]) do |(param, value), result|
if value.is_a?(Hash)
values = value.map { |key, val| "#{param}[#{key}]=#{val}" }
values = value.map { |key, val| "#{CGI.escape(param.to_s)}[#{CGI.escape(key.to_s)}]=#{CGI.escape(val.to_s)}" }
result.concat(values)
else
result.push(["#{param}=#{value}"])
result.push("#{CGI.escape(param.to_s)}=#{CGI.escape(value.to_s)}")
end
end
list.join("&")
Expand Down
15 changes: 5 additions & 10 deletions lib/tiny_admin/views/actions/index.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ def table_body
attributes = prepare_record.call(record)
attributes.each do |key, value|
field = fields[key]
next unless field

td(class: "field-value-#{field.name} field-value-type-#{field.type}") {
render TinyAdmin.settings.components[:field_value].new(field, value, record: record)
}
Expand Down Expand Up @@ -110,16 +112,9 @@ def table_body
end

def actions_buttons
ul(class: "nav justify-content-end") {
(actions || {}).each do |action, action_class|
li(class: "nav-item mx-1") {
href = TinyAdmin.route_for(slug, action: action)
a(href: href, class: "nav-link btn btn-outline-secondary") {
action_class.respond_to?(:title) ? action_class.title : action
}
}
end
}
buttons = TinyAdmin::Views::Components::ActionsButtons.new
buttons.update_attributes(actions: actions, slug: slug)
render buttons
end
end
end
Expand Down
19 changes: 6 additions & 13 deletions lib/tiny_admin/views/actions/show.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ def view_template

prepare_record.call(record).each do |key, value|
field = fields[key]
next unless field

div(class: "field-#{field.name} row lh-lg") {
if field
div(class: "field-header col-2") { field.options[:header] || field.title }
end
div(class: "field-header col-2") { field.options[:header] || field.title }
div(class: "field-value col-10") {
render TinyAdmin.settings.components[:field_value].new(field, value, record: record)
}
Expand All @@ -43,16 +43,9 @@ def view_template
private

def actions_buttons
ul(class: "nav justify-content-end") {
(actions || {}).each do |action, action_class|
li(class: "nav-item mx-1") {
href = TinyAdmin.route_for(slug, reference: reference, action: action)
a(href: href, class: "nav-link btn btn-outline-secondary") {
action_class.respond_to?(:title) ? action_class.title : action
}
}
end
}
buttons = TinyAdmin::Views::Components::ActionsButtons.new
buttons.update_attributes(actions: actions, slug: slug, reference: reference)
render buttons
end
end
end
Expand Down
13 changes: 13 additions & 0 deletions lib/tiny_admin/views/attributes.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

module TinyAdmin
module Views
module Attributes
def update_attributes(attributes)
attributes.each do |key, value|
send("#{key}=", value)
end
end
end
end
end
7 changes: 1 addition & 6 deletions lib/tiny_admin/views/basic_layout.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,14 @@
module TinyAdmin
module Views
class BasicLayout < Phlex::HTML
include Attributes
include Utils

attr_accessor :content, :params, :widgets

def label_for(value, options: [])
TinyAdmin.settings.helper_class.label_for(value, options: options)
end

def update_attributes(attributes)
attributes.each do |key, value|
send("#{key}=", value)
end
end
end
end
end
24 changes: 24 additions & 0 deletions lib/tiny_admin/views/components/actions_buttons.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

module TinyAdmin
module Views
module Components
class ActionsButtons < BasicComponent
attr_accessor :actions, :slug, :reference

def view_template
ul(class: "nav justify-content-end") {
(actions || {}).each do |action, action_class|
li(class: "nav-item mx-1") {
href = TinyAdmin.route_for(slug, reference: reference, action: action)
a(href: href, class: "nav-link btn btn-outline-secondary") {
action_class.respond_to?(:title) ? action_class.title : action
}
}
end
}
end
end
end
end
end
Loading
Loading