rails_audit_log-graphql 0.6.0 → 0.6.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 +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +6 -2
- data/lib/generators/rails_audit_log/graphql/install/install_generator.rb +22 -1
- data/lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb +22 -12
- data/lib/rails_audit_log/graphql/version.rb +1 -1
- data/sig/rails_audit_log/graphql.rbs +8 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a1df5ae47e9bae5cc635eb04372e8a84f3c484350f50284d98ab4602d9f2175c
|
|
4
|
+
data.tar.gz: 5bd2df5463caab8646bfab17973cd85343819b94fb189d6c3d52bbe65cbf11ce
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3899c333a5af6c7f9c1a05cfe1bc882f8464ad9da9d21ed677c75ce7ec6546a6181893d8a27f563822d46ed4bfb7d6f91e8349285d1bc83e3cc6aaae2a8d5147
|
|
7
|
+
data.tar.gz: cdc13b1d159a794f67fa1c46a3410b3196529dba59e234eba32147338d15e85a2478bcb676821738256792e4358100a4c07bc96cfb855c00d68db828807a1d48
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.6.1] - 2026-06-04
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `actorType:` filter argument on `auditLogEntries`, `auditLogEntriesConnection`, and `auditLogEntriesCount` — filter by actor model class name (e.g. `"User"`)
|
|
8
|
+
- `forTenant:` argument on `auditLogReify` and `auditLogEntriesCount` — consistent tenant scoping across all query fields; both also respect `RailsAuditLog.current_tenant` auto-tenant
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- `auditLogReify` return type changed from generic `JSON` to `AuditLogJson` for consistency with other entry fields
|
|
13
|
+
- `rails g rails_audit_log:graphql:install` now also injects `SchemaPlugin` into the host schema file (detected via `app/graphql/**/*schema*.rb` glob); `print_next_steps` updated to mention all available queries and the complexity config override
|
|
14
|
+
|
|
3
15
|
## [0.6.0] - 2026-06-04
|
|
4
16
|
|
|
5
17
|
### Added
|
data/README.md
CHANGED
|
@@ -152,6 +152,7 @@ List entries with optional filters and offset pagination.
|
|
|
152
152
|
| `itemType` | `String` | — | Filter by audited model class name |
|
|
153
153
|
| `itemId` | `ID` | — | Filter by audited record ID |
|
|
154
154
|
| `actorId` | `ID` | — | Filter by actor ID |
|
|
155
|
+
| `actorType` | `String` | — | Filter by actor model class name (e.g. `"User"`) |
|
|
155
156
|
| `since` | `ISO8601DateTime` | — | Return entries created at or after this time |
|
|
156
157
|
| `until` | `ISO8601DateTime` | — | Return entries created at or before this time |
|
|
157
158
|
| `touching` | `String` | — | Filter to entries that changed a specific attribute |
|
|
@@ -172,6 +173,7 @@ Same filters as `auditLogEntries`, but returns a [Relay-style connection](https:
|
|
|
172
173
|
| `itemType` | `String` | Filter by audited model class name |
|
|
173
174
|
| `itemId` | `ID` | Filter by audited record ID |
|
|
174
175
|
| `actorId` | `ID` | Filter by actor ID |
|
|
176
|
+
| `actorType` | `String` | Filter by actor model class name (e.g. `"User"`) |
|
|
175
177
|
| `forTenant` | `String` | Scope to a specific tenant ID; overrides auto-tenant |
|
|
176
178
|
| `first` | `Int` | Return the first N edges after `after` |
|
|
177
179
|
| `after` | `String` | Cursor to paginate forward from |
|
|
@@ -221,7 +223,9 @@ Returns the count of matching audit log entries. Respects auto-tenant when `Rail
|
|
|
221
223
|
|---|---|---|
|
|
222
224
|
| `event` | `String` | Filter by event type (`create`, `update`, `destroy`) |
|
|
223
225
|
| `itemType` | `String` | Filter by audited model class name |
|
|
226
|
+
| `actorType` | `String` | Filter by actor model class name (e.g. `"User"`) |
|
|
224
227
|
| `since` | `ISO8601DateTime` | Count entries created at or after this time |
|
|
228
|
+
| `forTenant` | `String` | Scope to a specific tenant ID; overrides auto-tenant |
|
|
225
229
|
|
|
226
230
|
```graphql
|
|
227
231
|
{ auditLogEntriesCount(event: "update", itemType: "Post") }
|
|
@@ -291,9 +295,9 @@ The plugin also adds `AuditLogActor.record` and `AuditedResource.record` fields
|
|
|
291
295
|
|
|
292
296
|
[↑ Back to top](#table-of-contents)
|
|
293
297
|
|
|
294
|
-
### `auditLogReify(itemType:, itemId:, at:):
|
|
298
|
+
### `auditLogReify(itemType:, itemId:, at:): AuditLogJson`
|
|
295
299
|
|
|
296
|
-
Reconstructs the attribute state of a record at a given point in time. Returns the attributes as
|
|
300
|
+
Reconstructs the attribute state of a record at a given point in time. Returns the attributes as `AuditLogJson`, or `nil` when no entry exists at or before `at` or the record was destroyed at that time. Accepts `forTenant:` and respects auto-tenant.
|
|
297
301
|
|
|
298
302
|
```graphql
|
|
299
303
|
{
|
|
@@ -7,10 +7,11 @@ module RailsAuditLog
|
|
|
7
7
|
module Graphql
|
|
8
8
|
class InstallGenerator < Rails::Generators::Base
|
|
9
9
|
source_root File.expand_path("templates", __dir__)
|
|
10
|
-
desc "Injects AuditLogEntriesQueryMixin into your GraphQL QueryType."
|
|
10
|
+
desc "Injects AuditLogEntriesQueryMixin into your GraphQL QueryType and SchemaPlugin into your schema."
|
|
11
11
|
|
|
12
12
|
QUERY_TYPE_PATH = "app/graphql/types/query_type.rb"
|
|
13
13
|
MIXIN = "RailsAuditLog::Graphql::Queries::AuditLogEntriesQueryMixin"
|
|
14
|
+
SCHEMA_PLUGIN = "RailsAuditLog::Graphql::SchemaPlugin"
|
|
14
15
|
|
|
15
16
|
def inject_mixin
|
|
16
17
|
if File.exist?(File.join(destination_root, QUERY_TYPE_PATH))
|
|
@@ -24,11 +25,31 @@ module RailsAuditLog
|
|
|
24
25
|
end
|
|
25
26
|
end
|
|
26
27
|
|
|
28
|
+
def inject_schema_plugin
|
|
29
|
+
schema_files = Dir.glob(File.join(destination_root, "app/graphql/**/*schema*.rb"))
|
|
30
|
+
if schema_files.any?
|
|
31
|
+
schema_path = schema_files.first.delete_prefix("#{destination_root}/")
|
|
32
|
+
inject_into_file schema_path,
|
|
33
|
+
" include #{SCHEMA_PLUGIN}\n",
|
|
34
|
+
after: /class\s+\S+\s*<\s*GraphQL::Schema\s*\n/
|
|
35
|
+
else
|
|
36
|
+
say ""
|
|
37
|
+
say "No schema file found. Add this line manually to your GraphQL::Schema subclass:", :yellow
|
|
38
|
+
say " include #{SCHEMA_PLUGIN}", :green
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
27
42
|
def print_next_steps
|
|
28
43
|
say ""
|
|
29
44
|
say "Done! Your GraphQL API now has:", :green
|
|
30
45
|
say " auditLogEntry(id: ID!): AuditLogEntry"
|
|
31
46
|
say " auditLogEntries(...): [AuditLogEntry!]!"
|
|
47
|
+
say " auditLogReify(itemType:, itemId:, at:): AuditLogJson"
|
|
48
|
+
say " auditLogEntriesCount(...): Int!"
|
|
49
|
+
say ""
|
|
50
|
+
say "SchemaPlugin applies complexity/depth limits and enables dataloader."
|
|
51
|
+
say "Override defaults in an initializer:"
|
|
52
|
+
say " RailsAuditLog::Graphql.max_complexity = 500"
|
|
32
53
|
say ""
|
|
33
54
|
say "See the README for full documentation."
|
|
34
55
|
end
|
|
@@ -29,6 +29,7 @@ module RailsAuditLog
|
|
|
29
29
|
argument :item_type, String, required: false, description: "Filter by audited model class name."
|
|
30
30
|
argument :item_id, GraphQL::Types::ID, required: false, description: "Filter by audited record ID."
|
|
31
31
|
argument :actor_id, GraphQL::Types::ID, required: false, description: "Filter by actor ID."
|
|
32
|
+
argument :actor_type, String, required: false, description: "Filter by actor model class name (e.g. \"User\")."
|
|
32
33
|
argument :since, GraphQL::Types::ISO8601DateTime, required: false, description: "Return entries created at or after this time."
|
|
33
34
|
argument :until, GraphQL::Types::ISO8601DateTime, required: false, as: :until_time, description: "Return entries created at or before this time."
|
|
34
35
|
argument :touching, String, required: false, description: "Filter to entries that changed a specific attribute (matches object_changes keys)."
|
|
@@ -50,6 +51,7 @@ module RailsAuditLog
|
|
|
50
51
|
argument :item_type, String, required: false, description: "Filter by audited model class name."
|
|
51
52
|
argument :item_id, GraphQL::Types::ID, required: false, description: "Filter by audited record ID."
|
|
52
53
|
argument :actor_id, GraphQL::Types::ID, required: false, description: "Filter by actor ID."
|
|
54
|
+
argument :actor_type, String, required: false, description: "Filter by actor model class name (e.g. \"User\")."
|
|
53
55
|
argument :since, GraphQL::Types::ISO8601DateTime, required: false, description: "Return entries created at or after this time."
|
|
54
56
|
argument :until, GraphQL::Types::ISO8601DateTime, required: false, as: :until_time, description: "Return entries created at or before this time."
|
|
55
57
|
argument :touching, String, required: false, description: "Filter to entries that changed a specific attribute (matches object_changes keys)."
|
|
@@ -60,7 +62,7 @@ module RailsAuditLog
|
|
|
60
62
|
|
|
61
63
|
base.field(
|
|
62
64
|
:audit_log_reify,
|
|
63
|
-
|
|
65
|
+
Types::AuditLogJsonScalar,
|
|
64
66
|
null: true,
|
|
65
67
|
description: "Reconstruct the attribute state of a record at a given point in time. Returns nil when no entry exists at or before `at`, or when the record was destroyed.",
|
|
66
68
|
resolver_method: :resolve_audit_log_reify
|
|
@@ -68,6 +70,8 @@ module RailsAuditLog
|
|
|
68
70
|
argument :item_type, String, required: true, description: "The audited model class name."
|
|
69
71
|
argument :item_id, GraphQL::Types::ID, required: true, description: "The audited record ID."
|
|
70
72
|
argument :at, GraphQL::Types::ISO8601DateTime, required: true, description: "Reconstruct state as of this time."
|
|
73
|
+
argument :for_tenant, String, required: false,
|
|
74
|
+
description: "Scope to a specific tenant ID. Overrides auto-tenant when RailsAuditLog.current_tenant is configured."
|
|
71
75
|
end
|
|
72
76
|
|
|
73
77
|
base.field(
|
|
@@ -79,7 +83,10 @@ module RailsAuditLog
|
|
|
79
83
|
) do
|
|
80
84
|
argument :event, String, required: false, description: "Filter by event type (create, update, destroy)."
|
|
81
85
|
argument :item_type, String, required: false, description: "Filter by audited model class name."
|
|
86
|
+
argument :actor_type, String, required: false, description: "Filter by actor model class name (e.g. \"User\")."
|
|
82
87
|
argument :since, GraphQL::Types::ISO8601DateTime, required: false, description: "Count entries created at or after this time."
|
|
88
|
+
argument :for_tenant, String, required: false,
|
|
89
|
+
description: "Scope to a specific tenant ID. Overrides auto-tenant when RailsAuditLog.current_tenant is configured."
|
|
83
90
|
end
|
|
84
91
|
end
|
|
85
92
|
|
|
@@ -90,43 +97,45 @@ module RailsAuditLog
|
|
|
90
97
|
base.find_by(id: id)
|
|
91
98
|
end
|
|
92
99
|
|
|
93
|
-
def resolve_audit_log_entries(event: nil, item_type: nil, item_id: nil, actor_id: nil, since: nil, until_time: nil, touching: nil, order_by: nil, for_tenant: nil, page: 1, per_page: 25)
|
|
100
|
+
def resolve_audit_log_entries(event: nil, item_type: nil, item_id: nil, actor_id: nil, actor_type: nil, since: nil, until_time: nil, touching: nil, order_by: nil, for_tenant: nil, page: 1, per_page: 25)
|
|
94
101
|
check_authentication!
|
|
95
|
-
scope = build_scope(event: event, item_type: item_type, item_id: item_id, actor_id: actor_id, since: since, until_time: until_time, touching: touching, order_by: order_by, for_tenant: for_tenant)
|
|
102
|
+
scope = build_scope(event: event, item_type: item_type, item_id: item_id, actor_id: actor_id, actor_type: actor_type, since: since, until_time: until_time, touching: touching, order_by: order_by, for_tenant: for_tenant)
|
|
96
103
|
scope.limit(per_page).offset((page - 1) * per_page)
|
|
97
104
|
end
|
|
98
105
|
|
|
99
|
-
def resolve_audit_log_entries_connection(event: nil, item_type: nil, item_id: nil, actor_id: nil, since: nil, until_time: nil, touching: nil, order_by: nil, for_tenant: nil)
|
|
106
|
+
def resolve_audit_log_entries_connection(event: nil, item_type: nil, item_id: nil, actor_id: nil, actor_type: nil, since: nil, until_time: nil, touching: nil, order_by: nil, for_tenant: nil)
|
|
100
107
|
check_authentication!
|
|
101
|
-
build_scope(event: event, item_type: item_type, item_id: item_id, actor_id: actor_id, since: since, until_time: until_time, touching: touching, order_by: order_by, for_tenant: for_tenant)
|
|
108
|
+
build_scope(event: event, item_type: item_type, item_id: item_id, actor_id: actor_id, actor_type: actor_type, since: since, until_time: until_time, touching: touching, order_by: order_by, for_tenant: for_tenant)
|
|
102
109
|
end
|
|
103
110
|
|
|
104
|
-
def resolve_audit_log_reify(item_type:, item_id:, at:)
|
|
111
|
+
def resolve_audit_log_reify(item_type:, item_id:, at:, for_tenant: nil)
|
|
105
112
|
check_authentication!
|
|
106
|
-
|
|
113
|
+
tenant_id = for_tenant || RailsAuditLog.current_tenant&.call
|
|
114
|
+
scope = RailsAuditLog::AuditLogEntry
|
|
107
115
|
.where(item_type: item_type, item_id: item_id)
|
|
108
116
|
.where("created_at <= ?", at)
|
|
109
|
-
|
|
110
|
-
|
|
117
|
+
scope = scope.for_tenant(tenant_id) if tenant_id
|
|
118
|
+
entry = scope.order(created_at: :desc, id: :desc).first
|
|
111
119
|
return nil if entry.nil? || entry.event == "destroy"
|
|
112
120
|
to_attrs = (entry.object_changes || {}).transform_values { |v| v[1] }
|
|
113
121
|
entry.object.present? ? entry.object.merge(to_attrs) : to_attrs
|
|
114
122
|
end
|
|
115
123
|
|
|
116
|
-
def resolve_audit_log_entries_count(event: nil, item_type: nil, since: nil)
|
|
124
|
+
def resolve_audit_log_entries_count(event: nil, item_type: nil, actor_type: nil, since: nil, for_tenant: nil)
|
|
117
125
|
check_authentication!
|
|
118
126
|
scope = RailsAuditLog::AuditLogEntry.all
|
|
119
127
|
scope = scope.where(event: event) if event
|
|
120
128
|
scope = scope.where(item_type: item_type) if item_type
|
|
129
|
+
scope = scope.where(actor_type: actor_type) if actor_type
|
|
121
130
|
scope = scope.where("created_at >= ?", since) if since
|
|
122
|
-
tenant_id = RailsAuditLog.current_tenant&.call
|
|
131
|
+
tenant_id = for_tenant || RailsAuditLog.current_tenant&.call
|
|
123
132
|
scope = scope.for_tenant(tenant_id) if tenant_id
|
|
124
133
|
scope.count
|
|
125
134
|
end
|
|
126
135
|
|
|
127
136
|
private
|
|
128
137
|
|
|
129
|
-
def build_scope(event: nil, item_type: nil, item_id: nil, actor_id: nil, since: nil, until_time: nil, touching: nil, order_by: nil, for_tenant: nil)
|
|
138
|
+
def build_scope(event: nil, item_type: nil, item_id: nil, actor_id: nil, actor_type: nil, since: nil, until_time: nil, touching: nil, order_by: nil, for_tenant: nil)
|
|
130
139
|
sort_field = order_by&.field || :created_at
|
|
131
140
|
sort_direction = order_by&.direction || :desc
|
|
132
141
|
scope = RailsAuditLog::AuditLogEntry.order(sort_field => sort_direction)
|
|
@@ -134,6 +143,7 @@ module RailsAuditLog
|
|
|
134
143
|
scope = scope.where(item_type: item_type) if item_type
|
|
135
144
|
scope = scope.where(item_id: item_id) if item_id
|
|
136
145
|
scope = scope.where(actor_id: actor_id) if actor_id
|
|
146
|
+
scope = scope.where(actor_type: actor_type) if actor_type
|
|
137
147
|
scope = scope.where("created_at >= ?", since) if since
|
|
138
148
|
scope = scope.where("created_at <= ?", until_time) if until_time
|
|
139
149
|
if touching
|
|
@@ -112,6 +112,7 @@ module RailsAuditLog
|
|
|
112
112
|
?item_type: String?,
|
|
113
113
|
?item_id: String?,
|
|
114
114
|
?actor_id: String?,
|
|
115
|
+
?actor_type: String?,
|
|
115
116
|
?since: Time?,
|
|
116
117
|
?until_time: Time?,
|
|
117
118
|
?touching: String?,
|
|
@@ -126,6 +127,7 @@ module RailsAuditLog
|
|
|
126
127
|
?item_type: String?,
|
|
127
128
|
?item_id: String?,
|
|
128
129
|
?actor_id: String?,
|
|
130
|
+
?actor_type: String?,
|
|
129
131
|
?since: Time?,
|
|
130
132
|
?until_time: Time?,
|
|
131
133
|
?touching: String?,
|
|
@@ -136,13 +138,16 @@ module RailsAuditLog
|
|
|
136
138
|
def resolve_audit_log_reify: (
|
|
137
139
|
item_type: String,
|
|
138
140
|
item_id: String,
|
|
139
|
-
at: Time
|
|
141
|
+
at: Time,
|
|
142
|
+
?for_tenant: String?
|
|
140
143
|
) -> Hash[String, untyped]?
|
|
141
144
|
|
|
142
145
|
def resolve_audit_log_entries_count: (
|
|
143
146
|
?event: String?,
|
|
144
147
|
?item_type: String?,
|
|
145
|
-
?
|
|
148
|
+
?actor_type: String?,
|
|
149
|
+
?since: Time?,
|
|
150
|
+
?for_tenant: String?
|
|
146
151
|
) -> Integer
|
|
147
152
|
|
|
148
153
|
private
|
|
@@ -152,6 +157,7 @@ module RailsAuditLog
|
|
|
152
157
|
?item_type: String?,
|
|
153
158
|
?item_id: String?,
|
|
154
159
|
?actor_id: String?,
|
|
160
|
+
?actor_type: String?,
|
|
155
161
|
?since: Time?,
|
|
156
162
|
?until_time: Time?,
|
|
157
163
|
?touching: String?,
|