Skip to content

Commit

Permalink
Add WorkOS::Portal.create_organization
Browse files Browse the repository at this point in the history
* Adds the ability to create an organization via the SDK for use
  with the Admin Portal.
  • Loading branch information
willmanduffy committed Sep 11, 2020
1 parent 0d05476 commit 71523db
Show file tree
Hide file tree
Showing 8 changed files with 289 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/workos.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def self.key!
autoload :AuditTrail, 'workos/audit_trail'
autoload :Connection, 'workos/connection'
autoload :DirectorySync, 'workos/directory_sync'
autoload :Organization, 'workos/organization'
autoload :Portal, 'workos/portal'
autoload :Profile, 'workos/profile'
autoload :SSO, 'workos/sso'
Expand Down
49 changes: 49 additions & 0 deletions lib/workos/organization.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true
# typed: true

require 'json'

module WorkOS
# The Organization class provides a lightweight wrapper around
# a WorkOS Organization resource. This class is not meant to be instantiated
# in user space, and is instantiated internally but exposed.
class Organization
extend T::Sig

attr_accessor :id, :domains, :name

sig { params(json: String).void }
def initialize(json)
raw = parse_json(json)

@id = T.let(raw.id, String)
@name = T.let(raw.name, String)
@domains = T.let(raw.domains, Array)
end

def to_json(*)
{
id: id,
name: name,
domains: domains,
}
end

private

sig do
params(
json_string: String,
).returns(WorkOS::Types::OrganizationStruct)
end
def parse_json(json_string)
hash = JSON.parse(json_string, symbolize_names: true)

WorkOS::Types::OrganizationStruct.new(
id: hash[:id],
name: hash[:name],
domains: hash[:domains],
)
end
end
end
47 changes: 47 additions & 0 deletions lib/workos/portal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,30 @@ class << self
include Base
include Client

# Create an organization
#
# @param [Array<String>] domains List of domains that belong to the
# organization
# @param [String] name A unique, descriptive name for the organization
sig do
params(
domains: T::Array[String],
name: String,
).returns(WorkOS::Organization)
end
def create_organization(domains:, name:)
request = post_request(
auth: true,
body: { domains: domains, name: name },
path: '/organizations',
)

response = execute_request(request: request)
check_and_raise_organization_error(response: response)

WorkOS::Organization.new(response.body)
end

# Retrieve a list of organizations that have connections configured
# within your WorkOS dashboard.
#
Expand Down Expand Up @@ -46,6 +70,29 @@ def list_organizations(options = {})
)
end
# rubocop:enable Metrics/MethodLength

private

sig { params(response: Net::HTTPResponse).void }
# rubocop:disable Metrics/MethodLength
def check_and_raise_organization_error(response:)
begin
body = JSON.parse(response.body)
return unless body['message']

message = body['message']
request_id = response['x-request-id']
rescue StandardError
message = 'Something went wrong'
end

raise APIError.new(
message: message,
http_status: nil,
request_id: request_id,
)
end
# rubocop:enable Metrics/MethodLength
end
end
end
1 change: 1 addition & 0 deletions lib/workos/types.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module WorkOS
module Types
require_relative 'types/connection_struct'
require_relative 'types/list_struct'
require_relative 'types/organization_struct'
require_relative 'types/profile_struct'
require_relative 'types/provider_enum'
end
Expand Down
14 changes: 14 additions & 0 deletions lib/workos/types/organization_struct.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true
# typed: strict

module WorkOS
module Types
# This OrganizationStruct acts as a typed interface
# for the Organization class
class OrganizationStruct < T::Struct
const :id, String
const :name, String
const :domains, T::Array[T.untyped]
end
end
end
33 changes: 33 additions & 0 deletions spec/lib/workos/portal_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,39 @@
WorkOS.key = nil
end

describe '.create_organization' do
context 'with valid payload' do
it 'creates an organization' do
VCR.use_cassette 'organization/create' do
organization = described_class.create_organization(
domains: ['example.com'],
name: 'Test Organization',
)

expect(organization.id).to eq('org_01EHT88Z8J8795GZNQ4ZP1J81T')
expect(organization.name).to eq('Test Organization')
expect(organization.domains.first[:domain]).to eq('example.com')
end
end
end

