Skip to content

Commit

Permalink
Add drive object to onedrive integration
Browse files Browse the repository at this point in the history
  • Loading branch information
amuwal committed Sep 9, 2024
1 parent ccd4c8e commit 7102605
Show file tree
Hide file tree
Showing 12 changed files with 476 additions and 61 deletions.
40 changes: 28 additions & 12 deletions packages/api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -1965,18 +1965,19 @@ model linked_users {

/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments
model projects {
id_project String @id(map: "pk_projects") @db.Uuid
name String
sync_mode String
pull_frequency BigInt?
redirect_url String?
id_user String @db.Uuid
id_connector_set String @db.Uuid
api_keys api_keys[]
connections connections[]
linked_users linked_users[]
users users @relation(fields: [id_user], references: [id_user], onDelete: NoAction, onUpdate: NoAction, map: "fk_46_1")
connector_sets connector_sets @relation(fields: [id_connector_set], references: [id_connector_set], onDelete: NoAction, onUpdate: NoAction, map: "fk_project_connectorsetid")
id_project String @id(map: "pk_projects") @db.Uuid
name String
sync_mode String
pull_frequency BigInt?
redirect_url String?
id_user String @db.Uuid
id_connector_set String @db.Uuid
api_keys api_keys[]
connections connections[]
linked_users linked_users[]
users users @relation(fields: [id_user], references: [id_user], onDelete: NoAction, onUpdate: NoAction, map: "fk_46_1")
connector_sets connector_sets @relation(fields: [id_connector_set], references: [id_connector_set], onDelete: NoAction, onUpdate: NoAction, map: "fk_project_connectorsetid")
projects_pull_frequency projects_pull_frequency?
@@index([id_connector_set], map: "fk_connectors_sets")
}
Expand Down Expand Up @@ -2128,3 +2129,18 @@ model webhook_delivery_attempts {
@@index([id_event], map: "fk_webhook_delivery_attempt_eventid")
@@index([id_webhooks_reponse], map: "fk_webhook_delivery_attempt_webhook_responseid")
}

model projects_pull_frequency {
id_projects_pull_frequency String @id(map: "pk_projects_pull_frequency") @db.Uuid
crm BigInt?
ats BigInt?
hris BigInt?
accounting BigInt?
filestorage BigInt?
ecommerce BigInt?
ticketing BigInt?
created_at DateTime @default(now()) @db.Timestamptz(6)
modified_at DateTime @default(now()) @db.Timestamptz(6)
id_project String @unique(map: "uq_projects_pull_frequency_project") @db.Uuid
projects projects @relation(fields: [id_project], references: [id_project], onDelete: NoAction, onUpdate: NoAction, map: "fk_projects_pull_frequency_project")
}
37 changes: 22 additions & 15 deletions packages/api/scripts/connectorUpdate.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,10 @@ function updateModuleFileForMapper(moduleFile, newServiceDirs, objectType) {
// Generate and insert new service imports
newServiceDirs.forEach((serviceName) => {
const mapperClass =
serviceName.charAt(0).toUpperCase() + serviceName.slice(1) + objectType + 'Mapper';
serviceName.charAt(0).toUpperCase() +
serviceName.slice(1) +
objectType +
'Mapper';
const importStatement = `import { ${mapperClass} } from './services/${serviceName}/mappers';\n`;
if (!moduleFileContent.includes(importStatement)) {
moduleFileContent = importStatement + moduleFileContent;
Expand Down Expand Up @@ -404,17 +407,20 @@ function updateSeedSQLFile(seedSQLFile, newServiceDirs, vertical) {
fileContent = fileContent.replace(lastMatch[1], newColumnsSection);

// Update each VALUES section
fileContent = fileContent.replace(/INSERT INTO connector_sets \(([^)]+)\) VALUES(.*?);/gs, (match) => {
return match
.replace(/\),\s*\(/g, '),\n (') // Fix line formatting
.replace(/\([^\)]+\)/g, (values, index) => {
if (values.startsWith('(id_connector_set')) {
return values
}
let newValues = newColumns.map(() => 'TRUE').join(', ');
return values.slice(0, -1) + ', ' + newValues + ')';
});
});
fileContent = fileContent.replace(
/INSERT INTO connector_sets \(([^)]+)\) VALUES(.*?);/gs,
(match) => {
return match
.replace(/\),\s*\(/g, '),\n (') // Fix line formatting
.replace(/\([^\)]+\)/g, (values, index) => {
if (values.startsWith('(id_connector_set')) {
return values;
}
let newValues = newColumns.map(() => 'TRUE').join(', ');
return values.slice(0, -1) + ', ' + newValues + ')';
});
},
);
}
// Write the modified content back to the file
console.log(fileContent);
Expand All @@ -427,9 +433,10 @@ function updateSeedSQLFile(seedSQLFile, newServiceDirs, vertical) {
function updateObjectTypes(baseDir, objectType, vertical) {
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const servicesDir = path.join(__dirname, baseDir);
const targetFilename = vertical == 'filestorage' ? 'file-storage' : vertical;
const targetFile = path.join(
__dirname,
`../src/@core/utils/types/original/original.${vertical}.ts`,
`../src/@core/utils/types/original/original.${targetFilename}.ts`,
);

const newServiceDirs = scanDirectory(servicesDir);
Expand Down Expand Up @@ -468,7 +475,7 @@ function updateObjectTypes(baseDir, objectType, vertical) {
);

updateModuleFileForService(moduleFile, newServiceDirs);
updateModuleFileForMapper(moduleFile, newServiceDirs, objectType)
updateModuleFileForMapper(moduleFile, newServiceDirs, objectType);

// Path to the mappings file
// const mappingsFile = path.join(
Expand Down Expand Up @@ -522,4 +529,4 @@ if (import.meta.url === process.argv[1]) {

const argv = yargs(hideBin(process.argv)).argv;
const baseDir = `../src/${argv.vertical.toLowerCase()}/${argv.objectType.toLowerCase()}/services`;
updateObjectTypes(baseDir, argv.objectType, argv.vertical);
updateObjectTypes(baseDir, argv.objectType, argv.vertical);
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ export class SharepointConnectionService extends AbstractBaseConnectionService {
grant_type: 'authorization_code',
});
const res = await axios.post(
`https://app.sharepoint.com/oauth2/tokens`,
// `https://app.sharepoint.com/oauth2/tokens`,
`https://login.microsoftonline.com/common/oauth2/v2.0/token`,
formData.toString(),
{
headers: {
Expand Down Expand Up @@ -214,7 +215,8 @@ export class SharepointConnectionService extends AbstractBaseConnectionService {
)) as OAuth2AuthData;

const res = await axios.post(
`https://app.sharepoint.com/oauth2/tokens`,
// `https://app.sharepoint.com/oauth2/tokens`,
`https://login.microsoftonline.com/common/oauth2/v2.0/token`,
formData.toString(),
{
headers: {
Expand Down
1 change: 1 addition & 0 deletions packages/api/src/@core/sync/sync.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ export class CoreSyncService {
try {
await task();
} catch (error) {
console.log(error);
this.logger.error(`File Storage Task failed: ${error.message}`, error);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { SharepointDriveInput, SharepointDriveOutput } from '@filestorage/drive/services/sharepoint/types';

/* INPUT */

import {
Expand Down Expand Up @@ -30,7 +32,7 @@ export type OriginalPermissionInput = any;
export type OriginalSharedLinkInput = any;

/* drive */
export type OriginalDriveInput = any;
export type OriginalDriveInput = any | SharepointDriveInput;

/* group */
export type OriginalGroupInput = BoxGroupInput;
Expand Down Expand Up @@ -62,7 +64,7 @@ export type OriginalPermissionOutput = any;
export type OriginalSharedLinkOutput = any;

/* drive */
export type OriginalDriveOutput = any;
export type OriginalDriveOutput = any | SharepointDriveOutput;

/* group */
export type OriginalGroupOutput = BoxGroupOutput;
Expand Down
4 changes: 4 additions & 0 deletions packages/api/src/filestorage/drive/drive.module.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { SharepointDriveMapper } from './services/sharepoint/mappers';
import { SharepointService } from './services/sharepoint';
import { BullQueueModule } from '@@core/@core-services/queues/queue.module';
import { WebhookService } from '@@core/@core-services/webhooks/panora-webhooks/webhook.service';
import { Module } from '@nestjs/common';
Expand All @@ -17,6 +19,8 @@ import { Utils } from '@filestorage/@lib/@utils';
ServiceRegistry,
Utils,
/* PROVIDERS SERVICES */
SharepointService,
SharepointDriveMapper,
],
exports: [SyncService],
})
Expand Down
71 changes: 71 additions & 0 deletions packages/api/src/filestorage/drive/services/sharepoint/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { EncryptionService } from '@@core/@core-services/encryption/encryption.service';
import { LoggerService } from '@@core/@core-services/logger/logger.service';
import { PrismaService } from '@@core/@core-services/prisma/prisma.service';
import { ApiResponse } from '@@core/utils/types';
import { SyncParam } from '@@core/utils/types/interface';
import { FileStorageObject } from '@filestorage/@lib/@types';
import { IDriveService } from '@filestorage/drive/types';
import { Injectable } from '@nestjs/common';
import axios from 'axios';
import { ServiceRegistry } from '../registry.service';
import { SharepointDriveOutput } from './types';
import { DesunifyReturnType } from '@@core/utils/types/desunify.input';
import { OriginalDriveOutput } from '@@core/utils/types/original/original.file-storage';

@Injectable()
export class SharepointService implements IDriveService {
constructor(
private prisma: PrismaService,
private logger: LoggerService,
private cryptoService: EncryptionService,
private registry: ServiceRegistry,
) {
this.logger.setContext(
`${FileStorageObject.file.toUpperCase()}:${SharepointService.name}`,
);
this.registry.registerService('sharepoint', this);
}

async addDrive(
driveData: DesunifyReturnType,
linkedUserId: string,
): Promise<ApiResponse<OriginalDriveOutput>> {
// No API to add drive in Sharepoint
return;
}

async sync(data: SyncParam): Promise<ApiResponse<SharepointDriveOutput[]>> {
try {
const { linkedUserId } = data;

const connection = await this.prisma.connections.findFirst({
where: {
id_linked_user: linkedUserId,
provider_slug: 'sharepoint',
vertical: 'filestorage',
},
});

const resp = await axios.get(`${connection.account_url}/drives`, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.cryptoService.decrypt(
connection.access_token,
)}`,
},
});

const drives: SharepointDriveOutput[] = resp.data.value;
this.logger.log(`Synced sharepoint drives !`);

return {
data: drives,
message: 'Sharepoint drives retrived',
statusCode: 200,
};
} catch (error) {
console.log(error.response);
throw error;
}
}
}
86 changes: 86 additions & 0 deletions packages/api/src/filestorage/drive/services/sharepoint/mappers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { MappersRegistry } from '@@core/@core-services/registries/mappers.registry';
import { CoreUnification } from '@@core/@core-services/unification/core-unification.service';
import { Utils } from '@filestorage/@lib/@utils';
import {
UnifiedFilestorageDriveInput,
UnifiedFilestorageDriveOutput,
} from '@filestorage/drive/types/model.unified';
import { Injectable } from '@nestjs/common';
import { SharepointDriveInput, SharepointDriveOutput } from './types';
import { IDriveMapper } from '@filestorage/drive/types';

@Injectable()
export class SharepointDriveMapper implements IDriveMapper {
constructor(
private mappersRegistry: MappersRegistry,
private utils: Utils,
private coreUnificationService: CoreUnification,
) {
this.mappersRegistry.registerService(
'filestorage',
'drive',
'sharepoint',
this,
);
}

async desunify(
source: UnifiedFilestorageDriveInput,
customFieldMappings?: {
slug: string;
remote_id: string;
}[],
): Promise<SharepointDriveInput> {
return;
}

async unify(
source: SharepointDriveOutput | SharepointDriveOutput[],
connectionId: string,
customFieldMappings?: {
slug: string;
remote_id: string;
}[],
): Promise<UnifiedFilestorageDriveOutput | UnifiedFilestorageDriveOutput[]> {
if (!Array.isArray(source)) {
return await this.mapSingleDriveToUnified(
source,
connectionId,
customFieldMappings,
);
}
// Handling array of SharepointDriveOutput
return Promise.all(
source.map((drive) =>
this.mapSingleDriveToUnified(drive, connectionId, customFieldMappings),
),
);
}

private async mapSingleDriveToUnified(
drive: SharepointDriveOutput,
connectionId: string,
customFieldMappings?: {
slug: string;
remote_id: string;
}[],
): Promise<UnifiedFilestorageDriveOutput> {
const field_mappings: { [key: string]: any } = {};
if (customFieldMappings) {
for (const mapping of customFieldMappings) {
field_mappings[mapping.slug] = drive[mapping.remote_id];
}
}

const result: UnifiedFilestorageDriveOutput = {
remote_id: drive.id,
remote_data: drive,
name: drive.name,
remote_created_at: drive.createdDateTime,
drive_url: drive.webUrl,
field_mappings,
};

return result;
}
}
Loading

0 comments on commit 7102605

Please sign in to comment.