rails_audit_log-graphql 0.3.0 → 0.5.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 +4 -4
- data/CHANGELOG.md +17 -0
- data/README.md +120 -0
- data/ROADMAP.md +0 -18
- data/lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb +40 -7
- data/lib/rails_audit_log/graphql/subscriptions/audit_log_entry_created.rb +20 -0
- data/lib/rails_audit_log/graphql/subscriptions/audit_log_subscriptions_mixin.rb +17 -0
- data/lib/rails_audit_log/graphql/subscriptions/broadcaster.rb +43 -0
- data/lib/rails_audit_log/graphql/types/base_subscription.rb +10 -0
- data/lib/rails_audit_log/graphql/version.rb +1 -1
- data/lib/rails_audit_log/graphql.rb +4 -0
- data/sig/rails_audit_log/graphql.rbs +33 -3
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f64cce54638f8999c6489e0881a1fedfcb447b0b5b8f52270a0d8247719c8f19
|
|
4
|
+
data.tar.gz: 4b1225952a5a6adce3a5a03b804360765b0c70b9ad9a9688db96ba34139430c5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0b54b242a022b49d1917dd3c0370f96bde5ec210dad8959a34bc424132c7efd97aa0e1f781cebd0eaf21056b3b29c2c0c9632c08e94a4b0e2da851afe57044e5
|
|
7
|
+
data.tar.gz: fb448e67961e641eb6ce89081e832082cfa886856ccbd5f4d5de767d1bd21835d38034e6dd55a4d00b1f633f58da6a094e5d8e4e4886c24a6aece095386023f2
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.5.0] - 2026-06-04
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `forTenant:` argument on `auditLogEntry`, `auditLogEntries`, and `auditLogEntriesConnection` — explicitly scope results to a tenant ID; overrides auto-tenant
|
|
8
|
+
- Auto-tenant scoping — when `RailsAuditLog.current_tenant` is configured, all queries automatically filter to the current tenant without requiring an explicit argument
|
|
9
|
+
- `auditLogEntriesCount(event:, itemType:, since:)` — new aggregation query returning the count of matching entries; respects auto-tenant
|
|
10
|
+
|
|
11
|
+
## [0.4.0] - 2026-06-04
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `AuditLogEntryCreated` subscription — `auditLogEntryCreated(itemType:, itemId:)` subscribes to new entries for a specific record; `auditLogEntryCreated(actorId:)` subscribes to all entries by a specific actor
|
|
16
|
+
- `AuditLogSubscriptionsMixin` — include into host app's `SubscriptionType` to add the `auditLogEntryCreated` subscription field
|
|
17
|
+
- `BaseSubscription` base class for all gem GraphQL subscription types
|
|
18
|
+
- `Broadcaster` — call `Broadcaster.new(schema: MySchema).start` in an initializer to relay `rails_audit_log.entry_created` `ActiveSupport::Notifications` events into GraphQL subscription triggers; supports `stop` to unsubscribe
|
|
19
|
+
|
|
3
20
|
## [0.3.0] - 2026-06-03
|
|
4
21
|
|
|
5
22
|
### Added
|
data/README.md
CHANGED
|
@@ -20,7 +20,13 @@ A [graphql-ruby](https://graphql-ruby.org) API layer for the [`rails_audit_log`]
|
|
|
20
20
|
- [auditLogEntry](#auditlogentryid-id-auditlogentry)
|
|
21
21
|
- [auditLogEntries](#auditlogentries-auditlogentry)
|
|
22
22
|
- [auditLogEntriesConnection](#auditlogentriesconnection-auditlogentryconnection)
|
|
23
|
+
- [auditLogEntriesCount](#auditlogentriescount-int)
|
|
24
|
+
- [Tenant scoping](#tenant-scoping)
|
|
23
25
|
- [Authentication](#authentication)
|
|
26
|
+
- [Subscriptions](#subscriptions)
|
|
27
|
+
- [AuditLogSubscriptionsMixin](#auditlogsubscriptionsmixin)
|
|
28
|
+
- [auditLogEntryCreated](#auditlogentrycreated)
|
|
29
|
+
- [Broadcaster](#broadcaster)
|
|
24
30
|
- [Development](#development)
|
|
25
31
|
- [Contributing](#contributing)
|
|
26
32
|
- [License](#license)
|
|
@@ -148,6 +154,7 @@ List entries with optional filters and offset pagination.
|
|
|
148
154
|
| `until` | `ISO8601DateTime` | — | Return entries created at or before this time |
|
|
149
155
|
| `touching` | `String` | — | Filter to entries that changed a specific attribute |
|
|
150
156
|
| `orderBy` | `AuditLogEntrySortInput` | `CREATED_AT DESC` | Sort field and direction |
|
|
157
|
+
| `forTenant` | `String` | — | Scope to a specific tenant ID; overrides auto-tenant |
|
|
151
158
|
| `page` | `Int` | `1` | Page number (1-based) |
|
|
152
159
|
| `perPage` | `Int` | `25` | Results per page |
|
|
153
160
|
|
|
@@ -163,6 +170,7 @@ Same filters as `auditLogEntries`, but returns a [Relay-style connection](https:
|
|
|
163
170
|
| `itemType` | `String` | Filter by audited model class name |
|
|
164
171
|
| `itemId` | `ID` | Filter by audited record ID |
|
|
165
172
|
| `actorId` | `ID` | Filter by actor ID |
|
|
173
|
+
| `forTenant` | `String` | Scope to a specific tenant ID; overrides auto-tenant |
|
|
166
174
|
| `first` | `Int` | Return the first N edges after `after` |
|
|
167
175
|
| `after` | `String` | Cursor to paginate forward from |
|
|
168
176
|
| `last` | `Int` | Return the last N edges before `before` |
|
|
@@ -203,6 +211,40 @@ Results are ordered by `created_at DESC`.
|
|
|
203
211
|
|
|
204
212
|
[↑ Back to top](#table-of-contents)
|
|
205
213
|
|
|
214
|
+
#### `auditLogEntriesCount(...): Int!`
|
|
215
|
+
|
|
216
|
+
Returns the count of matching audit log entries. Respects auto-tenant when `RailsAuditLog.current_tenant` is configured.
|
|
217
|
+
|
|
218
|
+
| Argument | Type | Description |
|
|
219
|
+
|---|---|---|
|
|
220
|
+
| `event` | `String` | Filter by event type (`create`, `update`, `destroy`) |
|
|
221
|
+
| `itemType` | `String` | Filter by audited model class name |
|
|
222
|
+
| `since` | `ISO8601DateTime` | Count entries created at or after this time |
|
|
223
|
+
|
|
224
|
+
```graphql
|
|
225
|
+
{ auditLogEntriesCount(event: "update", itemType: "Post") }
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
[↑ Back to top](#table-of-contents)
|
|
229
|
+
|
|
230
|
+
#### Tenant scoping
|
|
231
|
+
|
|
232
|
+
When `RailsAuditLog.current_tenant` is configured, all queries automatically filter to the current tenant:
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
RailsAuditLog.configure do |c|
|
|
236
|
+
c.current_tenant { Current.tenant_id }
|
|
237
|
+
end
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
To override or explicitly specify a tenant per query, use the `forTenant:` argument (available on `auditLogEntry`, `auditLogEntries`, and `auditLogEntriesConnection`):
|
|
241
|
+
|
|
242
|
+
```graphql
|
|
243
|
+
{ auditLogEntries(forTenant: "acme") { id event } }
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
[↑ Back to top](#table-of-contents)
|
|
247
|
+
|
|
206
248
|
### Authentication
|
|
207
249
|
|
|
208
250
|
If `RailsAuditLog.authenticate` is configured, the block is called with the GraphQL context before every query. Return a truthy value to allow access; return falsy to raise `GraphQL::ExecutionError` with `"Unauthorized"`.
|
|
@@ -217,6 +259,84 @@ If no authenticate block is set, all queries are permitted.
|
|
|
217
259
|
|
|
218
260
|
[↑ Back to top](#table-of-contents)
|
|
219
261
|
|
|
262
|
+
### Subscriptions
|
|
263
|
+
|
|
264
|
+
Requires Action Cable in the host application.
|
|
265
|
+
|
|
266
|
+
#### AuditLogSubscriptionsMixin
|
|
267
|
+
|
|
268
|
+
Include `RailsAuditLog::Graphql::Subscriptions::AuditLogSubscriptionsMixin` into your app's `SubscriptionType` to add the `auditLogEntryCreated` field. Your schema must also use `GraphQL::Subscriptions::ActionCableSubscriptions`.
|
|
269
|
+
|
|
270
|
+
```ruby
|
|
271
|
+
# app/graphql/types/subscription_type.rb
|
|
272
|
+
class Types::SubscriptionType < Types::BaseObject
|
|
273
|
+
include RailsAuditLog::Graphql::Subscriptions::AuditLogSubscriptionsMixin
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# app/graphql/my_schema.rb
|
|
277
|
+
class MySchema < GraphQL::Schema
|
|
278
|
+
query Types::QueryType
|
|
279
|
+
subscription Types::SubscriptionType
|
|
280
|
+
use GraphQL::Subscriptions::ActionCableSubscriptions
|
|
281
|
+
end
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
#### `auditLogEntryCreated`
|
|
285
|
+
|
|
286
|
+
Fires when a new `RailsAuditLog::AuditLogEntry` is created. Accepts one of two argument combinations:
|
|
287
|
+
|
|
288
|
+
| Argument | Type | Description |
|
|
289
|
+
|---|---|---|
|
|
290
|
+
| `itemType` | `String` | Model class name to scope the subscription to |
|
|
291
|
+
| `itemId` | `ID` | Record ID to scope the subscription to |
|
|
292
|
+
| `actorId` | `ID` | Actor ID — subscribe to all entries by a specific actor |
|
|
293
|
+
|
|
294
|
+
Subscribe to all changes on a specific record:
|
|
295
|
+
|
|
296
|
+
```graphql
|
|
297
|
+
subscription {
|
|
298
|
+
auditLogEntryCreated(itemType: "Post", itemId: "42") {
|
|
299
|
+
id
|
|
300
|
+
event
|
|
301
|
+
diff { attribute from to }
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Subscribe to all entries by a specific actor:
|
|
307
|
+
|
|
308
|
+
```graphql
|
|
309
|
+
subscription {
|
|
310
|
+
auditLogEntryCreated(actorId: "7") {
|
|
311
|
+
id
|
|
312
|
+
event
|
|
313
|
+
itemType
|
|
314
|
+
itemId
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### Broadcaster
|
|
320
|
+
|
|
321
|
+
`RailsAuditLog::Graphql::Subscriptions::Broadcaster` bridges `ActiveSupport::Notifications` (fired by `RailsAuditLog::Streaming::NotificationsAdapter` or `ActiveJobAdapter`) to GraphQL subscription triggers. Start it in an initializer:
|
|
322
|
+
|
|
323
|
+
```ruby
|
|
324
|
+
# config/initializers/rails_audit_log_graphql.rb
|
|
325
|
+
RailsAuditLog.configure do |c|
|
|
326
|
+
c.streaming_adapter = RailsAuditLog::Streaming::NotificationsAdapter.new
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
Rails.application.config.after_initialize do
|
|
330
|
+
RailsAuditLog::Graphql::Subscriptions::Broadcaster.new(schema: MySchema).start
|
|
331
|
+
end
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
For each entry, the broadcaster triggers:
|
|
335
|
+
- `auditLogEntryCreated(itemType:, itemId:)` — notifies record-specific subscribers
|
|
336
|
+
- `auditLogEntryCreated(actorId:)` — notifies actor-specific subscribers (when an actor is present)
|
|
337
|
+
|
|
338
|
+
[↑ Back to top](#table-of-contents)
|
|
339
|
+
|
|
220
340
|
## Development
|
|
221
341
|
|
|
222
342
|
```bash
|
data/ROADMAP.md
CHANGED
|
@@ -4,24 +4,6 @@ This gem adds a GraphQL API layer on top of [`rails_audit_log`](https://github.c
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
## 0.4.0 — Subscriptions
|
|
8
|
-
|
|
9
|
-
Requires Action Cable in the host application.
|
|
10
|
-
|
|
11
|
-
- **`auditLogEntryCreated(itemType:, itemId:)`** — subscribe to new entries for a specific record
|
|
12
|
-
- **`auditLogEntryCreated(actorId:)`** — subscribe to all entries by a specific actor
|
|
13
|
-
- Hooks into `RailsAuditLog::Streaming::NotificationsAdapter` to trigger broadcasts
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## 0.5.0 — Multi-tenancy & Advanced Filtering
|
|
18
|
-
|
|
19
|
-
- **Tenant scoping** — automatically scope queries via `RailsAuditLog.current_tenant` when configured
|
|
20
|
-
- **`forTenant:` argument** — explicit tenant filter on `auditLogEntries`
|
|
21
|
-
- **Aggregations** — `auditLogEntriesCount(event:, itemType:, since:)` for dashboard metrics
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
7
|
## 0.6.0 — Performance & Safety
|
|
26
8
|
|
|
27
9
|
- **Dataloader batch loading** — batch-resolve polymorphic `actor` and `item` associations using graphql-ruby's `dataloader` to eliminate N+1 queries on list responses
|
|
@@ -14,6 +14,8 @@ module RailsAuditLog
|
|
|
14
14
|
) do
|
|
15
15
|
argument :id, GraphQL::Types::ID, required: true,
|
|
16
16
|
description: "ID of the audit log entry."
|
|
17
|
+
argument :for_tenant, String, required: false,
|
|
18
|
+
description: "Scope to a specific tenant ID. Overrides auto-tenant when RailsAuditLog.current_tenant is configured."
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
base.field(
|
|
@@ -31,6 +33,8 @@ module RailsAuditLog
|
|
|
31
33
|
argument :until, GraphQL::Types::ISO8601DateTime, required: false, as: :until_time, description: "Return entries created at or before this time."
|
|
32
34
|
argument :touching, String, required: false, description: "Filter to entries that changed a specific attribute (matches object_changes keys)."
|
|
33
35
|
argument :order_by, RailsAuditLog::Graphql::InputObjects::AuditLogEntrySortInput, required: false, description: "Sort order. Defaults to CREATED_AT DESC."
|
|
36
|
+
argument :for_tenant, String, required: false,
|
|
37
|
+
description: "Scope to a specific tenant ID. Overrides auto-tenant when RailsAuditLog.current_tenant is configured."
|
|
34
38
|
argument :page, GraphQL::Types::Int, required: false, default_value: 1, description: "Page number (1-based)."
|
|
35
39
|
argument :per_page, GraphQL::Types::Int, required: false, default_value: 25, description: "Number of results per page."
|
|
36
40
|
end
|
|
@@ -50,28 +54,55 @@ module RailsAuditLog
|
|
|
50
54
|
argument :until, GraphQL::Types::ISO8601DateTime, required: false, as: :until_time, description: "Return entries created at or before this time."
|
|
51
55
|
argument :touching, String, required: false, description: "Filter to entries that changed a specific attribute (matches object_changes keys)."
|
|
52
56
|
argument :order_by, RailsAuditLog::Graphql::InputObjects::AuditLogEntrySortInput, required: false, description: "Sort order. Defaults to CREATED_AT DESC."
|
|
57
|
+
argument :for_tenant, String, required: false,
|
|
58
|
+
description: "Scope to a specific tenant ID. Overrides auto-tenant when RailsAuditLog.current_tenant is configured."
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
base.field(
|
|
62
|
+
:audit_log_entries_count,
|
|
63
|
+
GraphQL::Types::Int,
|
|
64
|
+
null: false,
|
|
65
|
+
description: "Count audit log entries with optional filters. Respects auto-tenant when RailsAuditLog.current_tenant is configured.",
|
|
66
|
+
resolver_method: :resolve_audit_log_entries_count
|
|
67
|
+
) do
|
|
68
|
+
argument :event, String, required: false, description: "Filter by event type (create, update, destroy)."
|
|
69
|
+
argument :item_type, String, required: false, description: "Filter by audited model class name."
|
|
70
|
+
argument :since, GraphQL::Types::ISO8601DateTime, required: false, description: "Count entries created at or after this time."
|
|
53
71
|
end
|
|
54
72
|
end
|
|
55
73
|
|
|
56
|
-
def resolve_audit_log_entry(id:)
|
|
74
|
+
def resolve_audit_log_entry(id:, for_tenant: nil)
|
|
57
75
|
check_authentication!
|
|
58
|
-
RailsAuditLog
|
|
76
|
+
tenant_id = for_tenant || RailsAuditLog.current_tenant&.call
|
|
77
|
+
base = tenant_id ? RailsAuditLog::AuditLogEntry.for_tenant(tenant_id) : RailsAuditLog::AuditLogEntry
|
|
78
|
+
base.find_by(id: id)
|
|
59
79
|
end
|
|
60
80
|
|
|
61
|
-
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, page: 1, per_page: 25)
|
|
81
|
+
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)
|
|
62
82
|
check_authentication!
|
|
63
|
-
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)
|
|
83
|
+
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)
|
|
64
84
|
scope.limit(per_page).offset((page - 1) * per_page)
|
|
65
85
|
end
|
|
66
86
|
|
|
67
|
-
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)
|
|
87
|
+
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)
|
|
68
88
|
check_authentication!
|
|
69
|
-
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)
|
|
89
|
+
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)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def resolve_audit_log_entries_count(event: nil, item_type: nil, since: nil)
|
|
93
|
+
check_authentication!
|
|
94
|
+
scope = RailsAuditLog::AuditLogEntry.all
|
|
95
|
+
scope = scope.where(event: event) if event
|
|
96
|
+
scope = scope.where(item_type: item_type) if item_type
|
|
97
|
+
scope = scope.where("created_at >= ?", since) if since
|
|
98
|
+
tenant_id = RailsAuditLog.current_tenant&.call
|
|
99
|
+
scope = scope.for_tenant(tenant_id) if tenant_id
|
|
100
|
+
scope.count
|
|
70
101
|
end
|
|
71
102
|
|
|
72
103
|
private
|
|
73
104
|
|
|
74
|
-
def build_scope(event: nil, item_type: nil, item_id: nil, actor_id: nil, since: nil, until_time: nil, touching: nil, order_by: nil)
|
|
105
|
+
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)
|
|
75
106
|
sort_field = order_by&.field || :created_at
|
|
76
107
|
sort_direction = order_by&.direction || :desc
|
|
77
108
|
scope = RailsAuditLog::AuditLogEntry.order(sort_field => sort_direction)
|
|
@@ -85,6 +116,8 @@ module RailsAuditLog
|
|
|
85
116
|
safe = ActiveRecord::Base.sanitize_sql_like(touching)
|
|
86
117
|
scope = scope.where("object_changes LIKE ?", "%\"#{safe}\":%")
|
|
87
118
|
end
|
|
119
|
+
tenant_id = for_tenant || RailsAuditLog.current_tenant&.call
|
|
120
|
+
scope = scope.for_tenant(tenant_id) if tenant_id
|
|
88
121
|
scope
|
|
89
122
|
end
|
|
90
123
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsAuditLog
|
|
4
|
+
module Graphql
|
|
5
|
+
module Subscriptions
|
|
6
|
+
class AuditLogEntryCreated < Types::BaseSubscription
|
|
7
|
+
description "Fires when a new audit log entry is created."
|
|
8
|
+
|
|
9
|
+
argument :item_type, String, required: false,
|
|
10
|
+
description: "Filter to entries for a specific model class name."
|
|
11
|
+
argument :item_id, GraphQL::Types::ID, required: false,
|
|
12
|
+
description: "Filter to entries for a specific record ID."
|
|
13
|
+
argument :actor_id, GraphQL::Types::ID, required: false,
|
|
14
|
+
description: "Filter to entries by a specific actor ID."
|
|
15
|
+
|
|
16
|
+
type Types::AuditLogEntryType, null: false
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsAuditLog
|
|
4
|
+
module Graphql
|
|
5
|
+
module Subscriptions
|
|
6
|
+
module AuditLogSubscriptionsMixin
|
|
7
|
+
def self.included(base)
|
|
8
|
+
base.field(
|
|
9
|
+
:audit_log_entry_created,
|
|
10
|
+
subscription: AuditLogEntryCreated,
|
|
11
|
+
description: "Fires when a new audit log entry is created."
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsAuditLog
|
|
4
|
+
module Graphql
|
|
5
|
+
module Subscriptions
|
|
6
|
+
class Broadcaster
|
|
7
|
+
EVENT = "rails_audit_log.entry_created"
|
|
8
|
+
|
|
9
|
+
def initialize(schema:)
|
|
10
|
+
@schema = schema
|
|
11
|
+
@subscriber = nil
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def start
|
|
15
|
+
@subscriber = ActiveSupport::Notifications.subscribe(EVENT) do |*, payload|
|
|
16
|
+
broadcast(payload[:entry])
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def stop
|
|
21
|
+
ActiveSupport::Notifications.unsubscribe(@subscriber) if @subscriber
|
|
22
|
+
@subscriber = nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def broadcast(entry)
|
|
26
|
+
@schema.subscriptions.trigger(
|
|
27
|
+
"audit_log_entry_created",
|
|
28
|
+
{item_type: entry.item_type, item_id: entry.item_id.to_s},
|
|
29
|
+
entry
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
return unless entry.actor_id.present?
|
|
33
|
+
|
|
34
|
+
@schema.subscriptions.trigger(
|
|
35
|
+
"audit_log_entry_created",
|
|
36
|
+
{actor_id: entry.actor_id.to_s},
|
|
37
|
+
entry
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "graphql"
|
|
4
4
|
require_relative "graphql/version"
|
|
5
5
|
require_relative "graphql/types/base_object"
|
|
6
|
+
require_relative "graphql/types/base_subscription"
|
|
6
7
|
require_relative "graphql/types/diff_type"
|
|
7
8
|
require_relative "graphql/types/actor_type"
|
|
8
9
|
require_relative "graphql/types/audited_resource_type"
|
|
@@ -11,6 +12,9 @@ require_relative "graphql/types/sort_direction_enum"
|
|
|
11
12
|
require_relative "graphql/types/audit_log_entry_sort_field_enum"
|
|
12
13
|
require_relative "graphql/input_objects/audit_log_entry_sort_input"
|
|
13
14
|
require_relative "graphql/queries/audit_log_entries_query_mixin"
|
|
15
|
+
require_relative "graphql/subscriptions/audit_log_entry_created"
|
|
16
|
+
require_relative "graphql/subscriptions/audit_log_subscriptions_mixin"
|
|
17
|
+
require_relative "graphql/subscriptions/broadcaster"
|
|
14
18
|
|
|
15
19
|
module RailsAuditLog
|
|
16
20
|
module Graphql
|
|
@@ -6,6 +6,9 @@ module RailsAuditLog
|
|
|
6
6
|
class BaseObject < GraphQL::Schema::Object
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
+
class BaseSubscription < GraphQL::Schema::Subscription
|
|
10
|
+
end
|
|
11
|
+
|
|
9
12
|
class DiffType < BaseObject
|
|
10
13
|
def attribute: () -> String
|
|
11
14
|
def from: () -> untyped
|
|
@@ -51,11 +54,29 @@ module RailsAuditLog
|
|
|
51
54
|
end
|
|
52
55
|
end
|
|
53
56
|
|
|
57
|
+
module Subscriptions
|
|
58
|
+
class AuditLogEntryCreated < Types::BaseSubscription
|
|
59
|
+
def subscribe: (?item_type: String?, ?item_id: String?, ?actor_id: String?) -> :no_response
|
|
60
|
+
def update: (?item_type: String?, ?item_id: String?, ?actor_id: String?) -> untyped
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
module AuditLogSubscriptionsMixin
|
|
64
|
+
def self.included: (untyped base) -> void
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
class Broadcaster
|
|
68
|
+
def initialize: (schema: untyped) -> void
|
|
69
|
+
def start: () -> void
|
|
70
|
+
def stop: () -> void
|
|
71
|
+
def broadcast: (untyped entry) -> void
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
54
75
|
module Queries
|
|
55
76
|
module AuditLogEntriesQueryMixin
|
|
56
77
|
def self.included: (untyped base) -> void
|
|
57
78
|
|
|
58
|
-
def resolve_audit_log_entry: (id: String) -> untyped
|
|
79
|
+
def resolve_audit_log_entry: (id: String, ?for_tenant: String?) -> untyped
|
|
59
80
|
|
|
60
81
|
def resolve_audit_log_entries: (
|
|
61
82
|
?event: String?,
|
|
@@ -66,6 +87,7 @@ module RailsAuditLog
|
|
|
66
87
|
?until_time: Time?,
|
|
67
88
|
?touching: String?,
|
|
68
89
|
?order_by: InputObjects::AuditLogEntrySortInput?,
|
|
90
|
+
?for_tenant: String?,
|
|
69
91
|
?page: Integer,
|
|
70
92
|
?per_page: Integer
|
|
71
93
|
) -> untyped
|
|
@@ -78,9 +100,16 @@ module RailsAuditLog
|
|
|
78
100
|
?since: Time?,
|
|
79
101
|
?until_time: Time?,
|
|
80
102
|
?touching: String?,
|
|
81
|
-
?order_by: InputObjects::AuditLogEntrySortInput
|
|
103
|
+
?order_by: InputObjects::AuditLogEntrySortInput?,
|
|
104
|
+
?for_tenant: String?
|
|
82
105
|
) -> untyped
|
|
83
106
|
|
|
107
|
+
def resolve_audit_log_entries_count: (
|
|
108
|
+
?event: String?,
|
|
109
|
+
?item_type: String?,
|
|
110
|
+
?since: Time?
|
|
111
|
+
) -> Integer
|
|
112
|
+
|
|
84
113
|
private
|
|
85
114
|
|
|
86
115
|
def build_scope: (
|
|
@@ -91,7 +120,8 @@ module RailsAuditLog
|
|
|
91
120
|
?since: Time?,
|
|
92
121
|
?until_time: Time?,
|
|
93
122
|
?touching: String?,
|
|
94
|
-
?order_by: InputObjects::AuditLogEntrySortInput
|
|
123
|
+
?order_by: InputObjects::AuditLogEntrySortInput?,
|
|
124
|
+
?for_tenant: String?
|
|
95
125
|
) -> untyped
|
|
96
126
|
|
|
97
127
|
def check_authentication!: () -> void
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_audit_log-graphql
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chuck Smith
|
|
@@ -86,11 +86,15 @@ files:
|
|
|
86
86
|
- lib/rails_audit_log/graphql/input_objects/audit_log_entry_sort_input.rb
|
|
87
87
|
- lib/rails_audit_log/graphql/queries/audit_log_entries_query_mixin.rb
|
|
88
88
|
- lib/rails_audit_log/graphql/release_tooling.rb
|
|
89
|
+
- lib/rails_audit_log/graphql/subscriptions/audit_log_entry_created.rb
|
|
90
|
+
- lib/rails_audit_log/graphql/subscriptions/audit_log_subscriptions_mixin.rb
|
|
91
|
+
- lib/rails_audit_log/graphql/subscriptions/broadcaster.rb
|
|
89
92
|
- lib/rails_audit_log/graphql/types/actor_type.rb
|
|
90
93
|
- lib/rails_audit_log/graphql/types/audit_log_entry_sort_field_enum.rb
|
|
91
94
|
- lib/rails_audit_log/graphql/types/audit_log_entry_type.rb
|
|
92
95
|
- lib/rails_audit_log/graphql/types/audited_resource_type.rb
|
|
93
96
|
- lib/rails_audit_log/graphql/types/base_object.rb
|
|
97
|
+
- lib/rails_audit_log/graphql/types/base_subscription.rb
|
|
94
98
|
- lib/rails_audit_log/graphql/types/diff_type.rb
|
|
95
99
|
- lib/rails_audit_log/graphql/types/sort_direction_enum.rb
|
|
96
100
|
- lib/rails_audit_log/graphql/version.rb
|