context 'with an invalid payload' do
it 'returns an error' do
VCR.use_cassette 'organization/create_invalid' do
expect do
described_class.create_organization(
domains: ['example.com'],
name: 'Test Organization 2',
)
end.to raise_error(
WorkOS::APIError,
/An Organization with the domain example.com already exists/,
)
end
end
end
end

describe '.list_organizations' do
context 'with no options' do
it 'returns organizations and metadata' do
Expand Down
72 changes: 72 additions & 0 deletions spec/support/fixtures/vcr_cassettes/organization/create.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
http_interactions:
- request:
method: post
uri: https://api.workos.com/organizations
body:
encoding: UTF-8
string: '{"domains":["example.com"],"name":"Test Organization"}'
headers:
Content-Type:
- application/json
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept:
- "*/*"
User-Agent:
- WorkOS; ruby/2.7.1; x86_64-darwin19; v0.5.0
Authorization:
- Bearer <API_KEY>
response:
status:
code: 201
message: Created
headers:
Server:
- Cowboy
Connection:
- keep-alive
Vary:
- Origin, Accept-Encoding
Access-Control-Allow-Credentials:
- 'true'
Content-Security-Policy:
- 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self''
https: data:;frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src
''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests'
X-Dns-Prefetch-Control:
- 'off'
Expect-Ct:
- max-age=0
X-Frame-Options:
- SAMEORIGIN
Strict-Transport-Security:
- max-age=15552000; includeSubDomains
X-Download-Options:
- noopen
X-Content-Type-Options:
- nosniff
X-Permitted-Cross-Domain-Policies:
- none
Referrer-Policy:
- no-referrer
X-Xss-Protection:
- '0'
X-Request-Id:
- bcddfa8b-3a12-4d48-b265-6094a26225a4
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '203'
Etag:
- W/"cb-T4+GTGrJeuAmC0PAjcaSX5ZXL18"
Date:
- Wed, 09 Sep 2020 20:17:53 GMT
Via:
- 1.1 vegur
body:
encoding: UTF-8
string: '{"name":"Test Organization","object":"organization","id":"org_01EHT88Z8J8795GZNQ4ZP1J81T","domains":[{"domain":"example.com","object":"organization_domain","id":"org_domain_01EHT88Z8WZEFWYPM6EC9BX2R8"}]}'
http_version:
recorded_at: Wed, 09 Sep 2020 20:17:54 GMT
recorded_with: VCR 5.0.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
http_interactions:
- request:
method: post
uri: https://api.workos.com/organizations
body:
encoding: UTF-8
string: '{"domains":["example.com"],"name":"Test Organization 2"}'
headers:
Content-Type:
- application/json
Accept-Encoding:
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
Accept:
- "*/*"
User-Agent:
- WorkOS; ruby/2.7.1; x86_64-darwin19; v0.5.0
Authorization:
- Bearer <API_KEY>
response:
status:
code: 409
message: Conflict
headers:
Server:
- Cowboy
Connection:
- keep-alive
Vary:
- Origin, Accept-Encoding
Access-Control-Allow-Credentials:
- 'true'
Content-Security-Policy:
- 'default-src ''self'';base-uri ''self'';block-all-mixed-content;font-src ''self''
https: data:;frame-ancestors ''self'';img-src ''self'' data:;object-src ''none'';script-src
''self'';script-src-attr ''none'';style-src ''self'' https: ''unsafe-inline'';upgrade-insecure-requests'
X-Dns-Prefetch-Control:
- 'off'
Expect-Ct:
- max-age=0
X-Frame-Options:
- SAMEORIGIN
Strict-Transport-Security:
- max-age=15552000; includeSubDomains
X-Download-Options:
- noopen
X-Content-Type-Options:
- nosniff
X-Permitted-Cross-Domain-Policies:
- none
Referrer-Policy:
- no-referrer
X-Xss-Protection:
- '0'
X-Request-Id:
- 929940d6-33dd-404c-9856-eca6cc606d28
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '73'
Etag:
- W/"49-8i1S2EtfSciiA8rvGWbYFNlSlhw"
Date:
- Wed, 09 Sep 2020 21:26:03 GMT
Via:
- 1.1 vegur
body:
encoding: UTF-8
string: '{"message":"An Organization with the domain example.com already exists."}'
http_version:
recorded_at: Wed, 09 Sep 2020 21:26:03 GMT
recorded_with: VCR 5.0.0

0 comments on commit 71523db

Please sign in to comment.