diff --git a/.nycrc b/.nycrc index 80f4ea0..8db21fb 100644 --- a/.nycrc +++ b/.nycrc @@ -1,6 +1,10 @@ { "extends": "@istanbuljs/nyc-config-typescript", "check-coverage": true, + "branches": 80, + "lines": 80, + "functions": 80, + "statements": 80, "all": true, "include": ["src/**/*.ts"], "exclude": ["src/index.ts", "**/*.spec.ts"], diff --git a/package-lock.json b/package-lock.json index 21cd4fb..1c880f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "axios": "^1.2.4" + "axios": "^1.2.4", + "form-data": "^4.0.0" }, "devDependencies": { "@istanbuljs/nyc-config-typescript": "^1.0.2", diff --git a/package.json b/package.json index 37d4bbe..11039c6 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "typescript": "^4.9.5" }, "dependencies": { - "axios": "^1.2.4" + "axios": "^1.2.4", + "form-data": "^4.0.0" } } diff --git a/src/models/ApiResponse.ts b/src/models/ApiResponse.ts index a21d6e0..655f3c1 100644 --- a/src/models/ApiResponse.ts +++ b/src/models/ApiResponse.ts @@ -1,5 +1,6 @@ import { App } from './App'; import { CollectionResponse } from './CollectionResponse'; +import { CreatedWithIdResponse } from './CreatedWithIdResponse'; import { Field } from './Field'; import { GetPagedAppsResponse } from './GetPagedAppsResponse'; import { GetPagedFieldsResponse } from './GetPagedFieldsResponse'; @@ -199,4 +200,18 @@ export class ApiResponse { getPagedFieldsResponse ); } + + public AsCreatedWithIdResponseType(): ApiResponse { + const apiResponse = this as ApiResponse; + + const createdWithIdResponse = new CreatedWithIdResponse( + apiResponse.data.id + ); + + return new ApiResponse( + apiResponse.statusCode, + apiResponse.message, + createdWithIdResponse + ); + } } diff --git a/src/models/CreatedWithIdResponse.ts b/src/models/CreatedWithIdResponse.ts new file mode 100644 index 0000000..3dbd2c4 --- /dev/null +++ b/src/models/CreatedWithIdResponse.ts @@ -0,0 +1,15 @@ +export class CreatedWithIdResponse { + /** + * @property {number} id - The id of the created object. + */ + public id: number; + + /** + * @constructor - Creates a new instance of the CreatedWithIdResponse class. + * @param id - The id of the created object. + * @returns {CreatedWithIdResponse} - A new instance of the CreatedWithIdResponse class. + */ + constructor(id: number) { + this.id = id; + } +} diff --git a/src/models/OnspringClient.ts b/src/models/OnspringClient.ts index 40cf193..923d25a 100644 --- a/src/models/OnspringClient.ts +++ b/src/models/OnspringClient.ts @@ -10,6 +10,8 @@ import { type App } from './App'; import { type CollectionResponse } from './CollectionResponse'; import { type Field } from './Field'; import { type GetPagedFieldsResponse } from './GetPagedFieldsResponse'; +import { type SaveFileRequest } from './SaveFileRequest'; +import { type CreatedWithIdResponse } from './CreatedWithIdResponse'; /** * @class OnspringClient - A client that can communicate with the Onspring API. @@ -169,6 +171,27 @@ export class OnspringClient { return apiResponse.AsGetPagedFieldsResponseType(); } + /** + * @method saveFile - Saves a file to a record in Onspring. + * @param {SaveFileRequest} request - The request that will be used to save the file. + * @returns {Promise>} - A promise that resolves to an ApiResponse of type CreatedWithIdResponse. + */ + public async saveFile( + request: SaveFileRequest + ): Promise> { + const endpoint = EndpointFactory.getSaveFileEndpoint(); + const formData = request.AsFormData(); + const apiResponse = await this.post(endpoint, formData, { + headers: formData.getHeaders(), + }); + + if (apiResponse.isSuccessful === false) { + return apiResponse; + } + + return apiResponse.AsCreatedWithIdResponseType(); + } + /** * @method get - Makes a GET request to the specified endpoint. * @param {string} endpoint - The endpoint that will be used to make the request. diff --git a/src/models/SaveFileRequest.ts b/src/models/SaveFileRequest.ts new file mode 100644 index 0000000..f1978d4 --- /dev/null +++ b/src/models/SaveFileRequest.ts @@ -0,0 +1,86 @@ +import FormData = require('form-data'); + +/** + * @class SaveFileRequest - Represents a request to save a file. + */ +export class SaveFileRequest { + /** + * @property {number} recordId - The id of the record that the file will be saved to. + */ + public recordId: number; + + /** + * @property {number} fieldId - The id of the field that the file will be saved to. + */ + public fieldId: number; + + /** + * @property {string} notes - The notes for the file. + */ + public notes: string; + + /** + * @property {Date} modifiedDate - The modified date for the file. + */ + public modifiedDate: Date; + + /** + * @property {string} fileName - The name of the file. + */ + public fileName: string; + + /** + * @property {string} contentType - The content type of the file. + */ + public contentType: string; + + /** + * @property {ReadableStream} fileStream - The file stream. + */ + public fileStream: ReadableStream; + + /** + * @constructor - Creates a new SaveFileRequest. + * @param {number} recordId - The id of the record that the file will be saved to. + * @param {number} fieldId - The id of the field that the file will be saved to. + * @param {string} notes - The notes for the file. + * @param {Date} modifiedDate - The modified date for the file. + * @param {string} fileName - The name of the file. + * @param {string} contentType - The content type of the file. + * @param {ReadableStream} fileStream - The file stream. + * @returns {SaveFileRequest} - A new SaveFileRequest. + */ + constructor( + recordId: number, + fieldId: number, + notes: string, + modifiedDate: Date, + fileName: string, + contentType: string, + fileStream: ReadableStream + ) { + this.recordId = recordId; + this.fieldId = fieldId; + this.notes = notes; + this.modifiedDate = modifiedDate; + this.fileName = fileName; + this.contentType = contentType; + this.fileStream = fileStream; + } + + /** + * @method AsFormData - Converts the SaveFileRequest to a FormData object. + * @returns {FormData} - The SaveFileRequest as a FormData object. + */ + public AsFormData(): FormData { + const formData = new FormData(); + formData.append('recordId', this.recordId.toString()); + formData.append('fieldId', this.fieldId.toString()); + formData.append('notes', this.notes); + formData.append('modifiedDate', this.modifiedDate.toUTCString()); + formData.append('fileName', this.fileName); + formData.append('contentType', this.contentType); + formData.append('file', this.fileStream, this.fileName); + return formData; + } +}