atomic_admin 2.2.1 → 2.3.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/app/controllers/atomic_admin/api/admin/v1/role_capabilities_controller.rb +3 -0
- data/app/controllers/atomic_admin/v1/role_capabilities_controller.rb +188 -0
- data/config/routes.rb +8 -0
- data/lib/atomic_admin/interaction/capabilities.rb +15 -0
- data/lib/atomic_admin/interaction/manager.rb +1 -0
- data/lib/atomic_admin/interaction.rb +1 -0
- data/lib/atomic_admin/role_capabilities/provider.rb +154 -0
- data/lib/atomic_admin/version.rb +1 -1
- data/lib/atomic_admin.rb +1 -0
- metadata +7 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 06d8fa97576a29d8803456608d9081661ea90977713458d6386c9c55a8bb0356
|
|
4
|
+
data.tar.gz: e87935716e8a596854cb453f328fa30f9a0444b74954112993ee066269d3adfb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: de38f6db4e56f1ed6c0c24d58ac995ab00538843573476c4866af0bd4b281bae251109eb102a4f46438fd165b9f8858a52cf62f270e192f1f508f70133391ca6
|
|
7
|
+
data.tar.gz: 2f1485e9a3c9ac1d61a10eb01bb04fab78d68a7ef8e1d40149796b36db0f071f3ff28b6bf9444974c1819349a6e6f77f3b95a6cea0d496558fb3568ba37f671a
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
module AtomicAdmin::V1
|
|
2
|
+
# The API behind Skipper's `capabilities` interaction: a matrix of
|
|
3
|
+
# capabilities by roles, where each cell is what the role grants by default
|
|
4
|
+
# or an override row (ALLOW, DENY or PROHIBIT) at one scope. A scope is
|
|
5
|
+
# everywhere ("global"), one account ("account:<account id>") or one course
|
|
6
|
+
# ("course:<context id>").
|
|
7
|
+
#
|
|
8
|
+
# Rows are read and written through the host app's RoleCapability model
|
|
9
|
+
# (role, capability, mode, context_id, account_id) and Role model (name). The
|
|
10
|
+
# catalog, role defaults and account and course names come from the
|
|
11
|
+
# interaction's provider, an AtomicAdmin::RoleCapabilities::Provider
|
|
12
|
+
# subclass. See docs/interactions.md.
|
|
13
|
+
class RoleCapabilitiesController < AdminController
|
|
14
|
+
GLOBAL_SCOPE = "global".freeze
|
|
15
|
+
MODES = %w[ALLOW DENY PROHIBIT].freeze
|
|
16
|
+
|
|
17
|
+
around_action :switch_tenants
|
|
18
|
+
|
|
19
|
+
# The catalog, every role with what it grants by default, every override
|
|
20
|
+
# row for the catalog's capabilities, and the accounts and courses those
|
|
21
|
+
# rows are scoped to.
|
|
22
|
+
def show
|
|
23
|
+
rows = catalog_rows(RoleCapability.includes(:role).to_a)
|
|
24
|
+
|
|
25
|
+
render json: {
|
|
26
|
+
groups: provider.capability_groups,
|
|
27
|
+
capabilities: provider.capability_catalog,
|
|
28
|
+
modes: MODES,
|
|
29
|
+
tiers: provider.role_tiers,
|
|
30
|
+
roles: provider.listed_roles.map { |role| role_json(role) },
|
|
31
|
+
custom_roles: provider.custom_roles,
|
|
32
|
+
rows: rows.map { |row| row_json(row) },
|
|
33
|
+
scopes: scopes_json_for(rows),
|
|
34
|
+
notes: provider.notes,
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Replaces one role's override rows at one scope. A missing overrides key
|
|
39
|
+
# clears them.
|
|
40
|
+
#
|
|
41
|
+
# PATCH { role: { name: "canvas:Grade Viewer" }, scope: "account:12",
|
|
42
|
+
# overrides: { "reply_create" => "PROHIBIT", ... } }
|
|
43
|
+
def update
|
|
44
|
+
name = role_name_param
|
|
45
|
+
return render_unprocessable("role.name is required") if name.blank?
|
|
46
|
+
|
|
47
|
+
scope_key = params[:scope].presence || GLOBAL_SCOPE
|
|
48
|
+
context_id, account_id = parse_scope(scope_key)
|
|
49
|
+
if context_id.nil? && account_id.nil? && scope_key != GLOBAL_SCOPE
|
|
50
|
+
return render_unprocessable("scope must be global, account:<account id> or course:<context id>")
|
|
51
|
+
end
|
|
52
|
+
if context_id && provider.course_scopes([context_id]).empty?
|
|
53
|
+
return render_unprocessable("No course with context id #{context_id} has launched this tool")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
overrides = params.key?(:overrides) ? overrides_param : {}
|
|
57
|
+
return render_unprocessable("overrides must map capability names to modes") if overrides.nil?
|
|
58
|
+
|
|
59
|
+
overrides = overrides.compact_blank
|
|
60
|
+
unknown = overrides.keys - provider.capability_names
|
|
61
|
+
return render_unprocessable("Unknown capabilities: #{unknown.join(', ')}") if unknown.any?
|
|
62
|
+
|
|
63
|
+
invalid_modes = overrides.values.uniq - MODES
|
|
64
|
+
return render_unprocessable("Unknown modes: #{invalid_modes.join(', ')}") if invalid_modes.any?
|
|
65
|
+
|
|
66
|
+
role = provider.role_for_update(name)
|
|
67
|
+
return render_unprocessable("Unknown role: #{name}") if role.nil?
|
|
68
|
+
|
|
69
|
+
provider.replace_overrides!(role, overrides, context_id:, account_id:)
|
|
70
|
+
saved = catalog_rows(RoleCapability.where(role:, context_id:, account_id:).includes(:role).to_a)
|
|
71
|
+
|
|
72
|
+
render json: {
|
|
73
|
+
role: role_json(role),
|
|
74
|
+
scope: scope_key,
|
|
75
|
+
overrides: saved.to_h { |row| [row.capability, row.mode] },
|
|
76
|
+
}
|
|
77
|
+
rescue ActiveRecord::RecordInvalid => e
|
|
78
|
+
render_unprocessable(e.record.errors.full_messages.join(", "))
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Accounts and courses matching a search, for the scope picker.
|
|
82
|
+
#
|
|
83
|
+
# GET ?q=law
|
|
84
|
+
def scopes
|
|
85
|
+
render json: { scopes: provider.search_scopes(params[:q].to_s.strip) }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def application_instance
|
|
91
|
+
@application_instance ||= ApplicationInstance.find(params[:application_instance_id])
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def provider
|
|
95
|
+
@provider ||= interaction.provider_class.new(application_instance:)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# The routes are only drawn when a capabilities interaction is registered.
|
|
99
|
+
def interaction
|
|
100
|
+
AtomicAdmin.application_instance_interactions.for_type(:capabilities).first
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def switch_tenants(&)
|
|
104
|
+
Apartment::Tenant.switch(application_instance.tenant, &)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def render_unprocessable(message)
|
|
108
|
+
render json: { error: message }, status: 422
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Only rows for the catalog's capabilities. Other rows stay stored but are
|
|
112
|
+
# not this editor's to show or save back.
|
|
113
|
+
def catalog_rows(rows)
|
|
114
|
+
rows.select { |row| provider.capability_names.include?(row.capability.to_s) }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def role_json(role)
|
|
118
|
+
tier = provider.role_tier(role)&.to_s
|
|
119
|
+
{
|
|
120
|
+
id: role.id,
|
|
121
|
+
name: role.name,
|
|
122
|
+
display_name: provider.role_display_name(role),
|
|
123
|
+
kind: provider.role_kind(role),
|
|
124
|
+
custom: provider.custom_role?(role),
|
|
125
|
+
tier:,
|
|
126
|
+
tier_label: provider.role_tiers.find { |t| t[:key].to_s == tier }&.dig(:label),
|
|
127
|
+
defaults: (provider.role_defaults(role).map(&:to_s) & provider.capability_names).sort,
|
|
128
|
+
}
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def row_json(row)
|
|
132
|
+
{ role: row.role.name, scope: scope_key_for(row), capability: row.capability.to_s, mode: row.mode }
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def scope_key_for(row)
|
|
136
|
+
if row.context_id
|
|
137
|
+
"course:#{row.context_id}"
|
|
138
|
+
elsif row.account_id
|
|
139
|
+
"account:#{row.account_id}"
|
|
140
|
+
else
|
|
141
|
+
GLOBAL_SCOPE
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# [context_id, account_id] for a scope key; [nil, nil] for global and for
|
|
146
|
+
# anything malformed (the caller tells the two apart). Context ids are
|
|
147
|
+
# opaque, so only the first ":" separates the type.
|
|
148
|
+
def parse_scope(key)
|
|
149
|
+
type, id = key.to_s.split(":", 2)
|
|
150
|
+
return [nil, nil] if id.blank?
|
|
151
|
+
|
|
152
|
+
case type
|
|
153
|
+
when "course" then [id, nil]
|
|
154
|
+
when "account" then provider.valid_account_id?(id) ? [nil, id] : [nil, nil]
|
|
155
|
+
else [nil, nil]
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Names for the scopes the rows use. A course that is gone keeps its rows
|
|
160
|
+
# listed under an unnamed scope.
|
|
161
|
+
def scopes_json_for(rows)
|
|
162
|
+
account_ids = rows.filter_map(&:account_id).uniq
|
|
163
|
+
context_ids = rows.filter_map(&:context_id).uniq
|
|
164
|
+
courses = provider.course_scopes(context_ids).index_by { |scope| scope[:id] }
|
|
165
|
+
|
|
166
|
+
provider.account_scopes(account_ids) +
|
|
167
|
+
context_ids.map { |id| courses[id] || provider.course_scope_json(id) }
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# `role` must be an object with a name; anything else is treated as missing.
|
|
171
|
+
def role_name_param
|
|
172
|
+
role = params[:role]
|
|
173
|
+
role.respond_to?(:key?) ? role[:name].to_s.strip : ""
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# { capability => mode } with string or nil values, or nil when the shape
|
|
177
|
+
# is wrong.
|
|
178
|
+
def overrides_param
|
|
179
|
+
overrides = params[:overrides]
|
|
180
|
+
return nil unless overrides.respond_to?(:to_unsafe_h)
|
|
181
|
+
|
|
182
|
+
overrides = overrides.to_unsafe_h
|
|
183
|
+
return nil unless overrides.values.all? { |mode| mode.nil? || mode.is_a?(String) }
|
|
184
|
+
|
|
185
|
+
overrides
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
data/config/routes.rb
CHANGED
|
@@ -42,6 +42,14 @@ AtomicAdmin::Engine.routes.draw do
|
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
+
# Backs the `capabilities` interaction; the host supplies its
|
|
46
|
+
# provider. See AtomicAdmin::V1::RoleCapabilitiesController.
|
|
47
|
+
if AtomicAdmin.application_instance_interactions.for_type(:capabilities).any?
|
|
48
|
+
resource :role_capabilities, only: [:show, :update] do
|
|
49
|
+
get :scopes
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
45
53
|
AtomicAdmin.application_instance_interactions.for_type(:resource).each do |interaction|
|
|
46
54
|
controller_name = interaction.key.to_s.pluralize
|
|
47
55
|
resources controller_name do
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module AtomicAdmin::Interaction
|
|
2
|
+
# Skipper's Role Capabilities editor. `provider` is an
|
|
3
|
+
# AtomicAdmin::RoleCapabilities::Provider subclass, or its name; it is
|
|
4
|
+
# looked up on each request so it reloads in development.
|
|
5
|
+
class Capabilities < AtomicAdmin::Interaction::Base
|
|
6
|
+
def initialize(provider:, **kwargs)
|
|
7
|
+
super(**kwargs)
|
|
8
|
+
@provider = provider
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def provider_class
|
|
12
|
+
@provider.is_a?(String) ? @provider.constantize : @provider
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -4,6 +4,7 @@ require_relative 'interaction/analytics'
|
|
|
4
4
|
require_relative 'interaction/resource'
|
|
5
5
|
require_relative 'interaction/launch'
|
|
6
6
|
require_relative 'interaction/readonly'
|
|
7
|
+
require_relative 'interaction/capabilities'
|
|
7
8
|
require_relative 'interaction/manager'
|
|
8
9
|
|
|
9
10
|
module AtomicAdmin::Interaction
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
module AtomicAdmin
|
|
2
|
+
module RoleCapabilities
|
|
3
|
+
# What a host app supplies for the `capabilities` interaction: the
|
|
4
|
+
# capability catalog, what each role grants by default, and how accounts
|
|
5
|
+
# and courses are named and found. Subclass it, implement
|
|
6
|
+
# `capability_catalog` and `role_defaults`, override any other hook, and
|
|
7
|
+
# name the class in the interaction's `provider:` option.
|
|
8
|
+
#
|
|
9
|
+
# AtomicAdmin::V1::RoleCapabilitiesController builds one per request with
|
|
10
|
+
# the application instance, inside that instance's tenant, and reads and
|
|
11
|
+
# writes the host's RoleCapability rows (role, capability, mode,
|
|
12
|
+
# context_id, account_id) itself.
|
|
13
|
+
class Provider
|
|
14
|
+
attr_reader :application_instance
|
|
15
|
+
|
|
16
|
+
def initialize(application_instance:)
|
|
17
|
+
@application_instance = application_instance
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Required. The capabilities this application instance can grant, in
|
|
21
|
+
# display order: [{ name:, group:, label:, description: }].
|
|
22
|
+
def capability_catalog
|
|
23
|
+
raise NotImplementedError, "#{self.class.name} must implement capability_catalog"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Required. The capability names one role grants when it has no override
|
|
27
|
+
# rows.
|
|
28
|
+
def role_defaults(_role)
|
|
29
|
+
raise NotImplementedError, "#{self.class.name} must implement role_defaults"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# The catalog's groups in order: [{ key:, label: }].
|
|
33
|
+
def capability_groups
|
|
34
|
+
capability_catalog.map { |capability| capability[:group].to_s }.uniq.map do |group|
|
|
35
|
+
{ key: group, label: group.humanize }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# The default sets roles fall into, highest first: [{ key:, label: }].
|
|
40
|
+
# Columns are ordered by tier.
|
|
41
|
+
def role_tiers
|
|
42
|
+
[]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# The key of the role's tier, or nil for a role that grants nothing by
|
|
46
|
+
# default.
|
|
47
|
+
def role_tier(_role)
|
|
48
|
+
nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Every role that gets a column.
|
|
52
|
+
def listed_roles
|
|
53
|
+
Role.order(:name).to_a
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# The column title for a role whose name is not a standard LTI role URI
|
|
57
|
+
# (Skipper shortens those itself).
|
|
58
|
+
def role_display_name(role)
|
|
59
|
+
role.name
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# What kind of role it is ("Canvas custom role"), or nil to let Skipper
|
|
63
|
+
# work it out from an LTI role URI.
|
|
64
|
+
def role_kind(_role)
|
|
65
|
+
nil
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Whether the role is an LMS custom role added by name.
|
|
69
|
+
def custom_role?(_role)
|
|
70
|
+
false
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# nil, or how roles that have not launched yet can be added by name:
|
|
74
|
+
# { label: "Canvas custom role", prefix: "canvas:", example: "Grade Viewer" }.
|
|
75
|
+
# Skipper stores a typed name as prefix + name.
|
|
76
|
+
def custom_roles
|
|
77
|
+
nil
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# The role an update names, or nil to refuse it.
|
|
81
|
+
def role_for_update(name)
|
|
82
|
+
Role.find_by(name:)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Whether an id from an "account:<id>" scope key can be an account id.
|
|
86
|
+
def valid_account_id?(account_id)
|
|
87
|
+
account_id.present?
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Scope entries for these account ids, in the same order. Build them
|
|
91
|
+
# with account_scope_json.
|
|
92
|
+
def account_scopes(account_ids)
|
|
93
|
+
account_ids.map { |id| account_scope_json(id) }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Scope entries for the courses among these context ids that have
|
|
97
|
+
# launched the tool; leave the rest out. Build them with
|
|
98
|
+
# course_scope_json. Course scopes cannot be saved until this is
|
|
99
|
+
# implemented.
|
|
100
|
+
def course_scopes(_context_ids)
|
|
101
|
+
[]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Accounts and courses matching a search term.
|
|
105
|
+
def search_scopes(_term)
|
|
106
|
+
[]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Short notes shown under the matrix, such as how defaults combine.
|
|
110
|
+
def notes
|
|
111
|
+
[]
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Replaces the role's rows for the catalog's capabilities at one scope.
|
|
115
|
+
# Rows for capabilities outside the catalog are left alone.
|
|
116
|
+
def replace_overrides!(role, overrides, context_id:, account_id:)
|
|
117
|
+
RoleCapability.transaction do
|
|
118
|
+
RoleCapability.where(role:, capability: capability_names, context_id:, account_id:).delete_all
|
|
119
|
+
overrides.each do |capability, mode|
|
|
120
|
+
RoleCapability.create!(role:, capability:, mode:, context_id:, account_id:)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def capability_names
|
|
126
|
+
@capability_names ||= capability_catalog.map { |capability| capability[:name].to_s }
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# `path` names the account's ancestors and the account itself, root
|
|
130
|
+
# first.
|
|
131
|
+
def account_scope_json(account_id, label: nil, path: [])
|
|
132
|
+
{
|
|
133
|
+
key: "account:#{account_id}",
|
|
134
|
+
type: "account",
|
|
135
|
+
id: account_id.to_s,
|
|
136
|
+
label: label.presence || "Account #{account_id}",
|
|
137
|
+
path:,
|
|
138
|
+
}
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# `account` is the course's account scope, from account_scope_json, if
|
|
142
|
+
# known.
|
|
143
|
+
def course_scope_json(context_id, label: nil, account: nil)
|
|
144
|
+
{
|
|
145
|
+
key: "course:#{context_id}",
|
|
146
|
+
type: "course",
|
|
147
|
+
id: context_id.to_s,
|
|
148
|
+
label: label.presence || "Course #{context_id}",
|
|
149
|
+
account:,
|
|
150
|
+
}
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
data/lib/atomic_admin/version.rb
CHANGED
data/lib/atomic_admin.rb
CHANGED
metadata
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: atomic_admin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nick Benoit
|
|
8
8
|
- Sean Collings
|
|
9
|
-
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date:
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
13
12
|
dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
|
15
14
|
name: rails
|
|
@@ -113,6 +112,7 @@ files:
|
|
|
113
112
|
- app/controllers/atomic_admin/api/admin/v1/applications_controller.rb
|
|
114
113
|
- app/controllers/atomic_admin/api/admin/v1/lti_installs_controller.rb
|
|
115
114
|
- app/controllers/atomic_admin/api/admin/v1/lti_platforms_controller.rb
|
|
115
|
+
- app/controllers/atomic_admin/api/admin/v1/role_capabilities_controller.rb
|
|
116
116
|
- app/controllers/atomic_admin/api/admin/v1/sites_controller.rb
|
|
117
117
|
- app/controllers/atomic_admin/api/admin/v1/tenant_client_id_strategies_controller.rb
|
|
118
118
|
- app/controllers/atomic_admin/api/admin/v1/tenant_deployments_controller.rb
|
|
@@ -123,6 +123,7 @@ files:
|
|
|
123
123
|
- app/controllers/atomic_admin/v1/applications_controller.rb
|
|
124
124
|
- app/controllers/atomic_admin/v1/lti_installs_controller.rb
|
|
125
125
|
- app/controllers/atomic_admin/v1/lti_platforms_controller.rb
|
|
126
|
+
- app/controllers/atomic_admin/v1/role_capabilities_controller.rb
|
|
126
127
|
- app/controllers/atomic_admin/v1/sites_controller.rb
|
|
127
128
|
- app/controllers/atomic_admin/v1/tenant_client_id_strategies_controller.rb
|
|
128
129
|
- app/controllers/atomic_admin/v1/tenant_deployments_controller.rb
|
|
@@ -139,6 +140,7 @@ files:
|
|
|
139
140
|
- lib/atomic_admin/interaction.rb
|
|
140
141
|
- lib/atomic_admin/interaction/analytics.rb
|
|
141
142
|
- lib/atomic_admin/interaction/base.rb
|
|
143
|
+
- lib/atomic_admin/interaction/capabilities.rb
|
|
142
144
|
- lib/atomic_admin/interaction/json_form.rb
|
|
143
145
|
- lib/atomic_admin/interaction/launch.rb
|
|
144
146
|
- lib/atomic_admin/interaction/manager.rb
|
|
@@ -147,6 +149,7 @@ files:
|
|
|
147
149
|
- lib/atomic_admin/jwt_token.rb
|
|
148
150
|
- lib/atomic_admin/jwt_token/jwks_decoder.rb
|
|
149
151
|
- lib/atomic_admin/jwt_token/secret_decoder.rb
|
|
152
|
+
- lib/atomic_admin/role_capabilities/provider.rb
|
|
150
153
|
- lib/atomic_admin/schema.rb
|
|
151
154
|
- lib/atomic_admin/schema/application_instance_configuration_schema.rb
|
|
152
155
|
- lib/atomic_admin/schema/application_instance_create_schema.rb
|
|
@@ -165,7 +168,6 @@ metadata:
|
|
|
165
168
|
homepage_uri: https://github.com/atomicjolt/atomic_admin/
|
|
166
169
|
source_code_uri: https://github.com/atomicjolt/atomic_admin/
|
|
167
170
|
changelog_uri: https://github.com/atomicjolt/atomic_admin/
|
|
168
|
-
post_install_message:
|
|
169
171
|
rdoc_options: []
|
|
170
172
|
require_paths:
|
|
171
173
|
- lib
|
|
@@ -180,8 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
180
182
|
- !ruby/object:Gem::Version
|
|
181
183
|
version: '0'
|
|
182
184
|
requirements: []
|
|
183
|
-
rubygems_version: 3.
|
|
184
|
-
signing_key:
|
|
185
|
+
rubygems_version: 3.6.7
|
|
185
186
|
specification_version: 4
|
|
186
187
|
summary: Engine to provide apis that power the Atomic Jolt admin app
|
|
187
188
|
test_files: []
|