273 lines
7.3 KiB
TypeScript
273 lines
7.3 KiB
TypeScript
import * as plugins from './bunq.plugins.js';
|
|
import { BunqAccount } from './bunq.classes.account.js';
|
|
|
|
export class BunqAttachment {
|
|
private bunqAccount: BunqAccount;
|
|
|
|
public id?: number;
|
|
public created?: string;
|
|
public updated?: string;
|
|
public uuid?: string;
|
|
|
|
constructor(bunqAccount: BunqAccount) {
|
|
this.bunqAccount = bunqAccount;
|
|
}
|
|
|
|
/**
|
|
* Upload a file attachment
|
|
*/
|
|
public async upload(options: {
|
|
contentType: string;
|
|
description?: string;
|
|
body: Buffer | string;
|
|
}): Promise<string> {
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
// First, create the attachment placeholder
|
|
const attachmentResponse = await this.bunqAccount.getHttpClient().post(
|
|
'/v1/attachment-public',
|
|
{
|
|
description: options.description
|
|
}
|
|
);
|
|
|
|
if (!attachmentResponse.Response || !attachmentResponse.Response[0]) {
|
|
throw new Error('Failed to create attachment');
|
|
}
|
|
|
|
const attachmentUuid = attachmentResponse.Response[0].Uuid.uuid;
|
|
this.uuid = attachmentUuid;
|
|
|
|
// Upload the actual content
|
|
const uploadUrl = `/v1/attachment-public/${attachmentUuid}/content`;
|
|
|
|
// For file uploads, we need to make a raw request
|
|
const headers = {
|
|
'Content-Type': options.contentType,
|
|
'X-Bunq-Client-Authentication': this.bunqAccount.apiContext.getSession().getContext().sessionToken
|
|
};
|
|
|
|
const response = await fetch(
|
|
`${this.bunqAccount.apiContext.getBaseUrl()}${uploadUrl}`,
|
|
{
|
|
method: 'PUT',
|
|
headers: headers,
|
|
body: options.body
|
|
}
|
|
);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to upload attachment: HTTP ${response.status}`);
|
|
}
|
|
|
|
return attachmentUuid;
|
|
}
|
|
|
|
/**
|
|
* Get attachment content
|
|
*/
|
|
public async getContent(attachmentUuid: string): Promise<Buffer> {
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
const response = await fetch(
|
|
`${this.bunqAccount.apiContext.getBaseUrl()}/v1/attachment-public/${attachmentUuid}/content`,
|
|
{
|
|
method: 'GET',
|
|
headers: {
|
|
'X-Bunq-Client-Authentication': this.bunqAccount.apiContext.getSession().getContext().sessionToken
|
|
}
|
|
}
|
|
);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to get attachment: HTTP ${response.status}`);
|
|
}
|
|
|
|
const arrayBuffer = await response.arrayBuffer();
|
|
return Buffer.from(arrayBuffer);
|
|
}
|
|
|
|
/**
|
|
* Create attachment for a specific monetary account
|
|
*/
|
|
public async createForAccount(
|
|
monetaryAccountId: number,
|
|
attachmentPublicUuid: string
|
|
): Promise<number> {
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
const response = await this.bunqAccount.getHttpClient().post(
|
|
`/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccountId}/attachment`,
|
|
{
|
|
attachment_public_uuid: attachmentPublicUuid
|
|
}
|
|
);
|
|
|
|
if (response.Response && response.Response[0] && response.Response[0].Id) {
|
|
this.id = response.Response[0].Id.id;
|
|
return this.id;
|
|
}
|
|
|
|
throw new Error('Failed to create account attachment');
|
|
}
|
|
|
|
/**
|
|
* List attachments for a monetary account
|
|
*/
|
|
public static async listForAccount(
|
|
bunqAccount: BunqAccount,
|
|
monetaryAccountId: number
|
|
): Promise<any[]> {
|
|
await bunqAccount.apiContext.ensureValidSession();
|
|
|
|
const response = await bunqAccount.getHttpClient().list(
|
|
`/v1/user/${bunqAccount.userId}/monetary-account/${monetaryAccountId}/attachment`
|
|
);
|
|
|
|
return response.Response || [];
|
|
}
|
|
|
|
/**
|
|
* Create attachment for a payment
|
|
*/
|
|
public async createForPayment(
|
|
monetaryAccountId: number,
|
|
paymentId: number,
|
|
attachmentId: number
|
|
): Promise<void> {
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
await this.bunqAccount.getHttpClient().post(
|
|
`/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccountId}/payment/${paymentId}/attachment`,
|
|
{
|
|
id: attachmentId
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Upload image as avatar
|
|
*/
|
|
public async uploadAvatar(imageBuffer: Buffer, contentType: string = 'image/png'): Promise<string> {
|
|
return this.upload({
|
|
contentType,
|
|
description: 'Avatar image',
|
|
body: imageBuffer
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Upload document
|
|
*/
|
|
public async uploadDocument(
|
|
documentBuffer: Buffer,
|
|
contentType: string,
|
|
description: string
|
|
): Promise<string> {
|
|
return this.upload({
|
|
contentType,
|
|
description,
|
|
body: documentBuffer
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Helper to upload file from filesystem
|
|
*/
|
|
public async uploadFile(filePath: string, description?: string): Promise<string> {
|
|
const fileBuffer = await plugins.smartfile.fs.toBuffer(filePath);
|
|
const contentType = this.getContentType(filePath);
|
|
|
|
return this.upload({
|
|
contentType,
|
|
description: description || plugins.path.basename(filePath),
|
|
body: fileBuffer
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get content type from file extension
|
|
*/
|
|
private getContentType(filePath: string): string {
|
|
const ext = plugins.path.extname(filePath).toLowerCase();
|
|
|
|
const contentTypes: { [key: string]: string } = {
|
|
'.jpg': 'image/jpeg',
|
|
'.jpeg': 'image/jpeg',
|
|
'.png': 'image/png',
|
|
'.gif': 'image/gif',
|
|
'.pdf': 'application/pdf',
|
|
'.txt': 'text/plain',
|
|
'.csv': 'text/csv',
|
|
'.xml': 'application/xml',
|
|
'.json': 'application/json'
|
|
};
|
|
|
|
return contentTypes[ext] || 'application/octet-stream';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Tab attachment class for managing receipt attachments
|
|
*/
|
|
export class BunqTabAttachment {
|
|
private bunqAccount: BunqAccount;
|
|
private monetaryAccountId: number;
|
|
private tabUuid: string;
|
|
|
|
constructor(bunqAccount: BunqAccount, monetaryAccountId: number, tabUuid: string) {
|
|
this.bunqAccount = bunqAccount;
|
|
this.monetaryAccountId = monetaryAccountId;
|
|
this.tabUuid = tabUuid;
|
|
}
|
|
|
|
/**
|
|
* Upload attachment for a tab
|
|
*/
|
|
public async upload(attachmentPublicUuid: string): Promise<number> {
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
const response = await this.bunqAccount.getHttpClient().post(
|
|
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccountId}/tab/${this.tabUuid}/attachment`,
|
|
{
|
|
attachment_public_uuid: attachmentPublicUuid
|
|
}
|
|
);
|
|
|
|
if (response.Response && response.Response[0] && response.Response[0].Id) {
|
|
return response.Response[0].Id.id;
|
|
}
|
|
|
|
throw new Error('Failed to create tab attachment');
|
|
}
|
|
|
|
/**
|
|
* List attachments for a tab
|
|
*/
|
|
public async list(): Promise<any[]> {
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
const response = await this.bunqAccount.getHttpClient().list(
|
|
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccountId}/tab/${this.tabUuid}/attachment`
|
|
);
|
|
|
|
return response.Response || [];
|
|
}
|
|
|
|
/**
|
|
* Get specific attachment
|
|
*/
|
|
public async get(attachmentId: number): Promise<any> {
|
|
await this.bunqAccount.apiContext.ensureValidSession();
|
|
|
|
const response = await this.bunqAccount.getHttpClient().get(
|
|
`/v1/user/${this.bunqAccount.userId}/monetary-account/${this.monetaryAccountId}/tab/${this.tabUuid}/attachment/${attachmentId}`
|
|
);
|
|
|
|
if (response.Response && response.Response[0]) {
|
|
return response.Response[0].TabAttachment;
|
|
}
|
|
|
|
throw new Error('Tab attachment not found');
|
|
}
|
|
} |