Skip to content

Feat/backwards compatiable bubble url config #1043

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

Merged
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: 3 additions & 0 deletions apps/api/src/app/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export const APIMessages = {
ONBOARD_TEMPLATE_SHEET_NOT_FOUND: 'No sheets found in the workbook',
ONBOARD_TEMPLATE_FILE_EMPTY: 'File is empty or invalid',
ONBOARD_TEMPLATE_FILE_EMPTY_RECORDS: 'The file contains empty records',

INVALID_API_RESPONSE_STRUCTURE: `Invalid API response structure. Please recheck the URL and ensure the API is correctly configured to return data.`,
DATATYPE_EMPTY: `The datatype appears to be empty. Please add at least one entry and verify the URL points to the correct data source.`,
};

export const CONSTANTS = {
Expand Down
13 changes: 10 additions & 3 deletions apps/api/src/app/shared/services/bubble-io.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Injectable } from '@nestjs/common';
import { BubbleBaseService } from '@impler/services';
import { BubbleDestinationEntity } from '@impler/dal';
import { ColumnTypesEnum, DEFAULT_KEYS_OBJ, IColumn } from '@impler/shared';
import { APIMessages } from '@shared/constants';

interface IThingsResponse {
response: {
Expand All @@ -17,13 +18,19 @@ interface IThingsResponse {
export class BubbleIoService extends BubbleBaseService {
async getDatatypeData(data: Omit<BubbleDestinationEntity, '_id' | '_templateId'>) {
try {
const response = await axios.get<IThingsResponse>(data.bubbleAppUrl, {
const response = await axios.get<IThingsResponse>(this.createBubbleIoUrl(data.bubbleAppUrl), {
headers: {
Authorization: `Bearer ${data.apiPrivateKey}`,
},
});
if (!response.data.response.results.length)
throw new Error('Datatype is empty. Please add at least one entry to the datatype');

if (!Array.isArray(response.data.response.results)) {
throw new Error(APIMessages.INVALID_API_RESPONSE_STRUCTURE);
}

if (response.data.response.results.length === 0) {
throw new Error(APIMessages.DATATYPE_EMPTY);
}

return response.data.response.results;
} catch (error: unknown) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
*This migrartion is for the having only the bubbleAppUrl or streamlined using this send the bubble data to the specified destionation, the
*bubbleAppUrl contains everything the version the datatype and other things, if these fields are not there we construct using the existing data
*/
import '../../config';
import { AppModule } from '../../app.module';

import { NestFactory } from '@nestjs/core';
import { BubbleDestinationRepository } from '@impler/dal';

export async function run() {
const bubbleDestinationRepository: BubbleDestinationRepository = new BubbleDestinationRepository();

// eslint-disable-next-line no-console
console.log('start migration - Constructing, Generating and Updating the bubbleAppUrl');

// Init the mongodb connection
const app = await NestFactory.create(AppModule, {
logger: false,
});

const constructBubbleUrl = async (bubbleDestination: any | undefined | null) => {
const bubbleAppUrl = [{ _id: '', bubbleAppUrl: '' }];
bubbleDestination.forEach((destination) => {
/*
* If no direct URL, try to construct it from available fields
* Type assertion to access potential additional properties
*/
const customDomainName = destination.customDomainName as string | undefined;
const appName = destination.appName as string | undefined;
const environment = destination.environment as string | undefined;
const datatype = destination.datatype as string | undefined;

if (customDomainName || appName) {
// Use custom domain if available, otherwise use app name with bubbleapps.io
let baseUrl = customDomainName ? `https://${customDomainName}` : `https://${appName}.bubbleapps.io`;

// Add version-test for development environment if specified
if (environment === 'development') {
baseUrl += '/version-test';
}

// Construct the full URL with the data type if available
if (datatype) {
bubbleAppUrl.push({ _id: destination._id, bubbleAppUrl: `${baseUrl}/api/1.1/obj/${datatype}` });
}
}
});

return bubbleAppUrl;
};

const bubbleDestinationLink = await bubbleDestinationRepository.find({
bubbleAppUrl: { $exists: true, $ne: null },
});

const bubbleDestinations = await bubbleDestinationRepository.find({});
const bubbleAppUrls = await constructBubbleUrl(bubbleDestinations);
bubbleDestinationLink.map((link) => {
bubbleAppUrls.push({ _id: link._id, bubbleAppUrl: link.bubbleAppUrl });
});

bubbleAppUrls.map(async (url) => {
if (!url._id || !url.bubbleAppUrl) return;

try {
await bubbleDestinationRepository.update({ _id: url._id }, { $set: { bubbleAppUrl: url.bubbleAppUrl } });
} catch (error) {
return null;
}
});

// eslint-disable-next-line no-console
console.log('end migration - Constructed, Generated and Updated the bubbleAppUrl');

app.close();
process.exit(0);
}
run();
17 changes: 12 additions & 5 deletions apps/queue-manager/src/consumers/send-bubble-data.consumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class SendBubbleDataConsumer extends BaseConsumer {
const uploadId = data.uploadId;
const cachedData = data.cache || (await this.getInitialCachedData(uploadId));

if (cachedData && cachedData.bubbleUrl) {
if (cachedData && cachedData.bubbleAppUrl) {
// Get valid data information
let allDataJson: null | any[] = null;
if (cachedData.allDataFilePath) {
Expand All @@ -67,7 +67,7 @@ export class SendBubbleDataConsumer extends BaseConsumer {
uploadId,
page,
method: 'POST',
url: cachedData.bubbleUrl,
url: cachedData.bubbleAppUrl,
headers: {
Authorization: `Bearer ${cachedData.apiPrivateKey}`,
'Content-Type': 'text/plain',
Expand All @@ -76,7 +76,7 @@ export class SendBubbleDataConsumer extends BaseConsumer {

await this.makeResponseEntry(
response,
{ bubbleAppUrl: cachedData.bubbleUrl, datatype: cachedData.datatype },
{ bubbleAppUrl: cachedData.bubbleAppUrl, datatype: cachedData.datatype },
cachedData.name,
cachedData.email
);
Expand Down Expand Up @@ -142,7 +142,14 @@ export class SendBubbleDataConsumer extends BaseConsumer {
const templateData = await this.templateRepository.findById(uploadata._templateId, 'name');

const bubbleDestination = await this.bubbleDestinationRepository.findOne({ _templateId: uploadata._templateId });
const bubbleUrl = bubbleDestination.bubbleAppUrl;
if (!bubbleDestination) return null;

const bubbleAppUrl = bubbleDestination.bubbleAppUrl;

// If still no URL, return null as we can't proceed without a valid URL
if (!bubbleAppUrl) {
return null;
}

const defaultValueObj = {};
const customSchema = JSON.parse(uploadata.customSchema) as ITemplateSchemaItem;
Expand All @@ -163,7 +170,7 @@ export class SendBubbleDataConsumer extends BaseConsumer {

return {
page: 1,
bubbleUrl,
bubbleAppUrl,
chunkSize: 500,
email: userEmail,
datatype: bubbleDestination.datatype,
Expand Down
8 changes: 7 additions & 1 deletion apps/web/components/imports/destination/Destination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,13 @@ export function Destination({ template }: DestinationProps) {
<Input
required
label="Bubble App URL"
placeholder="Bubble App URL"
placeholder="https://acme.in/api/1.1/obj/customers"
description={
<>
<div>Example with default domain: https://your-app.bubbleapps.io/api/1.1/obj/your-datatype</div>
<div>Example with custom domain: https://yourapp.com/api/1.1/obj/your-datatype</div>
</>
}
{...register('bubbleIo.bubbleAppUrl')}
error={errors?.bubbleIo?.bubbleAppUrl?.message}
/>
Expand Down
2 changes: 1 addition & 1 deletion apps/widget/src/hooks/Phase3/usePhase3.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ export function usePhase3({ onNext }: IUsePhase3Props) {
setTotalPages(reviewDataResponse.totalPages);
},
onError(error: IErrorObject) {
notifier.showError({ message: 'Hellow World', title: error.error });
notifier.showError({ message: error.message, title: error.error });
},
}
);
Expand Down
2 changes: 1 addition & 1 deletion libs/shared/src/types/upload/upload.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export type SendBubbleCachedData = {
email: string;
datatype: string;
chunkSize: number;
bubbleUrl: string;
bubbleAppUrl: string;
apiPrivateKey: string;
_templateId: string;
recordFormat: string;
Expand Down
Loading