Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/admin.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Menus } from './resources/project/admin'
import { Menus, Redirects } from './resources/project/admin'

import type { Blutui } from './blutui'
import type { Project } from './project'
import { Request } from './utils/request'

export class Admin extends Request {
readonly menus = new Menus(this)
readonly redirects = new Redirects(this)

constructor(
private readonly project: Project,
Expand Down
3 changes: 2 additions & 1 deletion src/project.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Menus } from './resources/project'
import { Menus, Redirects } from './resources/project'

import type { Blutui } from './blutui'
import { Admin } from './admin'
Expand All @@ -7,6 +7,7 @@ import { Request } from './utils/request'
export class Project extends Request {
readonly admin: Admin
readonly menus = new Menus(this)
readonly redirects = new Redirects(this)

constructor(
public handle: string,
Expand Down
1 change: 1 addition & 0 deletions src/resources/project/admin.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { Menus } from './menus/menus.admin'
export { Redirects } from './redirect/redirect.admin'
1 change: 1 addition & 0 deletions src/resources/project/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { Menus } from './menus/menus'
export { Redirects } from './redirect/redirect'
23 changes: 23 additions & 0 deletions src/resources/project/redirect/fixtures/redirect-list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"object": "list",
"data": [
{
"id": "9bfdb42b-1bf0-4510-978e-46aa329f8efa",
"object": "redirect",
"from": "/old-url",
"to": "/new-url",
"created_at": "2025-01-23T14:03:00+11:00",
"updated_at": "2025-01-23T14:03:00+11:00",
"deleted_at": "2025-01-23T14:03:00+11:00"
}
],
"meta": {
"hasMore": false,
"currentPage": 1,
"from": 1,
"to": 1,
"perPage": 10,
"total": 1,
"lastPage": 1
}
}
9 changes: 9 additions & 0 deletions src/resources/project/redirect/fixtures/redirect.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"id": "9bfdb42b-1bf0-4510-978e-46aa329f8efa",
"object": "redirect",
"from": "/old-url",
"to": "/new-url",
"created_at": "2025-01-23T14:03:00+11:00",
"updated_at": "2025-01-23T14:03:00+11:00",
"deleted_at": "2025-01-23T14:03:00+11:00"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface CreateRedirectOptions {
from: string
to: string
}

export interface SerializedCreateRedirectOptions {
from: string
to: string
}
3 changes: 3 additions & 0 deletions src/resources/project/redirect/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './redirect.interface'
export * from './create-redirect-options.interface'
export * from './update-redirect-options.interface'
19 changes: 19 additions & 0 deletions src/resources/project/redirect/interfaces/redirect.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export interface Redirect {
id: string
object: 'redirect'
from: string
to: string
createdAt: string
updatedAt: string
deletedAt?: string
}

export interface RedirectResponse {
id: string
object: 'redirect'
from: string
to: string
created_at: string
updated_at: string
deleted_at?: string
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface UpdateRedirectOptions {
from?: string
to?: string
}

export interface SerializedUpdateRedirectOptions {
from?: string
to?: string
}
88 changes: 88 additions & 0 deletions src/resources/project/redirect/redirect.admin.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import fetch from 'jest-fetch-mock'
import { Blutui } from '@/blutui'
import { fetchOnce, fetchURL } from '@/utils/testing'

import redirectListFixture from './fixtures/redirect-list.json'
import redirectFixture from './fixtures/redirect.json'

const accessToken =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
const blutui = new Blutui(accessToken)

describe('Redirect', () => {
beforeEach(() => fetch.resetMocks())

describe('list', () => {
it('can retrieve a list of redirects', async () => {
fetchOnce(redirectListFixture)
const redirects = await blutui.project('foo').admin.redirects.list()

expect(fetchURL()).toBe('https://foo.blutui.com/admin/api/redirects')
expect(redirects).toMatchObject({
object: 'list',
})
})
})

describe('get', () => {
it('can retrieve a redirect information', async () => {
fetchOnce(redirectFixture)
const redirect = await blutui
.project('foo')
.admin.redirects.get(redirectFixture.id)

expect(fetchURL()).toBe(
`https://foo.blutui.com/admin/api/redirects/${redirectFixture.id}`
)

expect(redirect).toMatchObject({
object: 'redirect',
})
})
})

describe('create', () => {
it('can create a new redirect', async () => {
fetchOnce(redirectFixture)
const redirect = await blutui.project('foo').admin.redirects.create({
from: '/contact',
to: '/contact-us',
})

expect(fetchURL()).toBe('https://foo.blutui.com/admin/api/redirects')
expect(redirect).toMatchObject({
object: 'redirect',
})
})
})

describe('update', () => {
it('can update a redirect', async () => {
fetchOnce(redirectFixture)
const redirect = await blutui
.project('foo')
.admin.redirects.update(redirectFixture.id, {
from: '/contact',
to: '/contact-us',
})

expect(fetchURL()).toBe(
`https://foo.blutui.com/admin/api/redirects/${redirectFixture.id}`
)
expect(redirect).toMatchObject({
object: 'redirect',
})
})
})

describe('remove', () => {
it('can remove a redirect', async () => {
fetchOnce(redirectFixture)
await blutui.project('foo').admin.redirects.remove(redirectFixture.id)

expect(fetchURL()).toBe(
`https://foo.blutui.com/admin/api/redirects/${redirectFixture.id}`
)
})
})
})
87 changes: 87 additions & 0 deletions src/resources/project/redirect/redirect.admin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import type { Project } from '@/project'
import type {
DeletedResponse,
Expandable,
List,
ListResponse,
PaginationOptions,
} from '@/types'
import type {
Redirect,
RedirectResponse,
CreateRedirectOptions,
SerializedCreateRedirectOptions,
UpdateRedirectOptions,
SerializedUpdateRedirectOptions,
} from './interfaces'
import {
deserializeRedirect,
deserializeRedirectList,
serializeCreateRedirectOptions,
serializeUpdateRedirectOptions,
} from './serializers'
import type { Admin } from '@/admin'

export class Redirects {
constructor(private readonly project: Project | Admin) {}

/**
* Get the redirect list for the current project.
*/
async list(options?: PaginationOptions): Promise<List<Redirect>> {
const { data } = await this.project.get<ListResponse<RedirectResponse>>(
'redirects',
{ query: options }
)

return deserializeRedirectList(data)
}

/**
* Get a redirect's information by ID.
*/
async get(id: string, options?: Expandable<'items'>): Promise<Redirect> {
const { data } = await this.project.get<RedirectResponse>(`redirects/${id}`, {
query: options,
})

return deserializeRedirect(data)
}

/**
* Create a new redirect for a project.
*
* @param payload - The values to create the redirect
*/
async create(payload: CreateRedirectOptions): Promise<Redirect> {
const { data } = await this.project.post<
RedirectResponse,
SerializedCreateRedirectOptions
>('redirects', serializeCreateRedirectOptions(payload))

return deserializeRedirect(data)
}

/**
* Update the redirect for the a project.
*
* @param payload - The values to update the redirect
*/
async update(id: string, payload: UpdateRedirectOptions): Promise<Redirect> {
const { data } = await this.project.patch<
RedirectResponse,
SerializedUpdateRedirectOptions
>(`redirects/${id}`, serializeUpdateRedirectOptions(payload))

return deserializeRedirect(data)
}

/**
* Remove the redirect for the current project.
*/
async remove(id: string): Promise<DeletedResponse> {
const { data } = await this.project.delete<DeletedResponse>(`redirects/${id}`)

return data
}
}
43 changes: 43 additions & 0 deletions src/resources/project/redirect/redirect.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import fetch from 'jest-fetch-mock'
import { Blutui } from '@/blutui'
import { fetchOnce, fetchURL } from '@/utils/testing'

import redirectListFixture from './fixtures/redirect-list.json'
import redirectFixture from './fixtures/redirect.json'

const accessToken =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
const blutui = new Blutui(accessToken)

describe('Redirect', () => {
beforeEach(() => fetch.resetMocks())

describe('list', () => {
it('can retrieve a list of redirects', async () => {
fetchOnce(redirectListFixture)
const redirects = await blutui.project('foo').redirects.list()

expect(fetchURL()).toBe('https://foo.blutui.com/api/redirects')
expect(redirects).toMatchObject({
object: 'list',
})
})
})

describe('get', () => {
it('can retrieve a redirect information', async () => {
fetchOnce(redirectFixture)
const redirect = await blutui
.project('foo')
.redirects.get(redirectFixture.id)

expect(fetchURL()).toBe(
`https://foo.blutui.com/api/redirects/${redirectFixture.id}`
)

expect(redirect).toMatchObject({
object: 'redirect',
})
})
})
})
35 changes: 35 additions & 0 deletions src/resources/project/redirect/redirect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { Project } from '@/project'
import type { Expandable, List, ListResponse, PaginationOptions } from '@/types'
import type { Redirect, RedirectResponse } from './interfaces'
import { deserializeRedirect, deserializeRedirectList } from './serializers'
import type { Admin } from '@/admin'

export class Redirects {
constructor(private readonly project: Project | Admin) {}

/**
* Get the redirect list for the current project.
*/
async list(options?: PaginationOptions): Promise<List<Redirect>> {
const { data } = await this.project.get<ListResponse<RedirectResponse>>(
'redirects',
{ query: options }
)

return deserializeRedirectList(data)
}

/**
* Get a redirect's information by ID.
*/
async get(id: string, options?: Expandable<'items'>): Promise<Redirect> {
const { data } = await this.project.get<RedirectResponse>(
`redirects/${id}`,
{
query: options,
}
)

return deserializeRedirect(data)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type {
CreateRedirectOptions,
SerializedCreateRedirectOptions,
} from '../interfaces'

export const serializeCreateRedirectOptions = (
options: CreateRedirectOptions
): SerializedCreateRedirectOptions => ({
from: options.from,
to: options.to,
})
3 changes: 3 additions & 0 deletions src/resources/project/redirect/serializers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './redirect.serializer'
export * from './create-redirect-options.serializer'
export * from './update-redirect-options.serializer'
Loading