diff --git a/lib/workos/organizations.rb b/lib/workos/organizations.rb index b463dd15..af3dd472 100644 --- a/lib/workos/organizations.rb +++ b/lib/workos/organizations.rb @@ -185,7 +185,14 @@ def delete_organization(id:) # Retrieve a list of roles for the given organization. # - # @param [String] organizationId The ID of the organization to fetch roles for. + # @param [String] organization_id The ID of the organization to fetch roles for. + # + # @example + # WorkOS::Organizations.list_organization_roles(organization_id: 'org_01EHZNVPK3SFK441A1RGBFSHRT') + # => #] ...> + # + # @return [WorkOS::Types::ListStruct] - Collection of Role objects, each including permissions array def list_organization_roles(organization_id:) response = execute_request( request: get_request( diff --git a/lib/workos/role.rb b/lib/workos/role.rb index 5838cb41..e54db2a9 100644 --- a/lib/workos/role.rb +++ b/lib/workos/role.rb @@ -7,7 +7,7 @@ module WorkOS class Role include HashProvider - attr_accessor :id, :name, :slug, :description, :type, :created_at, :updated_at + attr_accessor :id, :name, :slug, :description, :permissions, :type, :created_at, :updated_at def initialize(json) hash = JSON.parse(json, symbolize_names: true) @@ -16,6 +16,7 @@ def initialize(json) @name = hash[:name] @slug = hash[:slug] @description = hash[:description] + @permissions = hash[:permissions] || [] @type = hash[:type] @created_at = hash[:created_at] @updated_at = hash[:updated_at] @@ -27,6 +28,7 @@ def to_json(*) name: name, slug: slug, description: description, + permissions: permissions, type: type, created_at: created_at, updated_at: updated_at, diff --git a/spec/lib/workos/organizations_spec.rb b/spec/lib/workos/organizations_spec.rb index 8552084f..2188c9f9 100644 --- a/spec/lib/workos/organizations_spec.rb +++ b/spec/lib/workos/organizations_spec.rb @@ -354,6 +354,48 @@ expect(roles.list_metadata).to eq(expected_metadata) end end + + it 'returns properly initialized Role objects with all attributes' do + VCR.use_cassette 'organization/list_organization_roles' do + roles = described_class.list_organization_roles(organization_id: 'org_01JEXP6Z3X7HE4CB6WQSH9ZAFE') + + first_role = roles.data.first + expect(first_role).to be_a(WorkOS::Role) + expect(first_role.id).to eq('role_01HS1C7GRJE08PBR3M6Y0ZYGDZ') + expect(first_role.name).to eq('Admin') + expect(first_role.slug).to eq('admin') + expect(first_role.description).to eq('Write access to every resource available') + expect(first_role.permissions).to eq(['admin:all', 'read:users', 'write:users', 'manage:roles']) + expect(first_role.type).to eq('EnvironmentRole') + expect(first_role.created_at).to eq('2024-03-15T15:38:29.521Z') + expect(first_role.updated_at).to eq('2024-11-14T17:08:00.556Z') + end + end + + it 'handles roles with empty permissions arrays' do + VCR.use_cassette 'organization/list_organization_roles' do + roles = described_class.list_organization_roles(organization_id: 'org_01JEXP6Z3X7HE4CB6WQSH9ZAFE') + + platform_manager_role = roles.data.find { |role| role.slug == 'org-platform-manager' } + expect(platform_manager_role).to be_a(WorkOS::Role) + expect(platform_manager_role.permissions).to eq([]) + end + end + + it 'properly serializes Role objects including permissions' do + VCR.use_cassette 'organization/list_organization_roles' do + roles = described_class.list_organization_roles(organization_id: 'org_01JEXP6Z3X7HE4CB6WQSH9ZAFE') + + billing_role = roles.data.find { |role| role.slug == 'billing' } + serialized = billing_role.to_json + + expect(serialized[:id]).to eq('role_01JA8GJZRDSZEB9289DQXJ3N9Z') + expect(serialized[:name]).to eq('Billing Manager') + expect(serialized[:slug]).to eq('billing') + expect(serialized[:permissions]).to eq(['read:billing', 'write:billing']) + expect(serialized[:type]).to eq('EnvironmentRole') + end + end end end end diff --git a/spec/lib/workos/role_spec.rb b/spec/lib/workos/role_spec.rb new file mode 100644 index 00000000..8d4d8f75 --- /dev/null +++ b/spec/lib/workos/role_spec.rb @@ -0,0 +1,142 @@ +# frozen_string_literal: true + +describe WorkOS::Role do + describe '.initialize' do + context 'with full role data including permissions' do + it 'initializes all attributes correctly' do + role_json = { + id: 'role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY', + name: 'Admin', + slug: 'admin', + description: 'Administrator role with full access', + permissions: ['read:users', 'write:users', 'admin:all'], + type: 'system', + created_at: '2022-05-13T17:45:31.732Z', + updated_at: '2022-07-13T17:45:42.618Z', + }.to_json + + role = described_class.new(role_json) + + expect(role.id).to eq('role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY') + expect(role.name).to eq('Admin') + expect(role.slug).to eq('admin') + expect(role.description).to eq('Administrator role with full access') + expect(role.permissions).to eq(['read:users', 'write:users', 'admin:all']) + expect(role.type).to eq('system') + expect(role.created_at).to eq('2022-05-13T17:45:31.732Z') + expect(role.updated_at).to eq('2022-07-13T17:45:42.618Z') + end + end + + context 'with role data without permissions' do + it 'initializes permissions as empty array' do + role_json = { + id: 'role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY', + name: 'User', + slug: 'user', + description: 'Basic user role', + type: 'custom', + created_at: '2022-05-13T17:45:31.732Z', + updated_at: '2022-07-13T17:45:42.618Z', + }.to_json + + role = described_class.new(role_json) + + expect(role.id).to eq('role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY') + expect(role.name).to eq('User') + expect(role.slug).to eq('user') + expect(role.description).to eq('Basic user role') + expect(role.permissions).to eq([]) + expect(role.type).to eq('custom') + expect(role.created_at).to eq('2022-05-13T17:45:31.732Z') + expect(role.updated_at).to eq('2022-07-13T17:45:42.618Z') + end + end + + context 'with role data with null permissions' do + it 'initializes permissions as empty array' do + role_json = { + id: 'role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY', + name: 'User', + slug: 'user', + description: 'Basic user role', + permissions: nil, + type: 'custom', + created_at: '2022-05-13T17:45:31.732Z', + updated_at: '2022-07-13T17:45:42.618Z', + }.to_json + + role = described_class.new(role_json) + + expect(role.permissions).to eq([]) + end + end + + context 'with role data with empty permissions array' do + it 'preserves empty permissions array' do + role_json = { + id: 'role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY', + name: 'User', + slug: 'user', + description: 'Basic user role', + permissions: [], + type: 'custom', + created_at: '2022-05-13T17:45:31.732Z', + updated_at: '2022-07-13T17:45:42.618Z', + }.to_json + + role = described_class.new(role_json) + + expect(role.permissions).to eq([]) + end + end + end + + describe '.to_json' do + context 'with role that has permissions' do + it 'includes permissions in serialized output' do + role_json = { + id: 'role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY', + name: 'Admin', + slug: 'admin', + description: 'Administrator role', + permissions: ['read:all', 'write:all'], + type: 'system', + created_at: '2022-05-13T17:45:31.732Z', + updated_at: '2022-07-13T17:45:42.618Z', + }.to_json + + role = described_class.new(role_json) + serialized = role.to_json + + expect(serialized[:id]).to eq('role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY') + expect(serialized[:name]).to eq('Admin') + expect(serialized[:slug]).to eq('admin') + expect(serialized[:description]).to eq('Administrator role') + expect(serialized[:permissions]).to eq(['read:all', 'write:all']) + expect(serialized[:type]).to eq('system') + expect(serialized[:created_at]).to eq('2022-05-13T17:45:31.732Z') + expect(serialized[:updated_at]).to eq('2022-07-13T17:45:42.618Z') + end + end + + context 'with role that has no permissions' do + it 'includes empty permissions array in serialized output' do + role_json = { + id: 'role_01FAEAJCJ3P1Z6WP5Y9VQPN2XY', + name: 'User', + slug: 'user', + description: 'Basic user role', + type: 'custom', + created_at: '2022-05-13T17:45:31.732Z', + updated_at: '2022-07-13T17:45:42.618Z', + }.to_json + + role = described_class.new(role_json) + serialized = role.to_json + + expect(serialized[:permissions]).to eq([]) + end + end + end +end diff --git a/spec/support/fixtures/vcr_cassettes/organization/list_organization_roles.yml b/spec/support/fixtures/vcr_cassettes/organization/list_organization_roles.yml index c07d5690..be7064da 100644 --- a/spec/support/fixtures/vcr_cassettes/organization/list_organization_roles.yml +++ b/spec/support/fixtures/vcr_cassettes/organization/list_organization_roles.yml @@ -70,13 +70,13 @@ http_interactions: encoding: ASCII-8BIT string: '{"object":"list","data":[{"object":"role","id":"role_01HS1C7GRJE08PBR3M6Y0ZYGDZ","description":"Write - access to every resource available","name":"Admin","slug":"admin","type":"EnvironmentRole","created_at":"2024-03-15T15:38:29.521Z","updated_at":"2024-11-14T17:08:00.556Z"},{"object":"role","id":"role_01JA8GJZRDSZEB9289DQXJ3N9Z","description":"","name":"Billing - Manager","slug":"billing","type":"EnvironmentRole","created_at":"2024-10-15T16:36:11.653Z","updated_at":"2024-12-19T21:27:01.286Z"},{"object":"role","id":"role_01HSBH4R6RX0V86S3R590NNZW2","description":"Developer - role","name":"Developer","slug":"developer","type":"EnvironmentRole","created_at":"2024-03-19T14:16:46.038Z","updated_at":"2024-03-19T14:16:46.038Z"},{"object":"role","id":"role_01HS4GDWJ8T6NQPTX2D0R5KBHN","description":"Edit - and view access to non-critical resources","name":"Editor","slug":"editor","type":"EnvironmentRole","created_at":"2024-03-16T20:49:35.815Z","updated_at":"2024-03-16T20:52:19.410Z"},{"object":"role","id":"role_01HRFZE22WS2MGX6EWAG2JX6NW","description":"The - default user role","name":"Member","slug":"member","type":"EnvironmentRole","created_at":"2024-03-08T21:27:47.034Z","updated_at":"2024-08-14T00:27:46.265Z"},{"object":"role","id":"role_01JEYJ2Z5MYG0TZYTDF02MW11N","description":"Manage - billing for organization.","name":"Billing manager","slug":"org-billing-manager","type":"OrganizationRole","created_at":"2024-12-12T23:08:28.712Z","updated_at":"2024-12-12T23:08:28.712Z"},{"object":"role","id":"role_01JF0B7MQ9X414WQRAQMQYE1GS","description":"","name":"Platform - Manager","slug":"org-platform-manager","type":"OrganizationRole","created_at":"2024-12-13T15:47:10.692Z","updated_at":"2024-12-13T15:47:10.692Z"}]}' + access to every resource available","name":"Admin","slug":"admin","permissions":["admin:all","read:users","write:users","manage:roles"],"type":"EnvironmentRole","created_at":"2024-03-15T15:38:29.521Z","updated_at":"2024-11-14T17:08:00.556Z"},{"object":"role","id":"role_01JA8GJZRDSZEB9289DQXJ3N9Z","description":"","name":"Billing + Manager","slug":"billing","permissions":["read:billing","write:billing"],"type":"EnvironmentRole","created_at":"2024-10-15T16:36:11.653Z","updated_at":"2024-12-19T21:27:01.286Z"},{"object":"role","id":"role_01HSBH4R6RX0V86S3R590NNZW2","description":"Developer + role","name":"Developer","slug":"developer","permissions":["read:code","write:code","deploy:apps"],"type":"EnvironmentRole","created_at":"2024-03-19T14:16:46.038Z","updated_at":"2024-03-19T14:16:46.038Z"},{"object":"role","id":"role_01HS4GDWJ8T6NQPTX2D0R5KBHN","description":"Edit + and view access to non-critical resources","name":"Editor","slug":"editor","permissions":["read:content","write:content","publish:content"],"type":"EnvironmentRole","created_at":"2024-03-16T20:49:35.815Z","updated_at":"2024-03-16T20:52:19.410Z"},{"object":"role","id":"role_01HRFZE22WS2MGX6EWAG2JX6NW","description":"The + default user role","name":"Member","slug":"member","permissions":["read:basic"],"type":"EnvironmentRole","created_at":"2024-03-08T21:27:47.034Z","updated_at":"2024-08-14T00:27:46.265Z"},{"object":"role","id":"role_01JEYJ2Z5MYG0TZYTDF02MW11N","description":"Manage + billing for organization.","name":"Billing manager","slug":"org-billing-manager","permissions":["read:org:billing","write:org:billing"],"type":"OrganizationRole","created_at":"2024-12-12T23:08:28.712Z","updated_at":"2024-12-12T23:08:28.712Z"},{"object":"role","id":"role_01JF0B7MQ9X414WQRAQMQYE1GS","description":"","name":"Platform + Manager","slug":"org-platform-manager","permissions":[],"type":"OrganizationRole","created_at":"2024-12-13T15:47:10.692Z","updated_at":"2024-12-13T15:47:10.692Z"}]}' http_version: recorded_at: Mon, 23 Dec 2024 20:23:07 GMT recorded_with: VCR 5.0.0