Skip to content

Commit

Permalink
feat: delete crashes (#131)
Browse files Browse the repository at this point in the history
* feat: delete crashes

* fix: post notes
  • Loading branch information
bobbyg603 authored Oct 16, 2024
1 parent 732d5e9 commit 8c72123
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 58 deletions.
51 changes: 36 additions & 15 deletions src/common/data/table-data/table-data-client/table-data-client.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import { ApiClient, TableDataRequest, BugSplatResponse, TableDataResponse } from '@common';
import {
ApiClient,
TableDataRequest,
BugSplatResponse,
TableDataResponse,
} from '@common';
import { TableDataFormDataBuilder } from '../table-data-form-data-builder/table-data-form-data-builder';

export class TableDataClient {

constructor(private _apiClient: ApiClient, private _url: string) { }
constructor(private _apiClient: ApiClient, private _url: string) {}

// We use POST to get data in most cases because it supports longer queries
async postGetData<T, U = (Record<string, unknown> | undefined)>(request: TableDataRequest, formParts: Record<string, string> = {}): Promise<BugSplatResponse<TableDataResponse<T, U>>> {
async postGetData<T, U = Record<string, unknown> | undefined>(
request: TableDataRequest,
formParts: Record<string, string> = {}
): Promise<BugSplatResponse<TableDataResponse<T, U>>> {
const factory = () => this._apiClient.createFormData();
const formData = new TableDataFormDataBuilder(factory, formParts)
.withDatabase(request.database)
Expand All @@ -23,12 +30,14 @@ export class TableDataClient {
cache: 'no-cache',
credentials: 'include',
redirect: 'follow',
duplex: 'half'
duplex: 'half',
} as RequestInit;
return this.makeRequest<T, U>(this._url, requestInit);
}

async getData<T, U = (Record<string, unknown> | undefined)>(request: TableDataRequest): Promise<BugSplatResponse<TableDataResponse<T, U>>> {
async getData<T, U = Record<string, unknown> | undefined>(
request: TableDataRequest
): Promise<BugSplatResponse<TableDataResponse<T, U>>> {
const factory = () => this._apiClient.createFormData();
const formData = new TableDataFormDataBuilder(factory)
.withDatabase(request.database)
Expand All @@ -43,17 +52,30 @@ export class TableDataClient {
method: 'GET',
cache: 'no-cache',
credentials: 'include',
redirect: 'follow'
redirect: 'follow',
} as RequestInit;
const queryParams = new URLSearchParams(formData).toString();
return this.makeRequest<T, U>(`${this._url}?${queryParams}`, requestInit);
}

private async makeRequest<T, U = unknown>(url: string, init: RequestInit): Promise<BugSplatResponse<TableDataResponse<T, U>>> {
const response = await this._apiClient.fetch<RawResponse<TableDataResponse<T,U>>>(url, init);
private async makeRequest<T, U = unknown>(
url: string,
init: RequestInit
): Promise<BugSplatResponse<TableDataResponse<T, U>>> {
const response = await this._apiClient.fetch<
RawResponse<TableDataResponse<T, U>> | TableDataResponse<T, U>
>(url, init);
const responseData = await response.json();
const rows = responseData ? responseData[0]?.Rows : [];
const pageData = responseData ? responseData[0]?.PageData : {};

// Handle legacy and new API responses until we can upgrade legacy APIs
const rows =
(responseData as TableDataResponse<T, U>)?.rows ??
responseData?.[0]?.Rows ??
[];
const pageData =
(responseData as TableDataResponse<T, U>)?.pageData ??
responseData?.[0]?.PageData ??
{};

const status = response.status;
const body = response.body;
Expand All @@ -64,13 +86,12 @@ export class TableDataClient {
status,
body,
json,
text
text,
};
}
}

// https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#key-remapping-via-as
export type RawResponse<T> = Array<{
[Property in keyof T as Capitalize<string & Property>]: T[Property]
}>

[Property in keyof T as Capitalize<string & Property>]: T[Property];
}>;
2 changes: 1 addition & 1 deletion src/crashes/crashes-api-client/crashes-api-client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ describe('CrashesApiClient', () => {
});

it('should call fetch with correct route', () => {
expect(apiClient.fetch).toHaveBeenCalledWith('/allcrash?data', jasmine.anything());
expect(apiClient.fetch).toHaveBeenCalledWith('/browse/allcrash.php', jasmine.anything());
});

it('should call fetch with requestInit containing formData', () => {
Expand Down
113 changes: 71 additions & 42 deletions src/crashes/crashes-api-client/crashes-api-client.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,76 @@
import { ApiClient, BugSplatResponse, TableDataClient, TableDataRequest, TableDataResponse } from '@common';
import {
ApiClient,
BugSplatResponse,
TableDataClient,
TableDataRequest,
TableDataResponse,
} from '@common';
import { CrashesApiRow, CrashesPageData } from '@crashes';
import { CrashesApiResponseRow } from '../crashes-api-row/crashes-api-row';

export class CrashesApiClient {
private _tableDataClient: TableDataClient;

private _tableDataClient: TableDataClient;

constructor(private _client: ApiClient) {
this._tableDataClient = new TableDataClient(this._client, '/allcrash?data');
}

async getCrashes(request: TableDataRequest): Promise<TableDataResponse<CrashesApiRow, CrashesPageData>> {
const response = await this._tableDataClient.postGetData<CrashesApiResponseRow, CrashesPageData>(request);
const json = await response.json();
const pageData = json.pageData;
const rows = json.rows.map(row => new CrashesApiRow(row));

return {
rows,
pageData
};
}

postNotes(
database: string,
id: number,
notes: string
): Promise<BugSplatResponse> {
const formData = this._client.createFormData();
formData.append('update', 'true');
formData.append('database', database);
formData.append('id', `${id}`);
formData.append('Comments', notes);

const request = {
method: 'POST',
body: formData,
cache: 'no-cache',
credentials: 'include',
redirect: 'follow',
duplex: 'half'
} as RequestInit;

return this._client.fetch('/allcrash?data', request);
}
}
constructor(private _client: ApiClient) {
this._tableDataClient = new TableDataClient(
this._client,
'/api/crashes.php'
);
}

async deleteCrashes(
database: string,
ids: number[]
): Promise<BugSplatResponse> {
const urlParams = new URLSearchParams({ database, ids: ids.join(',') });
const request = {
method: 'DELETE',
cache: 'no-cache',
credentials: 'include',
redirect: 'follow',
duplex: 'half',
} as RequestInit;
return this._client.fetch(`/api/crashes.php?${urlParams}`, request);
}

async getCrashes(
request: TableDataRequest
): Promise<TableDataResponse<CrashesApiRow, CrashesPageData>> {
const response = await this._tableDataClient.postGetData<
CrashesApiResponseRow,
CrashesPageData
>(request);
const json = await response.json();
const pageData = json.pageData;
const rows = json.rows.map((row) => new CrashesApiRow(row));

return {
rows,
pageData,
};
}

// TODO BG we should move this to an api/crash/notes endpoint and reture allcrash
postNotes(
database: string,
id: number,
notes: string
): Promise<BugSplatResponse> {
const formData = this._client.createFormData();
formData.append('update', 'true');
formData.append('database', database);
formData.append('id', `${id}`);
formData.append('Comments', notes);

const request = {
method: 'POST',
body: formData,
cache: 'no-cache',
credentials: 'include',
redirect: 'follow',
duplex: 'half',
} as RequestInit;

return this._client.fetch('/browse/allcrash.php', request);
}
}

0 comments on commit 8c72123

Please sign in to comment.