Skip to content

Commit 02ef0d7

Browse files
xjuniorgregblake
andauthored
Update ExternalUser on membership changeas (#541)
- **Propage a ReplaceEvent for users when a membership change happens** - **Change ExternalUser SCIM to represent current groups from relationships** --------- Co-authored-by: Greg Blake <[email protected]>
1 parent 1fef749 commit 02ef0d7

File tree

4 files changed

+132
-1
lines changed

4 files changed

+132
-1
lines changed

audiences/app/models/audiences/external_user.rb

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,52 @@ def picture_urls=(urls)
6464
end
6565

6666
def as_json(...)
67-
data&.slice(*Audiences.exposed_user_attributes)
67+
as_scim.slice(*Audiences.exposed_user_attributes)
6868
end
69+
70+
def as_scim(...)
71+
(data || {}).merge(groups_as_scim)
72+
end
73+
74+
def groups_as_scim
75+
names = groups.reduce({}) { |nam, group| nam.merge(group.resource_type => group.display_name) }
76+
77+
{
78+
"groups" => groups.map { |g| { "value" => g.scim_id, "display" => g.display_name } },
79+
"title" => names["Titles"],
80+
"urn:ietf:params:scim:schemas:extension:authservice:2.0:User" => {
81+
"role" => names["Roles"], "department" => names["Departments"],
82+
"territory" => names["Territories"], "territoryAbbr" => TERRITORY_ABBRS[names["Territories"]]
83+
},
84+
}
85+
end
86+
87+
TERRITORY_ABBRS = {
88+
"Philadelphia" => "PHL",
89+
"New Jersey" => "NJ",
90+
"Maryland" => "MD",
91+
"Connecticut" => "CT",
92+
"Long Island" => "LI",
93+
"Boston" => "BOS",
94+
"Atlanta" => "ATL",
95+
"Chicago" => "CHI",
96+
"Detroit" => "DET",
97+
"Houston" => "HOU",
98+
"Dallas" => "DAL",
99+
"Denver" => "DEN",
100+
"Tampa" => "TPA",
101+
"Austin" => "AUS",
102+
"Charlotte" => "CLT",
103+
"Nashville" => "NSH",
104+
"Phoenix" => "PHX",
105+
"Pittsburgh" => "PIT",
106+
"San Antonio" => "SAO",
107+
"Fort Lauderdale" => "FLL",
108+
"Las Vegas" => "LVS",
109+
"Orlando" => "ORL",
110+
"Cincinnati" => "CIN",
111+
"Columbus" => "CLB",
112+
"Jacksonville" => "JAX",
113+
}.freeze
69114
end
70115
end

audiences/lib/audiences/scim/patch_groups_observer.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ def process
1313
patch_op.process(group, attributes_mapping)
1414

1515
group.save!
16+
17+
propagate_changes_to_users!
1618
rescue => e
1719
Audiences.logger.error e
1820
raise
@@ -34,6 +36,16 @@ def group
3436
@group ||= Group.find_by!(resource_type: event_payload.resource,
3537
scim_id: event_payload.id)
3638
end
39+
40+
def propagate_changes_to_users!
41+
patch_op.operations.each do |operation|
42+
next unless operation.path == "members"
43+
44+
ExternalUser.where(user_id: operation.value.pluck("value")).find_each do |user|
45+
TwoPercent::ReplaceEvent.create(resource: "Users", id: user.scim_id, params: user.as_scim)
46+
end
47+
end
48+
end
3749
end
3850
end
3951
end

audiences/spec/models/audiences/external_user_spec.rb

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,51 @@
158158
expect(users).to match_array [user1]
159159
end
160160
end
161+
162+
describe "#as_json" do
163+
it "returns only exposed attributes" do
164+
user = create_user(
165+
scim_id: "scim-id",
166+
user_id: "user-id",
167+
display_name: "Display Name",
168+
active: true,
169+
data: { "displayName" => "value", "hiddenAttribute" => "Does Not Matter" }
170+
)
171+
172+
expect(user.as_json).to eq("displayName" => "value")
173+
end
174+
end
175+
176+
describe "#as_scim" do
177+
it "includes the updated groups from the relational data" do
178+
user = create_user(
179+
scim_id: "scim-id",
180+
user_id: "user-id",
181+
display_name: "Display Name",
182+
active: true,
183+
data: { "displayName" => "Display Name", "groups" => [] }
184+
)
185+
title = create_group(resource_type: "Titles", display_name: "Engineer", external_users: [user])
186+
role = create_group(resource_type: "Roles", display_name: "Admin", external_users: [user])
187+
department = create_group(resource_type: "Departments", display_name: "Engineering", external_users: [user])
188+
territory = create_group(resource_type: "Territories", display_name: "Long Island", external_users: [user])
189+
190+
expect(user.as_scim).to eq(
191+
"displayName" => "Display Name",
192+
"groups" => [
193+
{ "value" => title.scim_id, "display" => "Engineer" },
194+
{ "value" => role.scim_id, "display" => "Admin" },
195+
{ "value" => department.scim_id, "display" => "Engineering" },
196+
{ "value" => territory.scim_id, "display" => "Long Island" },
197+
],
198+
"title" => "Engineer",
199+
"urn:ietf:params:scim:schemas:extension:authservice:2.0:User" => {
200+
"role" => "Admin",
201+
"department" => "Engineering",
202+
"territory" => "Long Island",
203+
"territoryAbbr" => "LI",
204+
}
205+
)
206+
end
207+
end
161208
end

audiences/spec/observers/audiences/scim/patch_groups_observer_spec.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,31 @@
160160

161161
expect(new_member.reload.groups).to match_array []
162162
end
163+
164+
it "publishes a replace event for the users involved" do
165+
member = Audiences::ExternalUser.create(scim_id: "123", user_id: 1)
166+
new_member1 = Audiences::ExternalUser.create(scim_id: "321", user_id: 2)
167+
new_member2 = Audiences::ExternalUser.create(scim_id: "333", user_id: 3)
168+
group = create_group(external_users: [member])
169+
170+
allow(TwoPercent::ReplaceEvent).to receive(:create)
171+
172+
TwoPercent::UpdateEvent.create(resource: "Groups",
173+
id: group.scim_id,
174+
params: {
175+
"Operations" => [
176+
{
177+
"op" => "add",
178+
"path" => "members",
179+
"value" => [{ "value" => new_member1.user_id },
180+
{ "value" => new_member2.user_id }],
181+
},
182+
],
183+
})
184+
185+
expect(TwoPercent::ReplaceEvent).to have_received(:create).with(resource: "Users", id: new_member1.scim_id,
186+
params: anything)
187+
expect(TwoPercent::ReplaceEvent).to have_received(:create).with(resource: "Users", id: new_member2.scim_id,
188+
params: anything)
189+
end
163190
end

0 commit comments

Comments
 (0)