diff --git a/src/lib/microsoft-partnercenter.spec.ts b/src/lib/microsoft-partnercenter.spec.ts index 055d8dd..ce7b6ae 100644 --- a/src/lib/microsoft-partnercenter.spec.ts +++ b/src/lib/microsoft-partnercenter.spec.ts @@ -174,4 +174,37 @@ describe('Microsoft Partner Center', () => { expect(result).toEqual(licenses) expect(mockAxios.get).toHaveBeenCalledWith('/customers/1/subscribedskus') }) + + it('should create a customer', async () => { + const customer = { id: '1' } + jest.spyOn(mockAxios, 'post').mockResolvedValue({ data: customer }) + const result = await partnerCenter.createCustomer({ id: '1' } as never) + expect(result).toEqual(customer) + expect(mockAxios.post).toHaveBeenCalledWith('/customers', { id: '1' }) + }) + + it('should create a user', async () => { + const user = { id: '1' } + jest.spyOn(mockAxios, 'post').mockResolvedValue({ data: user }) + const result = await partnerCenter.createUser('1', { id: '1' } as never) + expect(result).toEqual(user) + expect(mockAxios.post).toHaveBeenCalledWith('/customers/1/users', { + id: '1', + }) + }) + + it('should set user role', async () => { + jest.spyOn(mockAxios, 'post').mockResolvedValue({ data: {} }) + const result = await partnerCenter.setUserRole('1', '1', { + Id: '1', + DisplayName: 'test', + UserPrincipalName: 'test', + }) + expect(result).toEqual({}) + expect(mockAxios.post).toHaveBeenCalledWith('/customers/1/directoryroles/1/usermembers', { + Id: '1', + DisplayName: 'test', + UserPrincipalName: 'test', + }) + }) }) diff --git a/src/lib/microsoft-partnercenter.ts b/src/lib/microsoft-partnercenter.ts index 2fba455..5fb0672 100644 --- a/src/lib/microsoft-partnercenter.ts +++ b/src/lib/microsoft-partnercenter.ts @@ -1,14 +1,15 @@ import { AxiosInstance } from 'axios' -import { ApplicationConsent } from './types' +import { ApplicationConsent, CreateUser, SetUserRole, SetUserRoleResponse, User } from './types' import { Availability } from './types/availabilities.types' import { IPartnerCenterConfig } from './types/common.types' -import { Customer } from './types/customers.types' +import { CreateCustomer, Customer } from './types/customers.types' import { Invoice } from './types/invoices.types' import { OrderLineItem, OrderLineItemOptions, OrderResponse } from './types/orders.types' import { Sku } from './types/sku.types' import { Subscription } from './types/subscriptions.types' import { TokenManager, initializeHttpAndTokenManager } from './utils/http-token-manager' import { LicenseUsage } from './types/licenses.types' +import { CreateGDAPRelationship, GDAPRelationship } from './types/gdap.types' export class MicrosoftPartnerCenter { private readonly httpAgent: AxiosInstance @@ -66,6 +67,36 @@ export class MicrosoftPartnerCenter { return sub } + async createCustomer(data: CreateCustomer): Promise { + const { data: customer } = await this.httpAgent.post('/customers', data) + return customer + } + + async createUser(customerId: string, data: CreateUser): Promise { + const { data: user } = await this.httpAgent.post(`/customers/${customerId}/users`, data) + return user + } + + async setUserRole( + customerId: string, + roleId: string, + data: SetUserRole, + ): Promise { + const { data: userRole } = await this.httpAgent.post( + `/customers/${customerId}/directoryroles/${roleId}/usermembers`, + data, + ) + return userRole + } + + async createGDAPRelationship(data: CreateGDAPRelationship): Promise { + const { data: gdapRelationship } = await this.httpAgent.post( + '/tenantRelationships/delegatedAdminRelationships', + data, + ) + return gdapRelationship + } + async updateCustomerSubscriptionUsers( customerId: string, subscriptionId: string, diff --git a/src/lib/types/customers.types.ts b/src/lib/types/customers.types.ts index c27bece..5e0e31a 100644 --- a/src/lib/types/customers.types.ts +++ b/src/lib/types/customers.types.ts @@ -29,3 +29,29 @@ export type Links = LinksBase export enum RelationshipToPartner { Reseller = 'reseller', } + +export interface CreateCustomer { + enableGDAPByDefault: boolean + CompanyProfile: { + Domain: string + } + BillingProfile: BillingProfile +} + +export interface BillingProfile { + Culture: string + Email: string + Language: string + CompanyName: string + DefaultAddress: DefaultAddress +} + +export interface DefaultAddress { + FirstName: string + LastName: string + AddressLine1: string + City: string + State: string + PostalCode: string + Country: string +} diff --git a/src/lib/types/gdap.types.ts b/src/lib/types/gdap.types.ts new file mode 100644 index 0000000..8f121d1 --- /dev/null +++ b/src/lib/types/gdap.types.ts @@ -0,0 +1,41 @@ +export interface CreateGDAPRelationship { + displayName: string + duration: string + customer: GDAPCustomer + accessDetails: AccessDetails + autoExtendDuration: string +} + +export interface AccessDetails { + unifiedRoles: UnifiedRole[] +} + +export interface UnifiedRole { + roleDefinitionId: string +} + +export interface GDAPCustomer { + tenantId: string + displayName: string +} + +export interface GDAPRelationship { + '@odata.type': '#microsoft.graph.delegatedAdminRelationship' + '@odata.context': 'https://graph.microsoft.com/v1.0/tenantRelationships/$metadata#delegatedAdminRelationships' + '@odata.etag': string + id: string + displayName: string + duration: string + customer: GDAPCustomer + accessDetails: AccessDetails + status: string + autoExtendDuration: string + createdDateTime: Date + lastModifiedDateTime: Date + activatedDateTime: string + endDateTime: Date +} + +export interface AccessDetails { + unifiedRoles: UnifiedRole[] +} diff --git a/src/lib/types/index.ts b/src/lib/types/index.ts index cdaf3c0..207f836 100644 --- a/src/lib/types/index.ts +++ b/src/lib/types/index.ts @@ -7,3 +7,5 @@ export * from './sku.types' export * from './availabilities.types' export * from './application-consent.types' export * from './licenses.types' +export * from './users.types' +export * from './gdap.types' diff --git a/src/lib/types/users.types.ts b/src/lib/types/users.types.ts new file mode 100644 index 0000000..8a81eb5 --- /dev/null +++ b/src/lib/types/users.types.ts @@ -0,0 +1,53 @@ +export interface CreateUser { + usageLocation: string + userPrincipalName: string + firstName: string + lastName: string + displayName: string + passwordProfile: PasswordProfile +} + +export interface PasswordProfile { + forceChangePassword: boolean + password: string +} + +export interface User { + usageLocation: string + id: string + userPrincipalName: string + firstName: string + lastName: string + displayName: string + immutableId: string + passwordProfile: PasswordProfile + lastDirectorySyncTime: null + userDomainType: string + state: string + softDeletionTime: { objectType: 'CustomerUser' } +} + +export interface SetUserRole { + /** + * The ID of the user + */ + Id: string + /** + * The Display Name of the user + */ + DisplayName: string + /** + * The User's Principal Name + */ + UserPrincipalName: string +} + +export interface SetUserRoleResponse { + displayName: string + userPrincipalName: string + roleId: string + id: string + attributes: { + objectType: 'UserMember' + } +}