From d473907990088cf123436c2de47c1db9c8a19e86 Mon Sep 17 00:00:00 2001 From: Jayan Ratna Date: Wed, 31 Jul 2024 14:55:43 +1200 Subject: [PATCH 1/5] feat: Add Members API --- .../domains/serializers/domain.serializer.ts | 2 +- src/resources/agency/index.ts | 1 + src/resources/agency/members/interfaces/index.ts | 1 + .../agency/members/interfaces/member.interface.ts | 7 +++++++ src/resources/agency/members/members.spec.ts | 0 src/resources/agency/members/members.ts | 14 ++++++++++++++ src/resources/agency/members/serializers/index.ts | 1 + .../members/serializers/member.serializer.ts | 5 +++++ 8 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/resources/agency/members/interfaces/index.ts create mode 100644 src/resources/agency/members/interfaces/member.interface.ts create mode 100644 src/resources/agency/members/members.spec.ts create mode 100644 src/resources/agency/members/members.ts create mode 100644 src/resources/agency/members/serializers/index.ts create mode 100644 src/resources/agency/members/serializers/member.serializer.ts diff --git a/src/resources/agency/domains/serializers/domain.serializer.ts b/src/resources/agency/domains/serializers/domain.serializer.ts index d6e1d6e..0c671b4 100644 --- a/src/resources/agency/domains/serializers/domain.serializer.ts +++ b/src/resources/agency/domains/serializers/domain.serializer.ts @@ -1,8 +1,8 @@ import { deserializePaginationMeta } from '@/utils/serializers' +import { deserializeProject } from '../../projects/serializers' import type { List, ListResponse } from '@/types' import type { Domain, DomainResponse } from '../interfaces' -import { deserializeProject } from '../../projects/serializers' export const deserializeDomain = (domain: DomainResponse): Domain => ({ id: domain.id, diff --git a/src/resources/agency/index.ts b/src/resources/agency/index.ts index 8b83505..3258f70 100644 --- a/src/resources/agency/index.ts +++ b/src/resources/agency/index.ts @@ -1,3 +1,4 @@ export { Brand } from './brand/brand' export { Domains } from './domains/domains' +export { Members } from './members/members' export { Projects } from './projects/projects' diff --git a/src/resources/agency/members/interfaces/index.ts b/src/resources/agency/members/interfaces/index.ts new file mode 100644 index 0000000..f784509 --- /dev/null +++ b/src/resources/agency/members/interfaces/index.ts @@ -0,0 +1 @@ +export * from './member.interface' diff --git a/src/resources/agency/members/interfaces/member.interface.ts b/src/resources/agency/members/interfaces/member.interface.ts new file mode 100644 index 0000000..eac380a --- /dev/null +++ b/src/resources/agency/members/interfaces/member.interface.ts @@ -0,0 +1,7 @@ +export interface Member { + id: string +} + +export interface MemberResponse { + id: string +} diff --git a/src/resources/agency/members/members.spec.ts b/src/resources/agency/members/members.spec.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/resources/agency/members/members.ts b/src/resources/agency/members/members.ts new file mode 100644 index 0000000..63b9835 --- /dev/null +++ b/src/resources/agency/members/members.ts @@ -0,0 +1,14 @@ +import type { Agency } from '@/agency' +import type { Member } from './interfaces' +import type { List, PaginationOptions } from '@/types' + +export class Members { + constructor(private readonly agency: Agency) {} + + /** + * Get a list of members for the current agency. + */ + async list(options?: PaginationOptions): Promise> { + const {} = await this.agency.get('members', { query: options }) + } +} diff --git a/src/resources/agency/members/serializers/index.ts b/src/resources/agency/members/serializers/index.ts new file mode 100644 index 0000000..eb65cab --- /dev/null +++ b/src/resources/agency/members/serializers/index.ts @@ -0,0 +1 @@ +export * from './member.serializer' diff --git a/src/resources/agency/members/serializers/member.serializer.ts b/src/resources/agency/members/serializers/member.serializer.ts new file mode 100644 index 0000000..0c59503 --- /dev/null +++ b/src/resources/agency/members/serializers/member.serializer.ts @@ -0,0 +1,5 @@ +import type { Member, MemberResponse } from '../interfaces' + +export const deserializeMember = (member: MemberResponse): Member => ({ + id: member.id, +}) From 814d8f1f6f0d99c4ab5141e11ba0e6e501187b65 Mon Sep 17 00:00:00 2001 From: Jayan Ratna Date: Thu, 1 Aug 2024 13:31:16 +1200 Subject: [PATCH 2/5] add tests --- src/agency.ts | 3 +- .../agency/members/fixtures/member-list.json | 31 +++++++++++++++++++ .../agency/members/fixtures/member.json | 20 ++++++++++++ .../members/interfaces/member.interface.ts | 20 ++++++++++++ src/resources/agency/members/members.spec.ts | 27 ++++++++++++++++ src/resources/agency/members/members.ts | 13 ++++++-- .../members/serializers/member.serializer.ts | 21 +++++++++++++ src/resources/agency/roles/roles.spec.ts | 4 +-- 8 files changed, 133 insertions(+), 6 deletions(-) create mode 100644 src/resources/agency/members/fixtures/member-list.json create mode 100644 src/resources/agency/members/fixtures/member.json diff --git a/src/agency.ts b/src/agency.ts index 57a7440..50f1fc5 100644 --- a/src/agency.ts +++ b/src/agency.ts @@ -1,4 +1,4 @@ -import { Brand, Domains, Projects, Roles } from './resources/agency' +import { Brand, Domains, Members, Projects, Roles } from './resources/agency' import type { Blutui } from './blutui' import type { GetOptions, PostOptions } from './types' @@ -6,6 +6,7 @@ import type { GetOptions, PostOptions } from './types' export class Agency { readonly brand = new Brand(this) readonly domains = new Domains(this) + readonly members = new Members(this) readonly projects = new Projects(this) readonly roles = new Roles(this) diff --git a/src/resources/agency/members/fixtures/member-list.json b/src/resources/agency/members/fixtures/member-list.json new file mode 100644 index 0000000..6ee7db3 --- /dev/null +++ b/src/resources/agency/members/fixtures/member-list.json @@ -0,0 +1,31 @@ +{ + "object": "list", + "data": [ + { + "id": "99bc147e-3ad5-4b09-a2e2-b21bd680ad05", + "object": "member", + "name": "Mara Schuppe", + "avatar_url": null, + "email": "mara@blutui.dev", + "two_factor_enabled": false, + "has_full_access": true, + "role": { + "id": 1, + "name": "Owner", + "description": null, + "is_super": true + }, + "created_at": 1690330767, + "updated_at": 1720481455 + } + ], + "meta": { + "hasMore": false, + "currentPage": 1, + "from": 1, + "to": 1, + "perPage": 10, + "total": 1, + "lastPage": 1 + } +} diff --git a/src/resources/agency/members/fixtures/member.json b/src/resources/agency/members/fixtures/member.json new file mode 100644 index 0000000..22d9c18 --- /dev/null +++ b/src/resources/agency/members/fixtures/member.json @@ -0,0 +1,20 @@ +{ + "id": "99bc147e-3ad5-4b09-a2e2-b21bd680ad05", + "object": "member", + "name": "Mara Schuppe", + "avatar_url": null, + "email": "mara@blutui.dev", + "two_factor_enabled": false, + "has_full_access": true, + "role": { + "id": 1, + "object": "role", + "name": "Owner", + "description": null, + "is_super": true, + "created_at": 1690330767, + "updated_at": 1690330767 + }, + "created_at": 1690330767, + "updated_at": 1720481455 +} diff --git a/src/resources/agency/members/interfaces/member.interface.ts b/src/resources/agency/members/interfaces/member.interface.ts index eac380a..72b2243 100644 --- a/src/resources/agency/members/interfaces/member.interface.ts +++ b/src/resources/agency/members/interfaces/member.interface.ts @@ -1,7 +1,27 @@ +import type { Role, RoleResponse } from '../../roles/interfaces' + export interface Member { id: string + object: 'member' + name: string + avatarUrl: string | null + email: string + twoFactorEnabled: boolean + hasFullAccess: boolean + role: Role + createdAt: number + updatedAt: number } export interface MemberResponse { id: string + object: 'member' + name: string + avatar_url: string | null + email: string + two_factor_enabled: boolean + has_full_access: boolean + role: RoleResponse + created_at: number + updated_at: number } diff --git a/src/resources/agency/members/members.spec.ts b/src/resources/agency/members/members.spec.ts index e69de29..964b248 100644 --- a/src/resources/agency/members/members.spec.ts +++ b/src/resources/agency/members/members.spec.ts @@ -0,0 +1,27 @@ +import fetch from 'jest-fetch-mock' +import { Blutui } from '@/blutui' +import { fetchOnce, fetchURL } from '@/utils/testing' + +// import memberFixture from './fixtures/member.json' +import memberListFixture from './fixtures/member-list.json' + +const accessToken = + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' +const blutui = new Blutui(accessToken) + +describe('Member', () => { + beforeEach(() => fetch.resetMocks()) + + describe('list', () => { + it('can retrieve a list of', async () => { + fetchOnce(memberListFixture) + const members = await blutui.agency('foo').members.list() + + expect(fetchURL()).toBe(`${blutui.baseURL}/v1/agencies/foo/members`) + expect(members).toMatchObject({ + object: 'list', + data: [{ hasFullAccess: true }], + }) + }) + }) +}) diff --git a/src/resources/agency/members/members.ts b/src/resources/agency/members/members.ts index 63b9835..474d762 100644 --- a/src/resources/agency/members/members.ts +++ b/src/resources/agency/members/members.ts @@ -1,6 +1,8 @@ +import { deserializeMemberList } from './serializers' + import type { Agency } from '@/agency' -import type { Member } from './interfaces' -import type { List, PaginationOptions } from '@/types' +import type { Member, MemberResponse } from './interfaces' +import type { List, ListResponse, PaginationOptions } from '@/types' export class Members { constructor(private readonly agency: Agency) {} @@ -9,6 +11,11 @@ export class Members { * Get a list of members for the current agency. */ async list(options?: PaginationOptions): Promise> { - const {} = await this.agency.get('members', { query: options }) + const { data } = await this.agency.get>( + 'members', + { query: options } + ) + + return deserializeMemberList(data) } } diff --git a/src/resources/agency/members/serializers/member.serializer.ts b/src/resources/agency/members/serializers/member.serializer.ts index 0c59503..92b5c05 100644 --- a/src/resources/agency/members/serializers/member.serializer.ts +++ b/src/resources/agency/members/serializers/member.serializer.ts @@ -1,5 +1,26 @@ +import { deserializePaginationMeta } from '@/utils/serializers' +import { deserializeRole } from '../../roles/serializers' + +import type { List, ListResponse } from '@/types' import type { Member, MemberResponse } from '../interfaces' export const deserializeMember = (member: MemberResponse): Member => ({ id: member.id, + object: member.object, + name: member.name, + avatarUrl: member.avatar_url, + email: member.email, + twoFactorEnabled: member.two_factor_enabled, + hasFullAccess: member.has_full_access, + role: deserializeRole(member.role), + createdAt: member.created_at, + updatedAt: member.updated_at, +}) + +export const deserializeMemberList = ( + members: ListResponse +): List => ({ + object: 'list', + data: members.data.map(deserializeMember), + meta: deserializePaginationMeta(members.meta), }) diff --git a/src/resources/agency/roles/roles.spec.ts b/src/resources/agency/roles/roles.spec.ts index e702340..0a3fc63 100644 --- a/src/resources/agency/roles/roles.spec.ts +++ b/src/resources/agency/roles/roles.spec.ts @@ -15,10 +15,10 @@ describe('Role', () => { describe('list', () => { it('can retrieve a list of roles', async () => { fetchOnce(roleListFixture) - const domains = await blutui.agency('foo').roles.list() + const roles = await blutui.agency('foo').roles.list() expect(fetchURL()).toBe(`${blutui.baseURL}/v1/agencies/foo/roles`) - expect(domains).toMatchObject({ + expect(roles).toMatchObject({ object: 'list', }) }) From 1773bb1459807d44e0768e14c262dd02901530e7 Mon Sep 17 00:00:00 2001 From: Jayan Ratna Date: Thu, 1 Aug 2024 13:35:29 +1200 Subject: [PATCH 3/5] improve test workflow --- .github/workflows/tests.yml | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0ddf28b..0f282b1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,35 +9,12 @@ on: - main jobs: - lint: - runs-on: ubuntu-latest - - name: Lint - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: "npm" - - - name: Install dependencies - run: | - npm install - - - name: Run lint - run: | - npm run lint - test: runs-on: ubuntu-latest strategy: matrix: - node: [18, 20] + node: [18, 20, 22] name: Node ${{ matrix.node }} @@ -55,6 +32,10 @@ jobs: run: | npm install + - name: Lint + run: | + npm run lint + - name: Run tests run: | npm run test From d28bd13104c3ae26dd1d32011835cc74a61b4a31 Mon Sep 17 00:00:00 2001 From: Jayan Ratna Date: Wed, 7 Aug 2024 13:07:34 +1200 Subject: [PATCH 4/5] add additional methods to members resource --- src/agency.ts | 8 +-- src/blutui.ts | 8 ++- .../agency/members/interfaces/index.ts | 1 + .../members/interfaces/member.interface.ts | 4 +- .../update-member-options.interface.ts | 9 +++ src/resources/agency/members/members.spec.ts | 62 ++++++++++++++++++- src/resources/agency/members/members.ts | 50 ++++++++++++++- .../agency/members/serializers/index.ts | 1 + .../members/serializers/member.serializer.ts | 2 +- .../update-member-options.serializer.ts | 11 ++++ src/utils/testing.ts | 4 ++ 11 files changed, 146 insertions(+), 14 deletions(-) create mode 100644 src/resources/agency/members/interfaces/update-member-options.interface.ts create mode 100644 src/resources/agency/members/serializers/update-member-options.serializer.ts diff --git a/src/agency.ts b/src/agency.ts index 50f1fc5..772b31e 100644 --- a/src/agency.ts +++ b/src/agency.ts @@ -16,7 +16,7 @@ export class Agency { ) {} async get(path: string, options: GetOptions = {}) { - return this.blutui.get(this.getAgencyPath(path), options) + return await this.blutui.get(this.getAgencyPath(path), options) } async post( @@ -24,7 +24,7 @@ export class Agency { entity: Entity, options: PostOptions = {} ) { - return this.blutui.post( + return await this.blutui.post( this.getAgencyPath(path), entity, options @@ -36,7 +36,7 @@ export class Agency { entity: Entity, options: PostOptions = {} ) { - return this.blutui.patch( + return await this.blutui.patch( this.getAgencyPath(path), entity, options @@ -44,7 +44,7 @@ export class Agency { } async delete(path: string, options: PostOptions = {}) { - return this.blutui.delete(this.getAgencyPath(path), options) + return await this.blutui.delete(this.getAgencyPath(path), options) } /** diff --git a/src/blutui.ts b/src/blutui.ts index d566d53..5a196ea 100644 --- a/src/blutui.ts +++ b/src/blutui.ts @@ -1,6 +1,6 @@ import { Agency } from './agency' import { - type FetchException, + FetchException, GenericServerException, NoAccessTokenProvidedException, NotFoundException, @@ -122,7 +122,7 @@ export class Blutui { options: PatchOptions = {} ): Promise<{ data: Result }> { try { - return this.client.patch(path, entity, { + return await this.client.patch(path, entity, { params: options.query, }) } catch (error) { @@ -148,6 +148,10 @@ export class Blutui { } private handleFetchError({ path, error }: { path: string; error: unknown }) { + if (!(error instanceof FetchException)) { + throw new Error(`Unexpected error: ${error}`) + } + const { response } = error as FetchException if (response) { diff --git a/src/resources/agency/members/interfaces/index.ts b/src/resources/agency/members/interfaces/index.ts index f784509..18772b1 100644 --- a/src/resources/agency/members/interfaces/index.ts +++ b/src/resources/agency/members/interfaces/index.ts @@ -1 +1,2 @@ export * from './member.interface' +export * from './update-member-options.interface' diff --git a/src/resources/agency/members/interfaces/member.interface.ts b/src/resources/agency/members/interfaces/member.interface.ts index 72b2243..ad92ee0 100644 --- a/src/resources/agency/members/interfaces/member.interface.ts +++ b/src/resources/agency/members/interfaces/member.interface.ts @@ -4,7 +4,7 @@ export interface Member { id: string object: 'member' name: string - avatarUrl: string | null + avatar: string | null email: string twoFactorEnabled: boolean hasFullAccess: boolean @@ -17,7 +17,7 @@ export interface MemberResponse { id: string object: 'member' name: string - avatar_url: string | null + avatar: string | null email: string two_factor_enabled: boolean has_full_access: boolean diff --git a/src/resources/agency/members/interfaces/update-member-options.interface.ts b/src/resources/agency/members/interfaces/update-member-options.interface.ts new file mode 100644 index 0000000..acea4d5 --- /dev/null +++ b/src/resources/agency/members/interfaces/update-member-options.interface.ts @@ -0,0 +1,9 @@ +export interface UpdateMemberOptions { + role?: number + hasFullAccess?: boolean +} + +export interface SerializedUpdateMemberOptions { + role?: number + has_full_access?: boolean +} diff --git a/src/resources/agency/members/members.spec.ts b/src/resources/agency/members/members.spec.ts index 964b248..e5fbc6b 100644 --- a/src/resources/agency/members/members.spec.ts +++ b/src/resources/agency/members/members.spec.ts @@ -2,8 +2,9 @@ import fetch from 'jest-fetch-mock' import { Blutui } from '@/blutui' import { fetchOnce, fetchURL } from '@/utils/testing' -// import memberFixture from './fixtures/member.json' +import memberFixture from './fixtures/member.json' import memberListFixture from './fixtures/member-list.json' +import { ValidationException } from '@/exceptions' const accessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' @@ -13,7 +14,7 @@ describe('Member', () => { beforeEach(() => fetch.resetMocks()) describe('list', () => { - it('can retrieve a list of', async () => { + it('can retrieve a list of members', async () => { fetchOnce(memberListFixture) const members = await blutui.agency('foo').members.list() @@ -24,4 +25,61 @@ describe('Member', () => { }) }) }) + + describe('get', () => { + it('can retrieve a member', async () => { + fetchOnce(memberFixture) + const member = await blutui.agency('foo').members.get(memberFixture.id) + + expect(fetchURL()).toBe( + `${blutui.baseURL}/v1/agencies/foo/members/${memberFixture.id}` + ) + expect(member).toMatchObject({ + object: 'member', + }) + }) + }) + + describe('update', () => { + it('can update a member', async () => { + fetchOnce(memberFixture) + const member = await blutui + .agency('foo') + .members.update(memberFixture.id, { role: 2 }) + + expect(fetchURL()).toBe( + `${blutui.baseURL}/v1/agencies/foo/members/${memberFixture.id}` + ) + expect(member).toMatchObject({ + object: 'member', + }) + }) + + it('can not update the current users member information', async () => { + fetchOnce( + { message: 'You can not update your own agency access.' }, + { status: 422 } + ) + + await expect( + blutui.agency('foo').members.update('my-id', { role: 2 }) + ).rejects.toThrow(ValidationException) + }) + }) + + describe('remove', () => { + it('can remove a member from an agency', async () => { + fetchOnce({ id: memberFixture.id, object: 'member', deleted: true }) + const removedMember = await blutui + .agency('foo') + .members.remove(memberFixture.id) + + expect(fetchURL()).toBe( + `${blutui.baseURL}/v1/agencies/foo/members/${memberFixture.id}` + ) + expect(removedMember).toMatchObject({ + object: 'member', + }) + }) + }) }) diff --git a/src/resources/agency/members/members.ts b/src/resources/agency/members/members.ts index 474d762..1ece1e8 100644 --- a/src/resources/agency/members/members.ts +++ b/src/resources/agency/members/members.ts @@ -1,8 +1,22 @@ -import { deserializeMemberList } from './serializers' +import { + deserializeMember, + deserializeMemberList, + serializeUpdateMemberOptions, +} from './serializers' import type { Agency } from '@/agency' -import type { Member, MemberResponse } from './interfaces' -import type { List, ListResponse, PaginationOptions } from '@/types' +import type { + Member, + MemberResponse, + SerializedUpdateMemberOptions, + UpdateMemberOptions, +} from './interfaces' +import type { + DeletedResponse, + List, + ListResponse, + PaginationOptions, +} from '@/types' export class Members { constructor(private readonly agency: Agency) {} @@ -18,4 +32,34 @@ export class Members { return deserializeMemberList(data) } + + /** + * Get a member from the current agency. + */ + async get(id: string): Promise { + const { data } = await this.agency.get(`members/${id}`) + + return deserializeMember(data) + } + + /** + * Update a member of the current agency. + */ + async update(id: string, payload: UpdateMemberOptions): Promise { + const { data } = await this.agency.patch< + MemberResponse, + SerializedUpdateMemberOptions + >(`members/${id}`, serializeUpdateMemberOptions(payload)) + + return deserializeMember(data) + } + + /** + * Remove a member from the current agency. + */ + async remove(id: string): Promise { + const { data } = await this.agency.delete(`members/${id}`) + + return data + } } diff --git a/src/resources/agency/members/serializers/index.ts b/src/resources/agency/members/serializers/index.ts index eb65cab..7306a1d 100644 --- a/src/resources/agency/members/serializers/index.ts +++ b/src/resources/agency/members/serializers/index.ts @@ -1 +1,2 @@ export * from './member.serializer' +export * from './update-member-options.serializer' diff --git a/src/resources/agency/members/serializers/member.serializer.ts b/src/resources/agency/members/serializers/member.serializer.ts index 92b5c05..e8716e2 100644 --- a/src/resources/agency/members/serializers/member.serializer.ts +++ b/src/resources/agency/members/serializers/member.serializer.ts @@ -8,7 +8,7 @@ export const deserializeMember = (member: MemberResponse): Member => ({ id: member.id, object: member.object, name: member.name, - avatarUrl: member.avatar_url, + avatar: member.avatar, email: member.email, twoFactorEnabled: member.two_factor_enabled, hasFullAccess: member.has_full_access, diff --git a/src/resources/agency/members/serializers/update-member-options.serializer.ts b/src/resources/agency/members/serializers/update-member-options.serializer.ts new file mode 100644 index 0000000..782c562 --- /dev/null +++ b/src/resources/agency/members/serializers/update-member-options.serializer.ts @@ -0,0 +1,11 @@ +import type { + SerializedUpdateMemberOptions, + UpdateMemberOptions, +} from '../interfaces' + +export const serializeUpdateMemberOptions = ( + options: UpdateMemberOptions +): SerializedUpdateMemberOptions => ({ + role: options.role, + has_full_access: options.hasFullAccess, +}) diff --git a/src/utils/testing.ts b/src/utils/testing.ts index 2b7e64a..1ca319f 100644 --- a/src/utils/testing.ts +++ b/src/utils/testing.ts @@ -15,6 +15,10 @@ export function fetchURL() { return fetch.mock.calls[0][0] } +export function fetchSearchParams() { + return Object.fromEntries(new URL(String(fetchURL())).searchParams) +} + export function fetchHeaders() { return fetch.mock.calls[0][1]?.headers } From 4b6a5dc98dbb15150f3e2efac03e6e829818fc2d Mon Sep 17 00:00:00 2001 From: Chengfang Liu Date: Thu, 8 Aug 2024 10:31:48 +1200 Subject: [PATCH 5/5] remove role permissions from member response --- .../members/interfaces/member.interface.ts | 4 +-- .../agency/roles/interfaces/role.interface.ts | 4 +-- .../roles/serializers/role.serializer.ts | 36 ++++++------------- 3 files changed, 15 insertions(+), 29 deletions(-) diff --git a/src/resources/agency/members/interfaces/member.interface.ts b/src/resources/agency/members/interfaces/member.interface.ts index ad92ee0..79eb1cc 100644 --- a/src/resources/agency/members/interfaces/member.interface.ts +++ b/src/resources/agency/members/interfaces/member.interface.ts @@ -8,7 +8,7 @@ export interface Member { email: string twoFactorEnabled: boolean hasFullAccess: boolean - role: Role + role: Omit createdAt: number updatedAt: number } @@ -21,7 +21,7 @@ export interface MemberResponse { email: string two_factor_enabled: boolean has_full_access: boolean - role: RoleResponse + role: Omit created_at: number updated_at: number } diff --git a/src/resources/agency/roles/interfaces/role.interface.ts b/src/resources/agency/roles/interfaces/role.interface.ts index 3adb533..f8a88b4 100644 --- a/src/resources/agency/roles/interfaces/role.interface.ts +++ b/src/resources/agency/roles/interfaces/role.interface.ts @@ -24,7 +24,7 @@ export interface Role { description: string isSuper: boolean usersCount?: number - permissions: { [key in Permission]: boolean } + permissions?: { [key in Permission]: boolean } createdAt: number updatedAt: number } @@ -36,7 +36,7 @@ export interface RoleResponse { description: string is_super: boolean users_count?: number - permissions: { [key in Permission]: boolean } + permissions?: { [key in Permission]: boolean } created_at: number updated_at: number } diff --git a/src/resources/agency/roles/serializers/role.serializer.ts b/src/resources/agency/roles/serializers/role.serializer.ts index 14ac59a..e5bd77f 100644 --- a/src/resources/agency/roles/serializers/role.serializer.ts +++ b/src/resources/agency/roles/serializers/role.serializer.ts @@ -3,31 +3,17 @@ import { deserializePaginationMeta } from '@/utils/serializers' import type { List, ListResponse } from '@/types' import type { Role, RoleResponse } from '../interfaces' -export const deserializeRole = (role: RoleResponse): Role => { - const { - id, - object, - name, - description, - is_super: isSuper, - permissions, - created_at: createdAt, - updated_at: updatedAt, - users_count: usersCount, - } = role - - return { - id, - object, - name, - description, - isSuper, - permissions, - createdAt, - updatedAt, - ...(usersCount !== undefined && { usersCount }), - } -} +export const deserializeRole = (role: RoleResponse): Role => ({ + id: role.id, + object: role.object, + name: role.name, + description: role.description, + isSuper: role.is_super, + ...(role.users_count !== undefined && { usersCount: role.users_count }), + ...(role.permissions !== undefined && { permissions: role.permissions }), + createdAt: role.created_at, + updatedAt: role.updated_at, +}) export const deserializeRoleList = ( roles: ListResponse