Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define model and refactor ApiClient #59

Merged
merged 24 commits into from
Sep 26, 2024
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
94 changes: 17 additions & 77 deletions src/api/ApiClient.ts
Original file line number Diff line number Diff line change
@@ -1,101 +1,41 @@
/* eslint-disable react/no-is-mounted */

import { PlaygroundClient } from '@wp-playground/client';

Check warning on line 2 in src/api/ApiClient.ts

View workflow job for this annotation

GitHub Actions / lint

PlaygroundClient not found in '@wp-playground/client'
import { Post } from '@/api/Post';
import { Settings } from '@/api/Settings';
import { User } from '@/api/User';
import { PostContent, PostDate, PostTitle } from '@/parser/post';

export interface CreatePostBody {
guid: string;
}

export interface CreateUserBody {
username: string;
email: string;
password: string;
role?: string; // default roles: administrator, editor, author, subscriber (default)
firstname?: string;
lastname?: string;
}

export interface UpdatePostBody {
date?: PostDate;
title?: PostTitle;
content?: PostContent;
}
import { PostsApi } from '@/api/Posts';
import { SettingsApi } from '@/api/Settings';
import { UsersApi } from '@/api/Users';

export class ApiClient {
private readonly playgroundClient: PlaygroundClient;
private readonly _siteUrl: string;
private readonly _posts: PostsApi;
private readonly _settings: SettingsApi;
private readonly _users: UsersApi;

constructor( playgroundClient: PlaygroundClient, siteUrl: string ) {
this.playgroundClient = playgroundClient;
this._siteUrl = siteUrl;
this._posts = new PostsApi( this );
this._settings = new SettingsApi( this );
this._users = new UsersApi( this );
}

get siteUrl(): string {
return this._siteUrl;
}

async createPost( body: CreatePostBody ): Promise< Post > {
return ( await this.post( '/liberated_posts', {
meta: {
guid: body.guid,
},
} ) ) as Post;
}

async updatePost( id: number, body: UpdatePostBody ): Promise< Post > {
const actualBody: any = {};
if ( body.date ) {
actualBody.date = body.date.parsed;
}
if ( body.title ) {
actualBody.title = body.title.parsed;
}
if ( body.content ) {
actualBody.content = body.content.parsed;
actualBody.meta = {
raw_content: body.content.original,
};
}
return ( await this.post(
`/liberated_posts/${ id }`,
actualBody
) ) as Post;
get posts(): PostsApi {
return this._posts;
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
async getPostByGuid( guid: string ): Promise< Post | null > {
return null;
get settings(): SettingsApi {
return this._settings;
}

async updateSiteTitle( title: string ): Promise< Settings > {
return ( await this.post( `/settings`, {
title,
} ) ) as Settings;
}

async createUser( body: CreateUserBody ): Promise< User > {
const actualBody: any = {
username: body.username,
email: body.email,
password: body.password,
};
if ( body.role ) {
actualBody.roles = [ body.role ];
}
if ( body.firstname ) {
actualBody.first_name = body.firstname;
}
if ( body.lastname ) {
actualBody.last_name = body.lastname;
}
return ( await this.post( `/users`, actualBody ) ) as User;
get users(): UsersApi {
return this._users;
}

private async get( route: string ): Promise< object > {
async get( route: string ): Promise< object > {
const response = await this.playgroundClient.request( {
url: `/index.php?rest_route=/wp/v2${ route }`,
method: 'GET',
Expand All @@ -107,7 +47,7 @@
return response.json;
}

private async post( route: string, body: object ): Promise< object > {
async post( route: string, body: object ): Promise< object > {
const response = await this.playgroundClient.request( {
url: `/index.php?rest_route=/wp/v2${ route }`,
method: 'POST',
Expand Down
7 changes: 0 additions & 7 deletions src/api/Post.ts

This file was deleted.

86 changes: 86 additions & 0 deletions src/api/Posts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/* eslint-disable camelcase */
import { WP_REST_API_Post } from 'wp-types';
type ApiPost = WP_REST_API_Post;
/* eslint-enable camelcase */

import { Post, PostContent, PostDate, PostTitle } from '@/model/Post';
import { ApiClient } from '@/api/ApiClient';

interface CreateBody {
guid: string;
}

interface UpdateBody {
date?: PostDate;
title?: PostTitle;
content?: PostContent;
}

interface PostMeta {
guid: string;
raw_title: string;
raw_date: string;
raw_content: string;
}

export class PostsApi {
// eslint-disable-next-line no-useless-constructor
constructor( private readonly client: ApiClient ) {}

async create( body: CreateBody ): Promise< Post > {
const response = ( await this.client.post( '/liberated_posts', {
meta: {
ashfame marked this conversation as resolved.
Show resolved Hide resolved
guid: body.guid,
},
} ) ) as ApiPost;
return makePostFromApiResponse( response );
}

async update( id: number, body: UpdateBody ): Promise< Post > {
const actualBody: any = {};
if ( body.date ) {
actualBody.date = body.date.parsed;
}
if ( body.title ) {
actualBody.title = body.title.parsed;
}
if ( body.content ) {
actualBody.content = body.content.parsed;
actualBody.meta = {
raw_content: body.content.original,
};
}
if ( Object.keys( actualBody ).length === 0 ) {
throw Error( 'attempting to update zero fields' );
}
const response = ( await this.client.post(
`/liberated_posts/${ id }`,
actualBody
) ) as ApiPost;
return makePostFromApiResponse( response );
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
async getByGuid( guid: string ): Promise< Post | null > {
return null;
}
}

function makePostFromApiResponse( response: ApiPost ): Post {
const meta = response.meta as unknown as PostMeta;
const date = new PostDate( response.date_gmt, meta.raw_date );
const title = new PostTitle( response.title.raw ?? '', meta.raw_title );
const content = new PostContent(
response.content.raw ?? '',
meta.raw_content
);

return {
guid: meta.guid,
id: response.id,
url: response.link,
date,
content,
title,
};
}
38 changes: 35 additions & 3 deletions src/api/Settings.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,39 @@
/* eslint-disable camelcase */

import { WP_REST_API_Settings } from 'wp-types';
type ApiSettings = WP_REST_API_Settings;
/* eslint-enable camelcase */

export interface Settings extends WP_REST_API_Settings {}
import { ApiClient } from '@/api/ApiClient';
import { SiteSettings } from '@/model/SiteSettings';

/* eslint-enable camelcase */
interface UpdateBody {
title?: string;
}

export class SettingsApi {
// eslint-disable-next-line no-useless-constructor
constructor( private readonly client: ApiClient ) {}

async update( body: UpdateBody ): Promise< SiteSettings > {
const actualBody: any = {};
if ( body.title ) {
actualBody.title = body.title;
}
if ( Object.keys( actualBody ).length === 0 ) {
throw Error( 'attempting to update zero fields' );
}
const response = ( await this.client.post(
`/settings`,
actualBody
) ) as ApiSettings;
return makeSiteSettingsFromApiResponse( response );
}
}

function makeSiteSettingsFromApiResponse(
response: ApiSettings
): SiteSettings {
return {
title: response.title,
};
}
7 changes: 0 additions & 7 deletions src/api/User.ts

This file was deleted.

53 changes: 53 additions & 0 deletions src/api/Users.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* eslint-disable camelcase */
import { WP_REST_API_User } from 'wp-types';
type ApiUser = WP_REST_API_User;
/* eslint-enable camelcase */

import { ApiClient } from '@/api/ApiClient';
import { User } from '@/model/User';

interface CreateBody {
username: string;
email: string;
password: string;
role?: string; // default roles: administrator, editor, author, subscriber (default)
firstName?: string;
lastName?: string;
}

export class UsersApi {
// eslint-disable-next-line no-useless-constructor
constructor( private readonly client: ApiClient ) {}

async create( body: CreateBody ): Promise< User > {
const actualBody: any = {
username: body.username,
email: body.email,
password: body.password,
};
if ( body.role ) {
actualBody.roles = [ body.role ];
}
if ( body.firstName ) {
actualBody.first_name = body.firstName;
}
if ( body.lastName ) {
actualBody.last_name = body.lastName;
}
const response = ( await this.client.post(
`/users`,
actualBody
) ) as ApiUser;
return makeUserFromApiResponse( response );
}
}

function makeUserFromApiResponse( response: ApiUser ): User {
return {
username: response.username ?? '',
email: response.email ?? '',
role: response.roles ? response.roles[ 0 ] : '',
firstName: response.first_name ?? '',
lastName: response.last_name ?? '',
};
}
36 changes: 36 additions & 0 deletions src/model/Post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export interface Post {
id: number;
guid: string;
url: string;
date: PostDate;
title: PostTitle;
content: PostContent;
}

abstract class PostSection< T > {
original: string;
parsed: string;
constructor( original: string, parsed: string ) {
this.original = original;
this.parsed = parsed;
}
abstract value(): T;
}

export class PostDate extends PostSection< Date > {
value(): Date {
return new Date( this.parsed );
}
}

export class PostTitle extends PostSection< string > {
value(): string {
return this.parsed;
}
}

export class PostContent extends PostSection< string > {
value(): string {
return this.parsed;
}
}
3 changes: 3 additions & 0 deletions src/model/SiteSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface SiteSettings {
title: string;
}
7 changes: 7 additions & 0 deletions src/model/User.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface User {
username: string;
email: string;
role: string;
firstName: string;
lastName: string;
}
Loading
Loading