argus-trail 0.1.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +176 -0
- data/Rakefile +6 -0
- data/app/controllers/argus/trail/application_controller.rb +45 -0
- data/app/controllers/argus/trail/audit_entries_controller.rb +19 -0
- data/app/controllers/argus/trail/permissions_controller.rb +65 -0
- data/app/controllers/argus/trail/roles_controller.rb +73 -0
- data/app/helpers/argus/trail/application_helper.rb +34 -0
- data/app/models/argus/trail/application_record.rb +7 -0
- data/app/models/argus/trail/audit_entry.rb +38 -0
- data/app/models/argus/trail/permission.rb +11 -0
- data/app/models/argus/trail/role.rb +53 -0
- data/app/models/argus/trail/role_assignment.rb +13 -0
- data/app/models/argus/trail/role_permission.rb +10 -0
- data/app/views/argus/trail/audit_entries/index.html.erb +94 -0
- data/app/views/argus/trail/pagination/_simple_pager.html.erb +9 -0
- data/app/views/argus/trail/permissions/_form.html.erb +29 -0
- data/app/views/argus/trail/permissions/edit.html.erb +10 -0
- data/app/views/argus/trail/permissions/index.html.erb +47 -0
- data/app/views/argus/trail/permissions/new.html.erb +10 -0
- data/app/views/argus/trail/permissions/show.html.erb +27 -0
- data/app/views/argus/trail/roles/_form.html.erb +50 -0
- data/app/views/argus/trail/roles/edit.html.erb +10 -0
- data/app/views/argus/trail/roles/index.html.erb +68 -0
- data/app/views/argus/trail/roles/new.html.erb +10 -0
- data/app/views/argus/trail/roles/show.html.erb +52 -0
- data/app/views/layouts/argus/trail/application.html.erb +38 -0
- data/config/routes.rb +7 -0
- data/lib/argus/trail/actor.rb +67 -0
- data/lib/argus/trail/configuration.rb +46 -0
- data/lib/argus/trail/current.rb +7 -0
- data/lib/argus/trail/engine.rb +13 -0
- data/lib/argus/trail/pagination.rb +41 -0
- data/lib/argus/trail/version.rb +5 -0
- data/lib/argus/trail.rb +30 -0
- data/lib/generators/argus/trail/config/config_generator.rb +21 -0
- data/lib/generators/argus/trail/install/install_generator.rb +46 -0
- data/lib/generators/argus/trail/install/templates/POST_INSTALL +43 -0
- data/lib/generators/argus/trail/install/templates/create_argus_trail_tables.rb.erb +47 -0
- data/lib/generators/argus/trail/install/templates/initializer.rb +40 -0
- data/lib/generators/argus/trail/views/views_generator.rb +18 -0
- metadata +105 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Argus
|
|
2
|
+
module Trail
|
|
3
|
+
module Pagination
|
|
4
|
+
# Minimal stand-in for a Kaminari page, used only when the host app
|
|
5
|
+
# hasn't bundled Kaminari. Implements just enough of Kaminari's relation
|
|
6
|
+
# interface for the engine's views (current_page, total_pages, total_count, each).
|
|
7
|
+
class SimplePage
|
|
8
|
+
include Enumerable
|
|
9
|
+
|
|
10
|
+
attr_reader :current_page, :per_page, :total_count
|
|
11
|
+
|
|
12
|
+
def initialize(relation, page:, per:)
|
|
13
|
+
@current_page = [ page.to_i, 1 ].max
|
|
14
|
+
@per_page = per
|
|
15
|
+
@total_count = relation.count
|
|
16
|
+
@records = relation.offset((@current_page - 1) * per).limit(per).to_a
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def each(&block) = @records.each(&block)
|
|
20
|
+
def any? = @records.any?
|
|
21
|
+
def empty? = @records.empty?
|
|
22
|
+
def size = @records.size
|
|
23
|
+
|
|
24
|
+
def total_pages
|
|
25
|
+
return 0 if per_page.zero?
|
|
26
|
+
(total_count.to_f / per_page).ceil
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
module_function
|
|
31
|
+
|
|
32
|
+
def paginate(relation, page:, per:)
|
|
33
|
+
if defined?(Kaminari)
|
|
34
|
+
relation.page(page).per(per)
|
|
35
|
+
else
|
|
36
|
+
SimplePage.new(relation, page: page, per: per)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
data/lib/argus/trail.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require "argus/trail/version"
|
|
2
|
+
require "argus/trail/configuration"
|
|
3
|
+
require "argus/trail/current"
|
|
4
|
+
require "argus/trail/actor"
|
|
5
|
+
require "argus/trail/pagination"
|
|
6
|
+
require "argus/trail/engine"
|
|
7
|
+
|
|
8
|
+
module Argus
|
|
9
|
+
module Trail
|
|
10
|
+
EVENT_TYPES = %w[role_assigned role_revoked permission_granted permission_revoked].freeze
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
def configure
|
|
14
|
+
yield config
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def config
|
|
18
|
+
@config ||= Configuration.new
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def current_actor=(actor)
|
|
22
|
+
Current.actor = actor
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def current_actor
|
|
26
|
+
Current.actor
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
require_relative "../install/install_generator"
|
|
3
|
+
|
|
4
|
+
module Argus
|
|
5
|
+
module Trail
|
|
6
|
+
module Generators
|
|
7
|
+
# Re-templates just the initializer — for hosts who already ran
|
|
8
|
+
# `install` (migrations + route already in place) and want the
|
|
9
|
+
# config/initializers/argus_trail.rb file regenerated.
|
|
10
|
+
class ConfigGenerator < Rails::Generators::Base
|
|
11
|
+
source_root Argus::Trail::Generators::InstallGenerator.source_root
|
|
12
|
+
|
|
13
|
+
desc "Writes (or rewrites) config/initializers/argus_trail.rb"
|
|
14
|
+
|
|
15
|
+
def create_initializer
|
|
16
|
+
template "initializer.rb", "config/initializers/argus_trail.rb"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
require "rails/generators/migration"
|
|
3
|
+
require "active_record"
|
|
4
|
+
|
|
5
|
+
module Argus
|
|
6
|
+
module Trail
|
|
7
|
+
module Generators
|
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
|
9
|
+
include Rails::Generators::Migration
|
|
10
|
+
|
|
11
|
+
source_root File.expand_path("templates", __dir__)
|
|
12
|
+
|
|
13
|
+
def self.next_migration_number(dirname)
|
|
14
|
+
ActiveRecord::Migration.next_migration_number(current_migration_number(dirname) + 1)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def create_initializer
|
|
18
|
+
template "initializer.rb", "config/initializers/argus_trail.rb"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def create_core_migration
|
|
22
|
+
migration_template "create_argus_trail_tables.rb.erb",
|
|
23
|
+
"db/migrate/create_argus_trail_tables.rb"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def mount_engine
|
|
27
|
+
routes_file = File.expand_path("config/routes.rb", destination_root)
|
|
28
|
+
return unless File.exist?(routes_file)
|
|
29
|
+
return if File.read(routes_file).include?("Argus::Trail::Engine")
|
|
30
|
+
|
|
31
|
+
route 'mount Argus::Trail::Engine => "/admin/access"'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def show_readme
|
|
35
|
+
readme "POST_INSTALL" if behavior == :invoke
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def migration_version
|
|
41
|
+
"[#{ActiveRecord::Migration.current_version}]"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
========================================================================
|
|
2
|
+
Argus::Trail installed
|
|
3
|
+
========================================================================
|
|
4
|
+
|
|
5
|
+
Next steps:
|
|
6
|
+
|
|
7
|
+
1. Run the migrations:
|
|
8
|
+
bin/rails db:migrate
|
|
9
|
+
|
|
10
|
+
2. Add one line to the user/account model you configured as actor_class_name.
|
|
11
|
+
No migration needed on that model — roles live in the engine's own
|
|
12
|
+
polymorphic join table, so an actor can hold any number of roles:
|
|
13
|
+
|
|
14
|
+
class User < ApplicationRecord
|
|
15
|
+
include Argus::Trail::Actor
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
3. Tell the engine who's making each change, once, in your ApplicationController:
|
|
19
|
+
|
|
20
|
+
class ApplicationController < ActionController::Base
|
|
21
|
+
before_action { Argus::Trail.current_actor = current_user }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
4. If you have Pundit in your Gemfile, define policies for the engine's
|
|
25
|
+
records so its admin screens know who's allowed in, e.g.:
|
|
26
|
+
|
|
27
|
+
class Argus::Trail::RolePolicy < ApplicationPolicy
|
|
28
|
+
def index? = user.admin?
|
|
29
|
+
def show? = user.admin?
|
|
30
|
+
# ...
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Do the same for Argus::Trail::PermissionPolicy and
|
|
34
|
+
Argus::Trail::AuditEntryPolicy. No Pundit? Set config.authorize_with
|
|
35
|
+
in config/initializers/argus_trail.rb instead.
|
|
36
|
+
|
|
37
|
+
5. Visit the mounted engine (default /admin/access, see config/routes.rb)
|
|
38
|
+
to manage roles, permissions, and view the audit log.
|
|
39
|
+
|
|
40
|
+
Want to customize the HTML? Run:
|
|
41
|
+
bin/rails generate argus:trail:views
|
|
42
|
+
to copy the views into app/views/argus/trail for editing.
|
|
43
|
+
========================================================================
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
class CreateArgusTrailTables < ActiveRecord::Migration<%= migration_version %>
|
|
2
|
+
def change
|
|
3
|
+
create_table :argus_trail_roles do |t|
|
|
4
|
+
t.string :name, null: false
|
|
5
|
+
t.string :description
|
|
6
|
+
t.timestamps
|
|
7
|
+
end
|
|
8
|
+
add_index :argus_trail_roles, :name, unique: true
|
|
9
|
+
|
|
10
|
+
create_table :argus_trail_permissions do |t|
|
|
11
|
+
t.string :name, null: false
|
|
12
|
+
t.string :description
|
|
13
|
+
t.timestamps
|
|
14
|
+
end
|
|
15
|
+
add_index :argus_trail_permissions, :name, unique: true
|
|
16
|
+
|
|
17
|
+
create_table :argus_trail_role_permissions do |t|
|
|
18
|
+
t.references :role, null: false, foreign_key: { to_table: :argus_trail_roles }
|
|
19
|
+
t.references :permission, null: false, foreign_key: { to_table: :argus_trail_permissions }
|
|
20
|
+
t.timestamps
|
|
21
|
+
end
|
|
22
|
+
add_index :argus_trail_role_permissions, [ :role_id, :permission_id ], unique: true,
|
|
23
|
+
name: "index_argus_trail_role_permissions_on_role_id_and_permission_id"
|
|
24
|
+
|
|
25
|
+
# Polymorphic join between any actor class (include Argus::Trail::Actor)
|
|
26
|
+
# and a role — engine-owned, so no migration is needed on your own
|
|
27
|
+
# actor/user table. An actor may hold any number of roles.
|
|
28
|
+
create_table :argus_trail_role_assignments do |t|
|
|
29
|
+
t.references :actor, polymorphic: true, null: false
|
|
30
|
+
t.references :role, null: false, foreign_key: { to_table: :argus_trail_roles }
|
|
31
|
+
t.timestamps
|
|
32
|
+
end
|
|
33
|
+
add_index :argus_trail_role_assignments, [ :actor_type, :actor_id, :role_id ], unique: true,
|
|
34
|
+
name: "index_argus_trail_role_assignments_on_actor_and_role"
|
|
35
|
+
|
|
36
|
+
create_table :argus_trail_audit_entries do |t|
|
|
37
|
+
t.string :event_type, null: false
|
|
38
|
+
t.references :subject, polymorphic: true, null: false
|
|
39
|
+
t.references :changed_by, polymorphic: true, null: true
|
|
40
|
+
t.references :role, foreign_key: { to_table: :argus_trail_roles }
|
|
41
|
+
t.references :permission, foreign_key: { to_table: :argus_trail_permissions }
|
|
42
|
+
t.text :metadata
|
|
43
|
+
t.datetime :created_at, null: false
|
|
44
|
+
end
|
|
45
|
+
add_index :argus_trail_audit_entries, :event_type
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Argus::Trail.configure do |config|
|
|
2
|
+
# The class name of your app's user/account model — the one that gets
|
|
3
|
+
# `include Argus::Trail::Actor`. No column is added to this model's own
|
|
4
|
+
# table; roles are tracked in the engine's own polymorphic join table, so
|
|
5
|
+
# an actor may hold any number of roles (0..N).
|
|
6
|
+
config.actor_class_name = "User"
|
|
7
|
+
|
|
8
|
+
# Rename the engine's Role/Permission/RolePermission model classes — useful
|
|
9
|
+
# if "Role"/"Permission" already collide with another gem or one of your
|
|
10
|
+
# own models. These still back onto the engine's own tables
|
|
11
|
+
# (argus_trail_roles / argus_trail_permissions / argus_trail_role_permissions)
|
|
12
|
+
# — this renames the class, it does not let you point at a pre-existing
|
|
13
|
+
# table with a different schema.
|
|
14
|
+
# config.role_class_name = "Argus::Trail::Role"
|
|
15
|
+
# config.permission_class_name = "Argus::Trail::Permission"
|
|
16
|
+
# config.role_permission_class_name = "Argus::Trail::RolePermission"
|
|
17
|
+
|
|
18
|
+
# How the engine looks up "who made this change" when writing an audit
|
|
19
|
+
# entry. Defaults to a per-request actor set via:
|
|
20
|
+
# # in your ApplicationController
|
|
21
|
+
# before_action { Argus::Trail.current_actor = current_user }
|
|
22
|
+
# Override entirely for jobs/console usage, e.g. `-> { SomeJob.current_actor }`.
|
|
23
|
+
# config.changed_by_resolver = -> { Argus::Trail.current_actor }
|
|
24
|
+
|
|
25
|
+
# Gate for who may use the roles/permissions/audit-log admin screens.
|
|
26
|
+
# Left unset, Argus::Trail falls back to Pundit if it's in your Gemfile
|
|
27
|
+
# (define Argus::Trail::RolePolicy / PermissionPolicy / AuditEntryPolicy)
|
|
28
|
+
# — otherwise it raises until you set one of the two.
|
|
29
|
+
# config.authorize_with = ->(controller, record_or_class) { controller.current_user&.admin? }
|
|
30
|
+
|
|
31
|
+
# The method the engine calls on its controllers to get the logged-in actor.
|
|
32
|
+
# config.current_actor_method = :current_user
|
|
33
|
+
|
|
34
|
+
# Rows per page on the roles/permissions/audit-log admin screens.
|
|
35
|
+
# config.per_page = 30
|
|
36
|
+
|
|
37
|
+
# Render engine screens inside one of your app's own layouts instead of
|
|
38
|
+
# the engine's self-contained Tailwind-CDN layout.
|
|
39
|
+
# config.layout = "application"
|
|
40
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
|
|
3
|
+
module Argus
|
|
4
|
+
module Trail
|
|
5
|
+
module Generators
|
|
6
|
+
class ViewsGenerator < Rails::Generators::Base
|
|
7
|
+
source_root Argus::Trail::Engine.root.join("app", "views")
|
|
8
|
+
|
|
9
|
+
desc "Copies Argus::Trail's views into your app for full override"
|
|
10
|
+
|
|
11
|
+
def copy_views
|
|
12
|
+
directory "argus/trail", "app/views/argus/trail"
|
|
13
|
+
directory "layouts/argus/trail", "app/views/layouts/argus/trail"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: argus-trail
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Ram Laxman Yadav
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-07-11 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rails
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '6.1'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '6.1'
|
|
27
|
+
description: Plug-and-play role/permission management with a unified audit log of
|
|
28
|
+
role reassignments and permission grants/revokes, shipped as a mountable engine
|
|
29
|
+
with paginated HTML admin screens and generators for install/views/config. Agnostic
|
|
30
|
+
to auth (works standalone, auto-integrates with Pundit) and pagination (auto-integrates
|
|
31
|
+
with Kaminari).
|
|
32
|
+
email:
|
|
33
|
+
- yadavramlaxman@gmail.com
|
|
34
|
+
executables: []
|
|
35
|
+
extensions: []
|
|
36
|
+
extra_rdoc_files: []
|
|
37
|
+
files:
|
|
38
|
+
- MIT-LICENSE
|
|
39
|
+
- README.md
|
|
40
|
+
- Rakefile
|
|
41
|
+
- app/controllers/argus/trail/application_controller.rb
|
|
42
|
+
- app/controllers/argus/trail/audit_entries_controller.rb
|
|
43
|
+
- app/controllers/argus/trail/permissions_controller.rb
|
|
44
|
+
- app/controllers/argus/trail/roles_controller.rb
|
|
45
|
+
- app/helpers/argus/trail/application_helper.rb
|
|
46
|
+
- app/models/argus/trail/application_record.rb
|
|
47
|
+
- app/models/argus/trail/audit_entry.rb
|
|
48
|
+
- app/models/argus/trail/permission.rb
|
|
49
|
+
- app/models/argus/trail/role.rb
|
|
50
|
+
- app/models/argus/trail/role_assignment.rb
|
|
51
|
+
- app/models/argus/trail/role_permission.rb
|
|
52
|
+
- app/views/argus/trail/audit_entries/index.html.erb
|
|
53
|
+
- app/views/argus/trail/pagination/_simple_pager.html.erb
|
|
54
|
+
- app/views/argus/trail/permissions/_form.html.erb
|
|
55
|
+
- app/views/argus/trail/permissions/edit.html.erb
|
|
56
|
+
- app/views/argus/trail/permissions/index.html.erb
|
|
57
|
+
- app/views/argus/trail/permissions/new.html.erb
|
|
58
|
+
- app/views/argus/trail/permissions/show.html.erb
|
|
59
|
+
- app/views/argus/trail/roles/_form.html.erb
|
|
60
|
+
- app/views/argus/trail/roles/edit.html.erb
|
|
61
|
+
- app/views/argus/trail/roles/index.html.erb
|
|
62
|
+
- app/views/argus/trail/roles/new.html.erb
|
|
63
|
+
- app/views/argus/trail/roles/show.html.erb
|
|
64
|
+
- app/views/layouts/argus/trail/application.html.erb
|
|
65
|
+
- config/routes.rb
|
|
66
|
+
- lib/argus/trail.rb
|
|
67
|
+
- lib/argus/trail/actor.rb
|
|
68
|
+
- lib/argus/trail/configuration.rb
|
|
69
|
+
- lib/argus/trail/current.rb
|
|
70
|
+
- lib/argus/trail/engine.rb
|
|
71
|
+
- lib/argus/trail/pagination.rb
|
|
72
|
+
- lib/argus/trail/version.rb
|
|
73
|
+
- lib/generators/argus/trail/config/config_generator.rb
|
|
74
|
+
- lib/generators/argus/trail/install/install_generator.rb
|
|
75
|
+
- lib/generators/argus/trail/install/templates/POST_INSTALL
|
|
76
|
+
- lib/generators/argus/trail/install/templates/create_argus_trail_tables.rb.erb
|
|
77
|
+
- lib/generators/argus/trail/install/templates/initializer.rb
|
|
78
|
+
- lib/generators/argus/trail/views/views_generator.rb
|
|
79
|
+
homepage: https://github.com/reddoorz/argus-trail
|
|
80
|
+
licenses:
|
|
81
|
+
- MIT
|
|
82
|
+
metadata:
|
|
83
|
+
homepage_uri: https://github.com/reddoorz/argus-trail
|
|
84
|
+
source_code_uri: https://github.com/reddoorz/argus-trail
|
|
85
|
+
post_install_message:
|
|
86
|
+
rdoc_options: []
|
|
87
|
+
require_paths:
|
|
88
|
+
- lib
|
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
90
|
+
requirements:
|
|
91
|
+
- - ">="
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: '3.1'
|
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
|
+
requirements:
|
|
96
|
+
- - ">="
|
|
97
|
+
- !ruby/object:Gem::Version
|
|
98
|
+
version: '0'
|
|
99
|
+
requirements: []
|
|
100
|
+
rubygems_version: 3.4.10
|
|
101
|
+
signing_key:
|
|
102
|
+
specification_version: 4
|
|
103
|
+
summary: Mountable Rails engine for roles, permissions, and an audit trail of who
|
|
104
|
+
changed what.
|
|
105
|
+
test_files: []
|