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.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +176 -0
  4. data/Rakefile +6 -0
  5. data/app/controllers/argus/trail/application_controller.rb +45 -0
  6. data/app/controllers/argus/trail/audit_entries_controller.rb +19 -0
  7. data/app/controllers/argus/trail/permissions_controller.rb +65 -0
  8. data/app/controllers/argus/trail/roles_controller.rb +73 -0
  9. data/app/helpers/argus/trail/application_helper.rb +34 -0
  10. data/app/models/argus/trail/application_record.rb +7 -0
  11. data/app/models/argus/trail/audit_entry.rb +38 -0
  12. data/app/models/argus/trail/permission.rb +11 -0
  13. data/app/models/argus/trail/role.rb +53 -0
  14. data/app/models/argus/trail/role_assignment.rb +13 -0
  15. data/app/models/argus/trail/role_permission.rb +10 -0
  16. data/app/views/argus/trail/audit_entries/index.html.erb +94 -0
  17. data/app/views/argus/trail/pagination/_simple_pager.html.erb +9 -0
  18. data/app/views/argus/trail/permissions/_form.html.erb +29 -0
  19. data/app/views/argus/trail/permissions/edit.html.erb +10 -0
  20. data/app/views/argus/trail/permissions/index.html.erb +47 -0
  21. data/app/views/argus/trail/permissions/new.html.erb +10 -0
  22. data/app/views/argus/trail/permissions/show.html.erb +27 -0
  23. data/app/views/argus/trail/roles/_form.html.erb +50 -0
  24. data/app/views/argus/trail/roles/edit.html.erb +10 -0
  25. data/app/views/argus/trail/roles/index.html.erb +68 -0
  26. data/app/views/argus/trail/roles/new.html.erb +10 -0
  27. data/app/views/argus/trail/roles/show.html.erb +52 -0
  28. data/app/views/layouts/argus/trail/application.html.erb +38 -0
  29. data/config/routes.rb +7 -0
  30. data/lib/argus/trail/actor.rb +67 -0
  31. data/lib/argus/trail/configuration.rb +46 -0
  32. data/lib/argus/trail/current.rb +7 -0
  33. data/lib/argus/trail/engine.rb +13 -0
  34. data/lib/argus/trail/pagination.rb +41 -0
  35. data/lib/argus/trail/version.rb +5 -0
  36. data/lib/argus/trail.rb +30 -0
  37. data/lib/generators/argus/trail/config/config_generator.rb +21 -0
  38. data/lib/generators/argus/trail/install/install_generator.rb +46 -0
  39. data/lib/generators/argus/trail/install/templates/POST_INSTALL +43 -0
  40. data/lib/generators/argus/trail/install/templates/create_argus_trail_tables.rb.erb +47 -0
  41. data/lib/generators/argus/trail/install/templates/initializer.rb +40 -0
  42. data/lib/generators/argus/trail/views/views_generator.rb +18 -0
  43. 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
@@ -0,0 +1,5 @@
1
+ module Argus
2
+ module Trail
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -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: []