audiences 1.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/audiences/contexts_controller.rb +3 -3
- data/app/controllers/audiences/scim_proxy_controller.rb +2 -4
- data/app/models/audiences/context/locating.rb +39 -0
- data/app/models/audiences/context.rb +1 -8
- data/app/models/audiences/context_users.rb +1 -1
- data/app/models/audiences/criterion_users.rb +1 -1
- data/app/models/audiences/external_user.rb +8 -2
- data/config/routes.rb +4 -5
- data/db/migrate/20240722025634_add_relation_to_context.rb +11 -0
- data/docs/CHANGELOG.md +6 -0
- data/docs/README.md +78 -38
- data/lib/audiences/configuration.rb +84 -0
- data/lib/audiences/engine.rb +8 -0
- data/lib/audiences/model.rb +34 -0
- data/lib/audiences/scim/resource.rb +19 -0
- data/lib/audiences/scim/resources_query.rb +6 -7
- data/lib/audiences/scim.rb +10 -8
- data/lib/audiences/version.rb +1 -1
- data/lib/audiences.rb +7 -31
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a764dbb90f7727e7b0054227fedb0d8eee691ab7e65a5c0007413121de492965
|
4
|
+
data.tar.gz: f4c0fc7843aae456f8df4e2aed78615fc3169257cdebe9a28578443ad32c0949
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b04b83f5314e11bdd03d373632683bfe59e39eb2ded010c8b49ccbaf914904f4a05dc9788589488a670ae168df19293a175bc9ade59044568d0f27b8e1769d1
|
7
|
+
data.tar.gz: a4abbd7408fceb3cc6349000003cddc78ceb564f2824d93dfbb27e340373603dc6cb9c844136954a95e12a374e1439216cd0d202cb75c6dd8b4feb9f91441545
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Audiences
|
4
4
|
class ContextsController < ApplicationController
|
5
5
|
def show
|
6
|
-
render_context Audiences.load(params.require(:key))
|
6
|
+
render_context Audiences::Context.load(params.require(:key))
|
7
7
|
end
|
8
8
|
|
9
9
|
def update
|
@@ -23,7 +23,7 @@ module Audiences
|
|
23
23
|
private
|
24
24
|
|
25
25
|
def current_context
|
26
|
-
@current_context ||= Audiences.load(params.require(:key))
|
26
|
+
@current_context ||= Audiences::Context.load(params.require(:key))
|
27
27
|
end
|
28
28
|
|
29
29
|
def current_criterion
|
@@ -44,7 +44,7 @@ module Audiences
|
|
44
44
|
params.permit(
|
45
45
|
:match_all,
|
46
46
|
criteria: [groups: {}],
|
47
|
-
extra_users: [:
|
47
|
+
extra_users: [:externalId, :displayName, { photos: %i[type value] }]
|
48
48
|
).to_h.symbolize_keys
|
49
49
|
end
|
50
50
|
end
|
@@ -3,10 +3,8 @@
|
|
3
3
|
module Audiences
|
4
4
|
class ScimProxyController < ApplicationController
|
5
5
|
def get
|
6
|
-
resources = Audiences::Scim.
|
7
|
-
|
8
|
-
filter: params[:filter]
|
9
|
-
)
|
6
|
+
resources = Audiences::Scim.resource(params[:scim_path].to_sym)
|
7
|
+
.query(filter: params[:filter])
|
10
8
|
|
11
9
|
render json: resources
|
12
10
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Audiences
|
4
|
+
class Context
|
5
|
+
module Locating
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
SIGNED_GID_RESOURCE = "audiences"
|
9
|
+
|
10
|
+
class_methods do
|
11
|
+
# Finds or creates a context for the given owner/relation
|
12
|
+
#
|
13
|
+
# @private
|
14
|
+
# @param owner [Class<ActiveRecord::Base>] an active record owning the context
|
15
|
+
# @Param relation [String,Symbol] a context relation (i.e.: :members)
|
16
|
+
# @return [Audiences::Context]
|
17
|
+
def for(owner, relation: nil)
|
18
|
+
where(owner: owner, relation: relation).first_or_create!
|
19
|
+
end
|
20
|
+
|
21
|
+
# Loads a context given a signed GlobalID key
|
22
|
+
#
|
23
|
+
# @private
|
24
|
+
# @param key [String] signed GlobalID key
|
25
|
+
# @return [Audiences::Context]
|
26
|
+
# @yield [Audiences::Context]
|
27
|
+
def load(key)
|
28
|
+
GlobalID::Locator.locate_signed(key, for: SIGNED_GID_RESOURCE).tap do |ctx|
|
29
|
+
yield ctx if block_given?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def signed_key
|
35
|
+
to_sgid(for: SIGNED_GID_RESOURCE)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -6,6 +6,7 @@ module Audiences
|
|
6
6
|
# users (#criteria, #match_all, #extra_users).
|
7
7
|
#
|
8
8
|
class Context < ApplicationRecord
|
9
|
+
include Locating
|
9
10
|
include ::Audiences::MembershipGroup
|
10
11
|
|
11
12
|
belongs_to :owner, polymorphic: true
|
@@ -18,14 +19,6 @@ module Audiences
|
|
18
19
|
self.extra_users = []
|
19
20
|
end
|
20
21
|
|
21
|
-
# Finds or creates a context for the given owner
|
22
|
-
#
|
23
|
-
# @private
|
24
|
-
# @return [Audiences::Context]
|
25
|
-
def self.for(owner)
|
26
|
-
where(owner: owner).first_or_create!
|
27
|
-
end
|
28
|
-
|
29
22
|
def refresh_users!
|
30
23
|
criteria.each(&:refresh_users!)
|
31
24
|
update!(users: ContextUsers.new(self).to_a)
|
@@ -21,7 +21,7 @@ module Audiences
|
|
21
21
|
|
22
22
|
def groups_users(group_ids)
|
23
23
|
filter = group_ids.map { "groups.value eq #{_1}" }.join(" OR ")
|
24
|
-
users = Audiences::Scim.
|
24
|
+
users = Audiences::Scim.resource(:Users).query(filter: filter)
|
25
25
|
ExternalUser.wrap(users.all)
|
26
26
|
end
|
27
27
|
end
|
@@ -2,13 +2,19 @@
|
|
2
2
|
|
3
3
|
module Audiences
|
4
4
|
class ExternalUser < ApplicationRecord
|
5
|
-
|
5
|
+
if Audiences.config.identity_class
|
6
|
+
belongs_to :identity, class_name: Audiences.config.identity_class, # rubocop:disable Rails/ReflectionClassName
|
7
|
+
primary_key: Audiences.config.identity_key,
|
8
|
+
foreign_key: :user_id,
|
9
|
+
optional: true,
|
10
|
+
inverse_of: false
|
11
|
+
end
|
6
12
|
|
7
13
|
def self.wrap(resources)
|
8
14
|
return [] unless resources&.any?
|
9
15
|
|
10
16
|
attrs = resources.map do |data|
|
11
|
-
{ user_id: data["
|
17
|
+
{ user_id: data["externalId"], data: data, created_at: Time.current, updated_at: Time.current }
|
12
18
|
end
|
13
19
|
unique_by = :user_id if connection.supports_insert_conflict_target?
|
14
20
|
upsert_all(attrs, unique_by: unique_by) # rubocop:disable Rails/SkipsModelValidations
|
data/config/routes.rb
CHANGED
@@ -8,13 +8,12 @@ Audiences::Engine.routes.draw do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
Rails.application.routes.draw do
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
audiences.route_for(:signed_context, key: Audiences.sign(owner), **options)
|
11
|
+
direct :audience_context do |owner, relation = nil|
|
12
|
+
context = Audiences::Context.for(owner, relation: relation)
|
13
|
+
Audiences::Engine.routes.url_helpers.route_for(:signed_context, key: context.signed_key, **url_options)
|
15
14
|
end
|
16
15
|
|
17
16
|
direct :audience_scim_proxy do |options|
|
18
|
-
|
17
|
+
Audiences::Engine.routes.url_helpers.route_for(:scim_proxy, **url_options, **options)
|
19
18
|
end
|
20
19
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class AddRelationToContext < ActiveRecord::Migration[6.1]
|
4
|
+
def change
|
5
|
+
add_column :audiences_contexts, :relation, :string, null: true
|
6
|
+
remove_index :audiences_contexts, %w[owner_type owner_id], unique: true
|
7
|
+
add_index :audiences_contexts, %w[owner_type owner_id relation],
|
8
|
+
unique: true,
|
9
|
+
name: "index_audiences_contexts_on_owner_type_owner_id_relation"
|
10
|
+
end
|
11
|
+
end
|
data/docs/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# Version 1.2.0 (2024-07-24)
|
4
|
+
|
5
|
+
- Add `has_audience` and the ability to attach multiple audiences to the same owner [#363](https://github.com/powerhome/audiences/pull/363)
|
6
|
+
- Audiences.config/configure helpers [#359](https://github.com/powerhome/audiences/pull/359)
|
7
|
+
- Adjust user id to SCIM Protocol [#356](https://github.com/powerhome/audiences/pull/356)
|
8
|
+
|
3
9
|
# Version 1.1.2 (2024-06-18)
|
4
10
|
|
5
11
|
- Ignore empty groups in criterion [#354](https://github.com/powerhome/audiences/pull/354)
|
data/docs/README.md
CHANGED
@@ -2,80 +2,120 @@
|
|
2
2
|
|
3
3
|
"Audiences" is a SCIM-integrated notifier for real-time Rails actions based on group changes.
|
4
4
|
|
5
|
-
##
|
5
|
+
## Installation
|
6
6
|
|
7
|
-
|
7
|
+
Add this line to your application's Gemfile:
|
8
8
|
|
9
|
-
|
9
|
+
```ruby
|
10
|
+
gem "audiences"
|
11
|
+
```
|
10
12
|
|
11
|
-
|
13
|
+
Then execute:
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
+
```bash
|
16
|
+
$ bundle install
|
17
|
+
```
|
15
18
|
|
16
|
-
|
19
|
+
Or install it yourself with:
|
17
20
|
|
18
|
-
|
21
|
+
```bash
|
22
|
+
$ gem install audiences
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
### Creating/Managing Audiences
|
28
|
+
|
29
|
+
An audience is tied to an owning model within your application. In this document, we'll use a `Team` model as an example. To create audiences for a team using `audiences-react`, render an audiences editor for your model.
|
19
30
|
|
20
|
-
|
31
|
+
This can be done with an unobtrusive JS renderer like `react-rails` or a custom one as shown in [our dummy app](../audiences/spec/dummy/app/frontend/entrypoints/application.js). The editor requires two arguments:
|
32
|
+
|
33
|
+
- The context URI: `audience_context_url(owner, relation)` helper
|
34
|
+
- The SCIM endpoint: `audience_scim_proxy_url` helper if using the [proxy](#configuring-the-scim-proxy), or the SCIM endpoint directly.
|
35
|
+
|
36
|
+
### Configuring Audiences
|
37
|
+
|
38
|
+
The `Audience.config.scim` should point to the SCIM endpoint. Configure the endpoint and the credentials/headers as follows:
|
21
39
|
|
22
40
|
```ruby
|
23
|
-
Audiences
|
24
|
-
|
25
|
-
|
26
|
-
)
|
41
|
+
Audiences.configure do |config|
|
42
|
+
config.scim = {
|
43
|
+
uri: ENV.fetch("SCIM_V2_API"),
|
44
|
+
headers: { "Authorization" => "Bearer #{ENV.fetch('SCIM_V2_TOKEN')}" }
|
45
|
+
}
|
46
|
+
end
|
27
47
|
```
|
28
48
|
|
29
|
-
###
|
49
|
+
### Adding Audiences to a Model
|
30
50
|
|
31
|
-
|
51
|
+
A model object can contain multiple audience contexts using the `has_audience` module helper, which is added to ActiveRecord automatically when configured:
|
32
52
|
|
33
53
|
```ruby
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
54
|
+
Audiences.configure do |config|
|
55
|
+
config.identity_class = "User"
|
56
|
+
config.identity_key = "login"
|
38
57
|
end
|
39
58
|
```
|
40
59
|
|
41
|
-
|
60
|
+
The `identity_class` represents the SCIM user within the app domain, and the `identity_key` maps directly to the SCIM User's `externalId`.
|
61
|
+
|
62
|
+
Once configured, add audience contexts to a model:
|
42
63
|
|
43
64
|
```ruby
|
44
|
-
|
45
|
-
|
46
|
-
|
65
|
+
class Survey < ApplicationRecord
|
66
|
+
has_audience :responders
|
67
|
+
has_audience :supervisors
|
47
68
|
end
|
48
69
|
```
|
49
70
|
|
50
|
-
|
71
|
+
### Listening to Audience Changes
|
51
72
|
|
52
|
-
|
53
|
-
- [job class](../spec/dummy/app/jobs/update_memberships_job.rb)
|
73
|
+
Audiences allows your app to keep up with mutable groups of people. To react to audience changes, subscribe to audiences related to a certain owner type and handle changes through a block:
|
54
74
|
|
55
|
-
|
75
|
+
```ruby
|
76
|
+
Audiences.configure do |config|
|
77
|
+
config.notifications do
|
78
|
+
subscribe Team do |context|
|
79
|
+
team.update_memberships(context.users)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
```
|
56
84
|
|
57
|
-
|
85
|
+
Or schedule an ActiveJob:
|
58
86
|
|
59
87
|
```ruby
|
60
|
-
|
88
|
+
Audiences.configure do |config|
|
89
|
+
config.notifications do
|
90
|
+
subscribe Group, job: UpdateGroupMembershipsJob
|
91
|
+
subscribe Team, job: UpdateTeamMembershipsJob.set(queue: "low")
|
92
|
+
end
|
93
|
+
end
|
61
94
|
```
|
62
95
|
|
63
|
-
|
96
|
+
The notifications block is executed every time the app is loaded or reloaded through a `to_prepare` block, allowing autoloaded constants such as model and job classes to be referenced.
|
64
97
|
|
65
|
-
|
66
|
-
$ bundle
|
67
|
-
```
|
98
|
+
See a working example in our dummy app:
|
68
99
|
|
69
|
-
|
100
|
+
- [Initializer](../spec/dummy/config/initializers/audiences.rb)
|
101
|
+
- [Job class](../spec/dummy/app/jobs/update_memberships_job.rb)
|
102
|
+
- [Example owning model](../spec/dummy/app/models/example_owner.rb)
|
70
103
|
|
71
|
-
|
72
|
-
|
104
|
+
### SCIM Resource Attributes
|
105
|
+
|
106
|
+
Configure which attributes are requested from the SCIM backend for each resource type. `Audiences` requires at least `id` and `displayName`, and also requests `photos` and `externalId` for users by default. To request additional attributes:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
Audiences.configure do |config|
|
110
|
+
config.resource :Users, attributes: "id,externalId,displayName,photos,name"
|
111
|
+
config.resource :Groups, attributes: "id,displayName,mfaRequired"
|
112
|
+
end
|
73
113
|
```
|
74
114
|
|
75
115
|
## Contributing
|
76
116
|
|
77
|
-
|
117
|
+
For more information, see the [development guide](../../docs/development.md).
|
78
118
|
|
79
119
|
## License
|
80
120
|
|
81
|
-
|
121
|
+
This gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Audiences
|
4
|
+
include ActiveSupport::Configurable
|
5
|
+
|
6
|
+
# Configuration options
|
7
|
+
|
8
|
+
#
|
9
|
+
# Identity model representing a SCIM User in the current application. I.e.: "User"
|
10
|
+
#
|
11
|
+
config_accessor :identity_class
|
12
|
+
|
13
|
+
#
|
14
|
+
# The key attribute on `identity_class` matching with the SCIM User externalId.
|
15
|
+
# This configuration defaults to `:id`
|
16
|
+
#
|
17
|
+
config_accessor(:identity_key) { :id }
|
18
|
+
|
19
|
+
#
|
20
|
+
# SCIM service configurations. This should be a Hash containint, at least, the URI.
|
21
|
+
#
|
22
|
+
# I.e.:
|
23
|
+
#
|
24
|
+
# Audiences.configure do |config|
|
25
|
+
# config.scim = { uri: "http://localhost/api/scim" }
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# It can also contain HTTP headers, such as "Authorization":
|
29
|
+
#
|
30
|
+
# I.e.:
|
31
|
+
#
|
32
|
+
# Audiences.configure do |config|
|
33
|
+
# config.scim = {
|
34
|
+
# uri: "http://localhost/api/scim",
|
35
|
+
# headers: { "Authorization" => "Bearer auth-token" }
|
36
|
+
# }
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
config_accessor :scim
|
40
|
+
|
41
|
+
#
|
42
|
+
# Resources defaults. Change this configuration via the `resource` helper.
|
43
|
+
# This configuration lists the current Audiences accessible resource defaults,
|
44
|
+
# and defaults to Users only. To add other resource types for criteria building.
|
45
|
+
#
|
46
|
+
# @see `resource`.
|
47
|
+
#
|
48
|
+
config_accessor :resources do
|
49
|
+
{ Users: Scim::Resource.new(type: :Users, attributes: "id,externalId,displayName,photos") }
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Configures a resource default.
|
54
|
+
#
|
55
|
+
# @param type [Symbol] the resource type in plural, as in scim (i.e.: :Users)
|
56
|
+
# @param attributes [String] the list of attributes to fetch for the resource (i.e.: "id,externalId,displayName")
|
57
|
+
# @see [Audiences::Scim::Resource]
|
58
|
+
def config.resource(type:, **kwargs)
|
59
|
+
config.resources[type] = Scim::Resource.new(type: type, **kwargs)
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Notifications configurations.
|
64
|
+
# Within this block, you should be able to easily register job classes to execute as
|
65
|
+
# audiences are changed. Notice: this block is executed every time your app initializes
|
66
|
+
# or reloads. This allows you to reference reloaded constants, like job names:
|
67
|
+
#
|
68
|
+
# I.e.:
|
69
|
+
#
|
70
|
+
# Audiences.configure do |config|
|
71
|
+
# config.notifications do
|
72
|
+
# subscribe CallQueue, job: CallQueueMembersSyncJob
|
73
|
+
# subscribe ChatRoom, job: ChatRoomMembersSyncJob
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# This block is executed
|
78
|
+
# @see [Audiences::Notifications]
|
79
|
+
def config.notifications(&block)
|
80
|
+
Rails.application.config.to_prepare do
|
81
|
+
Notifications.class_eval(&block)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/audiences/engine.rb
CHANGED
@@ -9,5 +9,13 @@ module Audiences
|
|
9
9
|
#
|
10
10
|
class Engine < ::Rails::Engine
|
11
11
|
isolate_namespace Audiences
|
12
|
+
|
13
|
+
initializer "audiences.model" do
|
14
|
+
if Audiences.config.identity_class
|
15
|
+
ActiveSupport.on_load(:active_record) do
|
16
|
+
include Audiences::Model
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
12
20
|
end
|
13
21
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Audiences
|
4
|
+
module Model
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
class_methods do
|
8
|
+
#
|
9
|
+
# Adds relationships between the audience context and the owner object
|
10
|
+
#
|
11
|
+
# @param name [Symbol,String] the member relationship name
|
12
|
+
#
|
13
|
+
# rubocop:disable Naming/PredicateName,Metrics/MethodLength,Metrics/AbcSize
|
14
|
+
def has_audience(name)
|
15
|
+
has_one :"#{name}_context", -> { where(relation: name) },
|
16
|
+
as: :owner, dependent: :destroy,
|
17
|
+
class_name: "Audiences::Context"
|
18
|
+
has_many :"#{name}_external_users",
|
19
|
+
through: :"#{name}_context", source: :users,
|
20
|
+
class_name: "Audiences::ExternalUser"
|
21
|
+
has_many name, -> { readonly }, through: :"#{name}_external_users", source: :identity
|
22
|
+
|
23
|
+
scope :"with_#{name}", -> { includes(name) }
|
24
|
+
scope :"with_#{name}_context", -> { includes(:"#{name}_context") }
|
25
|
+
scope :"with_#{name}_external_users", -> { includes(:"#{name}_external_users") }
|
26
|
+
|
27
|
+
after_initialize if: :new_record? do
|
28
|
+
association(:"#{name}_context").build
|
29
|
+
end
|
30
|
+
end
|
31
|
+
# rubocop:enable Naming/PredicateName,Metrics/MethodLength,Metrics/AbcSize
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Audiences
|
4
|
+
module Scim
|
5
|
+
class Resource
|
6
|
+
attr_accessor :options, :type
|
7
|
+
|
8
|
+
def initialize(type:, attributes: "id,externalId,displayName", **options)
|
9
|
+
@type = type
|
10
|
+
@options = options
|
11
|
+
@options[:attributes] = attributes
|
12
|
+
end
|
13
|
+
|
14
|
+
def query(**options)
|
15
|
+
ResourcesQuery.new(Scim.client, resource: self, **@options, **options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -9,12 +9,12 @@ module Audiences
|
|
9
9
|
class ResourcesQuery
|
10
10
|
include Enumerable
|
11
11
|
|
12
|
-
attr_reader :
|
12
|
+
attr_reader :options, :resource
|
13
13
|
|
14
|
-
def initialize(client,
|
14
|
+
def initialize(client, resource:, **options)
|
15
15
|
@client = client
|
16
|
-
@
|
17
|
-
@
|
16
|
+
@resource = resource
|
17
|
+
@options = options
|
18
18
|
end
|
19
19
|
|
20
20
|
def all
|
@@ -53,14 +53,13 @@ module Audiences
|
|
53
53
|
def next_page
|
54
54
|
return unless next_page?
|
55
55
|
|
56
|
-
ResourcesQuery.new(@client,
|
57
|
-
startIndex: next_index)
|
56
|
+
ResourcesQuery.new(@client, resource: @resource, **@options, startIndex: next_index)
|
58
57
|
end
|
59
58
|
|
60
59
|
private
|
61
60
|
|
62
61
|
def response
|
63
|
-
@response ||= @client.perform_request(path: @
|
62
|
+
@response ||= @client.perform_request(path: @resource.type, method: :Get, query: @options)
|
64
63
|
end
|
65
64
|
end
|
66
65
|
end
|
data/lib/audiences/scim.rb
CHANGED
@@ -1,19 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "scim/client"
|
4
|
-
require_relative "scim/resources_query"
|
5
|
-
|
6
3
|
module Audiences
|
7
4
|
module Scim
|
8
|
-
|
9
|
-
|
5
|
+
autoload :Client, "audiences/scim/client"
|
6
|
+
autoload :Resource, "audiences/scim/resource"
|
7
|
+
autoload :ResourcesQuery, "audiences/scim/resources_query"
|
10
8
|
|
11
9
|
module_function
|
12
10
|
|
13
|
-
def
|
14
|
-
|
11
|
+
def client
|
12
|
+
Client.new(**Audiences.config.scim)
|
13
|
+
end
|
15
14
|
|
16
|
-
|
15
|
+
def resource(type, **options)
|
16
|
+
Audiences.config.resources.fetch(type) do
|
17
|
+
Resource.new(type: type, **options)
|
18
|
+
end
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
data/lib/audiences/version.rb
CHANGED
data/lib/audiences.rb
CHANGED
@@ -1,37 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "audiences/version"
|
4
|
-
require "audiences/scim"
|
5
|
-
require "audiences/notifications"
|
6
|
-
|
7
3
|
# Audiences system
|
8
4
|
# Audiences pushes notifications to your rails app when a
|
9
5
|
# SCIM backend updates a user, notifying matching audiences.
|
10
6
|
#
|
11
7
|
module Audiences
|
12
|
-
|
8
|
+
autoload :Model, "audiences/model"
|
9
|
+
autoload :Notifications, "audiences/notifications"
|
10
|
+
autoload :Scim, "audiences/scim"
|
11
|
+
autoload :VERSION, "audiences/version"
|
13
12
|
|
14
13
|
module_function
|
15
14
|
|
16
|
-
# Provides a key to load an audience context for the given owner.
|
17
|
-
# An owner should implment GlobalID::Identification.
|
18
|
-
#
|
19
|
-
# @param owner [GlobalID::Identification] an owning model
|
20
|
-
# @return [String] context key
|
21
|
-
#
|
22
|
-
def sign(owner)
|
23
|
-
owner.to_sgid(for: GID_RESOURCE)
|
24
|
-
end
|
25
|
-
|
26
|
-
# Loads a context for the given context key
|
27
|
-
#
|
28
|
-
# @param token [String] a signed token (see #sign)
|
29
|
-
# @return Audience::Context
|
30
|
-
#
|
31
|
-
def load(key)
|
32
|
-
locate_context(key, &:readonly!)
|
33
|
-
end
|
34
|
-
|
35
15
|
# Updates the given context
|
36
16
|
#
|
37
17
|
# Params might contain:
|
@@ -44,18 +24,14 @@ module_function
|
|
44
24
|
# @return Audience::Context
|
45
25
|
#
|
46
26
|
def update(key, criteria: [], **attrs)
|
47
|
-
|
27
|
+
Audiences::Context.load(key) do |context|
|
48
28
|
context.update!(
|
49
29
|
criteria: ::Audiences::Criterion.map(criteria),
|
50
30
|
**attrs
|
51
31
|
)
|
52
32
|
context.refresh_users!
|
53
|
-
context.readonly!
|
54
33
|
end
|
55
34
|
end
|
56
|
-
|
57
|
-
private_class_method def locate_context(key, &block)
|
58
|
-
owner = GlobalID::Locator.locate_signed(key, for: GID_RESOURCE)
|
59
|
-
::Audiences::Context.for(owner).tap(&block)
|
60
|
-
end
|
61
35
|
end
|
36
|
+
|
37
|
+
require "audiences/configuration"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: audiences
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carlos Palhares
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-07-
|
11
|
+
date: 2024-07-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -39,6 +39,7 @@ files:
|
|
39
39
|
- app/jobs/audiences/application_job.rb
|
40
40
|
- app/models/audiences/application_record.rb
|
41
41
|
- app/models/audiences/context.rb
|
42
|
+
- app/models/audiences/context/locating.rb
|
42
43
|
- app/models/audiences/context_users.rb
|
43
44
|
- app/models/audiences/criterion.rb
|
44
45
|
- app/models/audiences/criterion_users.rb
|
@@ -55,13 +56,17 @@ files:
|
|
55
56
|
- db/migrate/20231130165945_create_audiences_external_users.rb
|
56
57
|
- db/migrate/20231130172718_create_audiences_memberships.rb
|
57
58
|
- db/migrate/20231205140046_remove_serialized_users_from_criterion.rb
|
59
|
+
- db/migrate/20240722025634_add_relation_to_context.rb
|
58
60
|
- docs/CHANGELOG.md
|
59
61
|
- docs/README.md
|
60
62
|
- lib/audiences.rb
|
63
|
+
- lib/audiences/configuration.rb
|
61
64
|
- lib/audiences/engine.rb
|
65
|
+
- lib/audiences/model.rb
|
62
66
|
- lib/audiences/notifications.rb
|
63
67
|
- lib/audiences/scim.rb
|
64
68
|
- lib/audiences/scim/client.rb
|
69
|
+
- lib/audiences/scim/resource.rb
|
65
70
|
- lib/audiences/scim/resources_query.rb
|
66
71
|
- lib/audiences/version.rb
|
67
72
|
- lib/tasks/audiences_tasks.rake
|