From 1632ad6d2d68c8b497bd6ec904cf90b1afe985de Mon Sep 17 00:00:00 2001 From: mit-27 Date: Sun, 5 May 2024 03:28:31 -0400 Subject: [PATCH 01/14] =?UTF-8?q?=F0=9F=90=9B=20Fix=20gitlab=20connection?= =?UTF-8?q?=20and=20add=20Collection=20object?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../services/gitlab/gitlab.service.ts | 5 +- .../types/original/original.ticketing.ts | 15 +- .../ticketing/collection/collection.module.ts | 2 + .../collection/services/collection.service.ts | 1 + .../collection/services/gitlab/index.ts | 117 +++++++ .../collection/services/gitlab/mappers.ts | 56 +++ .../collection/services/gitlab/types.ts | 138 ++++++++ .../collection/services/jira/index.ts | 12 +- .../ticketing/collection/sync/sync.service.ts | 5 +- .../src/ticketing/collection/types/index.ts | 7 +- .../collection/types/mappingsTypes.ts | 8 +- packages/api/swagger/swagger-spec.json | 89 ++--- packages/shared/src/authUrl.ts | 10 +- packages/shared/src/enum.ts | 1 + packages/shared/src/providers.ts | 2 +- packages/shared/src/utils.ts | 324 +++++++++--------- 16 files changed, 553 insertions(+), 239 deletions(-) create mode 100644 packages/api/src/ticketing/collection/services/gitlab/index.ts create mode 100644 packages/api/src/ticketing/collection/services/gitlab/mappers.ts create mode 100644 packages/api/src/ticketing/collection/services/gitlab/types.ts diff --git a/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts b/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts index d9794346f..9930bb6ee 100644 --- a/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts +++ b/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts @@ -12,7 +12,7 @@ import { ITicketingConnectionService, } from '../../types'; import { ServiceRegistry } from '../registry.service'; -import { AuthStrategy } from '@panora/shared'; +import { AuthStrategy, providersConfig } from '@panora/shared'; import { OAuth2AuthData, providerToType } from '@panora/shared'; import { ConnectionsStrategiesService } from '@@core/connections-strategies/connections-strategies.service'; @@ -67,7 +67,7 @@ export class GitlabConnectionService implements ITicketingConnectionService { grant_type: 'authorization_code', }); const res = await axios.post( - `https://api.gitlab.app/oauth/token`, + `https://gitlab.com/oauth/token`, formData.toString(), { headers: { @@ -105,6 +105,7 @@ export class GitlabConnectionService implements ITicketingConnectionService { connection_token: connection_token, provider_slug: 'gitlab', vertical: 'ticketing', + account_url: providersConfig['ticketing']['gitlab'].urls.apiUrl, token_type: 'oauth', access_token: this.cryptoService.encrypt(data.access_token), refresh_token: this.cryptoService.encrypt(data.refresh_token), diff --git a/packages/api/src/@core/utils/types/original/original.ticketing.ts b/packages/api/src/@core/utils/types/original/original.ticketing.ts index 678028eed..f334bf131 100644 --- a/packages/api/src/@core/utils/types/original/original.ticketing.ts +++ b/packages/api/src/@core/utils/types/original/original.ticketing.ts @@ -1,3 +1,4 @@ + import { FrontAccountInput, FrontAccountOutput, @@ -82,7 +83,7 @@ import { JiraTagInput, JiraTagOutput, } from '@ticketing/tag/services/jira/types'; -import { JiraCollectionOutput } from '@ticketing/collection/services/jira/types'; +import { JiraCollectionOutput, JiraCollectionInput } from '@ticketing/collection/services/jira/types'; import { ZendeskTicketInput, ZendeskTicketOutput, @@ -111,7 +112,10 @@ import { ZendeskUserInput, ZendeskUserOutput, } from '@ticketing/user/services/zendesk/types'; - +import { + GitlabCollectionInput, + GitlabCollectionOutput, +} from '@ticketing/collection/services/gitlab/types'; /* INPUT */ /* ticket */ @@ -161,7 +165,7 @@ export type OriginalTeamInput = /* attachment */ export type OriginalAttachmentInput = null; -export type OriginalCollectionInput = null; +export type OriginalCollectionInput = JiraCollectionInput | GitlabCollectionInput; export type TicketingObjectInput = | OriginalTicketInput @@ -228,7 +232,8 @@ export type OriginalAttachmentOutput = /* collection */ -export type OriginalCollectionOutput = JiraCollectionOutput; +export type OriginalCollectionOutput = JiraCollectionOutput | GitlabCollectionOutput; + export type TicketingObjectOutput = | OriginalTicketOutput @@ -240,3 +245,5 @@ export type TicketingObjectOutput = | OriginalContactOutput | OriginalAccountOutput | OriginalCollectionOutput; + + diff --git a/packages/api/src/ticketing/collection/collection.module.ts b/packages/api/src/ticketing/collection/collection.module.ts index 03dd577e7..a72cb8d05 100644 --- a/packages/api/src/ticketing/collection/collection.module.ts +++ b/packages/api/src/ticketing/collection/collection.module.ts @@ -1,3 +1,4 @@ +import { GitlabService } from './services/gitlab'; import { Module } from '@nestjs/common'; import { CollectionController } from './collection.controller'; import { SyncService } from './sync/sync.service'; @@ -32,6 +33,7 @@ import { JiraService } from './services/jira'; ServiceRegistry, /* PROVIDERS SERVICES */ JiraService, + GitlabService, ], exports: [ SyncService, diff --git a/packages/api/src/ticketing/collection/services/collection.service.ts b/packages/api/src/ticketing/collection/services/collection.service.ts index e7c4cbad9..698785f1e 100644 --- a/packages/api/src/ticketing/collection/services/collection.service.ts +++ b/packages/api/src/ticketing/collection/services/collection.service.ts @@ -68,6 +68,7 @@ export class CollectionService { remote_data?: boolean, ): Promise { try { + console.log("In collection service : ", integrationId) const collections = await this.prisma.tcg_collections.findMany({ where: { remote_platform: integrationId.toLowerCase(), diff --git a/packages/api/src/ticketing/collection/services/gitlab/index.ts b/packages/api/src/ticketing/collection/services/gitlab/index.ts new file mode 100644 index 000000000..c55d015ba --- /dev/null +++ b/packages/api/src/ticketing/collection/services/gitlab/index.ts @@ -0,0 +1,117 @@ +import { Injectable } from '@nestjs/common'; +import { LoggerService } from '@@core/logger/logger.service'; +import { PrismaService } from '@@core/prisma/prisma.service'; +import { EncryptionService } from '@@core/encryption/encryption.service'; +import { TicketingObject } from '@ticketing/@lib/@types'; +import { ApiResponse } from '@@core/utils/types'; +import axios from 'axios'; +import { ActionType, handleServiceError } from '@@core/utils/errors'; +import { ServiceRegistry } from '../registry.service'; +import { ICollectionService } from '@ticketing/collection/types'; +import { GitlabCollectionInput, GitlabCollectionOutput } from './types'; +import { DesunifyReturnType } from '@@core/utils/types/desunify.input'; + +@Injectable() +export class GitlabService implements ICollectionService { + constructor( + private prisma: PrismaService, + private logger: LoggerService, + private cryptoService: EncryptionService, + private registry: ServiceRegistry, + ) { + this.logger.setContext( + TicketingObject.collection.toUpperCase() + ':' + GitlabService.name, + ); + this.registry.registerService('gitlab', this); + } + + async syncCollections( + linkedUserId: string, + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'gitlab', + vertical: 'ticketing', + }, + }); + + console.log("xzx : ", `${connection.account_url}/projects`) + + const resp = await axios.get(`${connection.account_url}/projects`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }); + + this.logger.log(`Synced gitlab collections !`); + + // console.log("In index of gitlab", JSON.stringify(resp.data)) + + + return { + data: resp.data, + message: 'Gitlab collections retrieved', + statusCode: 200, + }; + } catch (error) { + handleServiceError( + error, + this.logger, + 'Gitlab', + TicketingObject.collection, + ActionType.GET, + ); + } + } + + async addCollection( + commentData: DesunifyReturnType, + linkedUserId: string + ): Promise> { + + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'gitlab', + vertical: 'ticketing', + }, + }); + + const resp = await axios.post( + `${connection.account_url}/projects`, + JSON.stringify({ + data: commentData, + }), + { + headers: { + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + 'Content-Type': 'application/json', + }, + }, + ); + + return { + data: resp.data, + message: 'Gitlab Collection created', + statusCode: 201, + }; + } catch (error) { + handleServiceError( + error, + this.logger, + 'Gitlab', + TicketingObject.collection, + ActionType.POST, + ); + } + + } +} diff --git a/packages/api/src/ticketing/collection/services/gitlab/mappers.ts b/packages/api/src/ticketing/collection/services/gitlab/mappers.ts new file mode 100644 index 000000000..e594505c2 --- /dev/null +++ b/packages/api/src/ticketing/collection/services/gitlab/mappers.ts @@ -0,0 +1,56 @@ +import { ICollectionMapper } from '@ticketing/collection/types'; +import { GitlabCollectionInput, GitlabCollectionOutput } from './types'; +import { + UnifiedCollectionInput, + UnifiedCollectionOutput, +} from '@ticketing/collection/types/model.unified'; + +export class GitlabCollectionMapper implements ICollectionMapper { + desunify( + source: UnifiedCollectionInput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): GitlabCollectionInput { + const result: GitlabCollectionInput = { + name: source.name, + description: source.description ? source.description : '', + path: source.name + } + + return result; + } + + unify( + source: GitlabCollectionOutput | GitlabCollectionOutput[], + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedCollectionOutput | UnifiedCollectionOutput[] { + // If the source is not an array, convert it to an array for mapping + const sourcesArray = Array.isArray(source) ? source : [source]; + + return sourcesArray.map((collection) => + this.mapSingleCollectionToUnified(collection, customFieldMappings), + ); + } + + private mapSingleCollectionToUnified( + collection: GitlabCollectionOutput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedCollectionOutput { + const unifiedCollection: UnifiedCollectionOutput = { + remote_id: String(collection.id), + name: collection.name, + description: collection.name, + collection_type: 'PROJECT', + }; + + return unifiedCollection; + } +} diff --git a/packages/api/src/ticketing/collection/services/gitlab/types.ts b/packages/api/src/ticketing/collection/services/gitlab/types.ts new file mode 100644 index 000000000..8796c5603 --- /dev/null +++ b/packages/api/src/ticketing/collection/services/gitlab/types.ts @@ -0,0 +1,138 @@ +interface GitlabCollection { + id: number + description: string + description_html: string + name: string + name_with_namespace: string + path: string + path_with_namespace: string + created_at: string + updated_at: string + default_branch: string + topics: string[] + ssh_url_to_repo: string + http_url_to_repo: string + web_url: string + readme_url: string + avatar_url: string + forks_count: number + star_count: number + last_activity_at: string + namespace: Namespace + container_registry_image_prefix: string + _links: Links + packages_enabled: boolean + empty_repo: boolean + archived: boolean + visibility: string + resolve_outdated_diff_discussions: boolean + container_expiration_policy: ContainerExpirationPolicy + issues_enabled: boolean + merge_requests_enabled: boolean + wiki_enabled: boolean + jobs_enabled: boolean + snippets_enabled: boolean + container_registry_enabled: boolean + service_desk_enabled: boolean + can_create_merge_request_in: boolean + issues_access_level: string + repository_access_level: string + merge_requests_access_level: string + forking_access_level: string + wiki_access_level: string + builds_access_level: string + snippets_access_level: string + pages_access_level: string + analytics_access_level: string + container_registry_access_level: string + security_and_compliance_access_level: string + emails_disabled: any + emails_enabled: any + shared_runners_enabled: boolean + group_runners_enabled: boolean + lfs_enabled: boolean + creator_id: number + import_url: any + import_type: any + import_status: string + import_error: any + open_issues_count: number + ci_default_git_depth: number + ci_forward_deployment_enabled: boolean + ci_forward_deployment_rollback_allowed: boolean + ci_allow_fork_pipelines_to_run_in_parent_project: boolean + ci_job_token_scope_enabled: boolean + ci_separated_caches: boolean + ci_restrict_pipeline_cancellation_role: string + public_jobs: boolean + build_timeout: number + auto_cancel_pending_pipelines: string + ci_config_path: string + shared_with_groups: any[] + only_allow_merge_if_pipeline_succeeds: boolean + allow_merge_on_skipped_pipeline: any + restrict_user_defined_variables: boolean + request_access_enabled: boolean + only_allow_merge_if_all_discussions_are_resolved: boolean + remove_source_branch_after_merge: boolean + printing_merge_request_link_enabled: boolean + merge_method: string + squash_option: string + enforce_auth_checks_on_uploads: boolean + suggestion_commit_message: any + merge_commit_template: any + squash_commit_template: any + issue_branch_template: string + auto_devops_enabled: boolean + auto_devops_deploy_strategy: string + autoclose_referenced_issues: boolean + keep_latest_artifact: boolean + runner_token_expiration_interval: any + external_authorization_classification_label: string + requirements_enabled: boolean + requirements_access_level: string + security_and_compliance_enabled: boolean + compliance_frameworks: any[] + warn_about_potentially_unwanted_characters: boolean + permissions: Permissions +} + +interface Namespace { + id: number + name: string + path: string + kind: string + full_path: string + parent_id: any + avatar_url: string + web_url: string +} + +interface Links { + self: string + issues: string + merge_requests: string + repo_branches: string + labels: string + events: string + members: string + cluster_agents: string +} + +interface ContainerExpirationPolicy { + cadence: string + enabled: boolean + keep_n: number + older_than: string + name_regex: string + name_regex_keep: string + next_run_at: string +} + +interface Permissions { + project_access: any + group_access: any +} + +export type GitlabCollectionInput = Partial; +export type GitlabCollectionOutput = GitlabCollectionInput; diff --git a/packages/api/src/ticketing/collection/services/jira/index.ts b/packages/api/src/ticketing/collection/services/jira/index.ts index 6c6831b65..ef3f48913 100644 --- a/packages/api/src/ticketing/collection/services/jira/index.ts +++ b/packages/api/src/ticketing/collection/services/jira/index.ts @@ -8,7 +8,8 @@ import axios from 'axios'; import { ActionType, handleServiceError } from '@@core/utils/errors'; import { ServiceRegistry } from '../registry.service'; import { ICollectionService } from '@ticketing/collection/types'; -import { JiraCollectionOutput } from './types'; +import { JiraCollectionOutput, JiraCollectionInput } from './types'; +import { DesunifyReturnType } from '@@core/utils/types/desunify.input'; @Injectable() export class JiraService implements ICollectionService { @@ -61,4 +62,13 @@ export class JiraService implements ICollectionService { ); } } + + async addCollection( + commentData: DesunifyReturnType, + linkedUserId: string + ): Promise> { + + return null; + + } } diff --git a/packages/api/src/ticketing/collection/sync/sync.service.ts b/packages/api/src/ticketing/collection/sync/sync.service.ts index 5a017bb36..84b70ddb8 100644 --- a/packages/api/src/ticketing/collection/sync/sync.service.ts +++ b/packages/api/src/ticketing/collection/sync/sync.service.ts @@ -59,7 +59,7 @@ export class SyncService implements OnModuleInit { } //function used by sync worker which populate our tcg_collections table //its role is to fetch all collections from providers 3rd parties and save the info inside our db - //@Cron('*/2 * * * *') // every 2 minutes (for testing) + // @Cron('*/2 * * * *') // every 2 minutes (for testing) @Cron('0 */8 * * *') // every 8 hours async syncCollections(user_id?: string) { try { @@ -195,6 +195,7 @@ export class SyncService implements OnModuleInit { ): Promise { try { let collections_results: TicketingCollection[] = []; + console.log(collections) for (let i = 0; i < collections.length; i++) { const collection = collections[i]; const originId = collection.remote_id; @@ -235,7 +236,7 @@ export class SyncService implements OnModuleInit { id_tcg_collection: uuidv4(), name: collection.name, description: collection.description, - type: collection.collection_type, + collection_type: collection.collection_type, created_at: new Date(), modified_at: new Date(), id_linked_user: linkedUserId, diff --git a/packages/api/src/ticketing/collection/types/index.ts b/packages/api/src/ticketing/collection/types/index.ts index d6283555a..894240e42 100644 --- a/packages/api/src/ticketing/collection/types/index.ts +++ b/packages/api/src/ticketing/collection/types/index.ts @@ -3,7 +3,7 @@ import { UnifiedCollectionInput, UnifiedCollectionOutput, } from './model.unified'; -import { OriginalCollectionOutput } from '@@core/utils/types/original/original.ticketing'; +import { OriginalCollectionOutput, OriginalCollectionInput } from '@@core/utils/types/original/original.ticketing'; import { ApiResponse } from '@@core/utils/types'; export interface ICollectionService { @@ -11,6 +11,11 @@ export interface ICollectionService { linkedUserId: string, custom_properties?: string[], ): Promise>; + + addCollection( + collectionData: DesunifyReturnType, + linkedUserId: string, + ): Promise>; } export interface ICollectionMapper { diff --git a/packages/api/src/ticketing/collection/types/mappingsTypes.ts b/packages/api/src/ticketing/collection/types/mappingsTypes.ts index edaf45c95..e18ad3cd1 100644 --- a/packages/api/src/ticketing/collection/types/mappingsTypes.ts +++ b/packages/api/src/ticketing/collection/types/mappingsTypes.ts @@ -1,10 +1,16 @@ +import { GitlabCollectionMapper } from '../services/gitlab/mappers'; import { JiraCollectionMapper } from '../services/jira/mappers'; const jiraCollectionMapper = new JiraCollectionMapper(); +const gitlabCollectionMapper = new GitlabCollectionMapper(); export const collectionUnificationMapping = { jira: { unify: jiraCollectionMapper.unify.bind(jiraCollectionMapper), - desunify: jiraCollectionMapper.desunify, + desunify: jiraCollectionMapper.desunify.bind(jiraCollectionMapper), + }, + gitlab: { + unify: gitlabCollectionMapper.unify.bind(gitlabCollectionMapper), + desunify: gitlabCollectionMapper.desunify.bind(gitlabCollectionMapper), }, }; diff --git a/packages/api/swagger/swagger-spec.json b/packages/api/swagger/swagger-spec.json index c00c2d20a..44f7aa6ab 100644 --- a/packages/api/swagger/swagger-spec.json +++ b/packages/api/swagger/swagger-spec.json @@ -83,31 +83,6 @@ ] } }, - "/auth/users/create": { - "post": { - "operationId": "createUser", - "summary": "Create User", - "parameters": [], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateUserDto" - } - } - } - }, - "responses": { - "201": { - "description": "" - } - }, - "tags": [ - "auth" - ] - } - }, "/auth/login": { "post": { "operationId": "signIn", @@ -425,7 +400,7 @@ ] } }, - "/linked-users/create": { + "/linked-users": { "post": { "operationId": "addLinkedUser", "summary": "Add Linked User", @@ -448,9 +423,7 @@ "tags": [ "linked-users" ] - } - }, - "/linked-users": { + }, "get": { "operationId": "getLinkedUsers", "summary": "Retrieve Linked Users", @@ -542,9 +515,7 @@ "tags": [ "projects" ] - } - }, - "/projects/create": { + }, "post": { "operationId": "createProject", "summary": "Create a project", @@ -569,7 +540,7 @@ ] } }, - "/field-mapping/entities": { + "/field-mappings/entities": { "get": { "operationId": "getFieldMappingsEntities", "summary": "Retrieve field mapping entities", @@ -580,11 +551,11 @@ } }, "tags": [ - "field-mapping" + "field-mappings" ] } }, - "/field-mapping/attribute": { + "/field-mappings/attribute": { "get": { "operationId": "getFieldMappings", "summary": "Retrieve field mappings", @@ -595,11 +566,11 @@ } }, "tags": [ - "field-mapping" + "field-mappings" ] } }, - "/field-mapping/value": { + "/field-mappings/value": { "get": { "operationId": "getFieldMappingValues", "summary": "Retrieve field mappings values", @@ -610,11 +581,11 @@ } }, "tags": [ - "field-mapping" + "field-mappings" ] } }, - "/field-mapping/define": { + "/field-mappings/define": { "post": { "operationId": "defineTargetField", "summary": "Define target Field", @@ -635,11 +606,11 @@ } }, "tags": [ - "field-mapping" + "field-mappings" ] } }, - "/field-mapping/map": { + "/field-mappings/map": { "post": { "operationId": "mapField", "summary": "Map Custom Field", @@ -660,11 +631,11 @@ } }, "tags": [ - "field-mapping" + "field-mappings" ] } }, - "/field-mapping/properties": { + "/field-mappings/properties": { "get": { "operationId": "getCustomProviderProperties", "summary": "Retrieve Custom Properties", @@ -700,7 +671,7 @@ } }, "tags": [ - "field-mapping" + "field-mappings" ] } }, @@ -762,7 +733,7 @@ ] } }, - "/magic-link/create": { + "/magic-links": { "post": { "operationId": "createMagicLink", "summary": "Create a Magic Link", @@ -783,11 +754,9 @@ } }, "tags": [ - "magic-link" + "magic-links" ] - } - }, - "/magic-link": { + }, "get": { "operationId": "getMagicLinks", "summary": "Retrieve Magic Links", @@ -798,11 +767,11 @@ } }, "tags": [ - "magic-link" + "magic-links" ] } }, - "/magic-link/single": { + "/magic-links/single": { "get": { "operationId": "getMagicLink", "summary": "Retrieve a Magic Link", @@ -822,7 +791,7 @@ } }, "tags": [ - "magic-link" + "magic-links" ] } }, @@ -1065,7 +1034,7 @@ ] } }, - "/sync/status/{vertical}": { + "/syncs/status/{vertical}": { "get": { "operationId": "getSyncStatus", "summary": "Retrieve sync status of a certain vertical", @@ -1085,11 +1054,11 @@ } }, "tags": [ - "sync" + "syncs" ] } }, - "/sync/resync/{vertical}": { + "/syncs/resyncs/{vertical}": { "get": { "operationId": "resync", "summary": "Resync common objects across a vertical", @@ -1109,7 +1078,7 @@ } }, "tags": [ - "sync" + "syncs" ] } }, @@ -3141,7 +3110,7 @@ ] } }, - "/ticketing/collection": { + "/ticketing/collections": { "get": { "operationId": "getCollections", "summary": "List a batch of Collections", @@ -3189,11 +3158,11 @@ } }, "tags": [ - "ticketing/collection" + "ticketing/collections" ] } }, - "/ticketing/collection/{id}": { + "/ticketing/collections/{id}": { "get": { "operationId": "getCollection", "summary": "Retrieve a Collection", @@ -3242,7 +3211,7 @@ } }, "tags": [ - "ticketing/collection" + "ticketing/collections" ] } }, diff --git a/packages/shared/src/authUrl.ts b/packages/shared/src/authUrl.ts index f3ff616df..79cda67de 100644 --- a/packages/shared/src/authUrl.ts +++ b/packages/shared/src/authUrl.ts @@ -82,7 +82,7 @@ const handleOAuth2Url = async (input: HandleOAuth2Url) => { } = input; const type = providerToType(providerName, vertical, authStrategy); - + // 1. env if selfhost and no custom // 2. backend if custom credentials // same for authBaseUrl with subdomain @@ -97,12 +97,12 @@ const handleOAuth2Url = async (input: HandleOAuth2Url) => { const { urls: urls } = config; const { authBaseUrl: baseUrl } = urls; - + if (!baseUrl) throw new Error(`No authBaseUrl found for type ${type}`) // construct the baseAuthUrl based on the fact that client may use custom subdomain - const BASE_URL: string = providerName === 'gorgias' ? `${apiUrl}${baseUrl}`: - data.SUBDOMAIN ? data.SUBDOMAIN + baseUrl : baseUrl; + const BASE_URL: string = providerName === 'gorgias' ? `${apiUrl}${baseUrl}` : + data.SUBDOMAIN ? data.SUBDOMAIN + baseUrl : baseUrl; // console.log('BASE URL IS '+ BASE_URL) if (!baseUrl || !BASE_URL) { @@ -127,7 +127,7 @@ const handleOAuth2Url = async (input: HandleOAuth2Url) => { params = `audience=api.atlassian.com&${params}&prompt=consent`; break; case 'gitlab': - params += '&code_challenge=&code_challenge_method='; + params += '&response_type=code&code_challenge=&code_challenge_method='; break; case 'gorgias': params = `&response_type=code&nonce=${randomString()}`; diff --git a/packages/shared/src/enum.ts b/packages/shared/src/enum.ts index 3d86d97f2..97ac5c7a3 100644 --- a/packages/shared/src/enum.ts +++ b/packages/shared/src/enum.ts @@ -22,6 +22,7 @@ export enum TicketingProviders { GITHUB = 'github', JIRA = 'jira', GORGIAS = 'gorgias', + GITLAB = 'gitlab', } export enum AccountingProviders { diff --git a/packages/shared/src/providers.ts b/packages/shared/src/providers.ts index 382a4e17b..3c38156be 100644 --- a/packages/shared/src/providers.ts +++ b/packages/shared/src/providers.ts @@ -7,7 +7,7 @@ export const CRM_PROVIDERS = ['zoho', 'zendesk', 'hubspot', 'pipedrive', 'attio' export const HRIS_PROVIDERS = ['']; export const ATS_PROVIDERS = ['']; export const ACCOUNTING_PROVIDERS = ['']; -export const TICKETING_PROVIDERS = ['zendesk', 'front', 'github', 'jira', 'gorgias']; +export const TICKETING_PROVIDERS = ['zendesk', 'front', 'github', 'jira', 'gorgias', 'gitlab']; export const MARKETINGAUTOMATION_PROVIDERS = ['']; export const FILESTORAGE_PROVIDERS = ['']; diff --git a/packages/shared/src/utils.ts b/packages/shared/src/utils.ts index de2af40e8..1d2f61480 100644 --- a/packages/shared/src/utils.ts +++ b/packages/shared/src/utils.ts @@ -14,13 +14,13 @@ export type ProviderConfig = { description: string; active?: boolean; - customPropertiesUrl?: string; + customPropertiesUrl?: string; authStrategy?: AuthStrategy; urls: { docsUrl: string; apiUrl: string; authBaseUrl?: string; // url used to authorize an application on behalf of the user (only when authStrategy is oauth2) - customPropertiesUrl?: string; + customPropertiesUrl?: string; } }; @@ -108,12 +108,12 @@ export const providersConfig: ProvidersConfig = { logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRNKVceZGVM7PbARp_2bjdOICUxlpS5B29UYlurvh6Z2Q&s', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', authStrategy: AuthStrategy.oauth2, - }, + }, 'accelo': { scopes: '', urls: { docsUrl: 'https://api.accelo.com/docs/#introduction', - authBaseUrl: '/oauth2/v0/authorize', + authBaseUrl: '/oauth2/v0/authorize', apiUrl: '/api/v0', }, logoPath: 'https://play-lh.googleusercontent.com/j63K2u8ZXukgPs8QPgyXfyoxuNBl_ST7gLx5DEFeczCTtM9e5JNpDjjBy32qLxFS7p0', @@ -219,7 +219,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://developers.nutshell.com/', apiUrl: '/api/v1/json', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRbCONyN9DCKfd4E8pzIdItl5VqPTEErpoEn9vHCgblRg&s', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -231,7 +231,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://pipeliner.stoplight.io/docs/api-docs', apiUrl: '', - }, + }, logoPath: 'https://play-lh.googleusercontent.com/rK9Qv_w9C8Py_aLZdQQDobNdHWSG8KL4dj3cBBQLcimVu-ctxwujA4VE442lIpZ65AE', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -255,7 +255,7 @@ export const providersConfig: ProvidersConfig = { docsUrl: '', authBaseUrl: '', apiUrl: '', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTgL4FJb-GptGfxDDkWbIX2CjIM77t5q-d7eCFY6sGsHA&s', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -268,7 +268,7 @@ export const providersConfig: ProvidersConfig = { docsUrl: '', authBaseUrl: '', apiUrl: '', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQftNERc1ImBHm8MXXuWdhQiFYwW-dXNcogRL1UV8JyHFQGY2BbsbpwKvERwKRB39RH6zw&usqp=CAU', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -302,7 +302,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRcUYrYD8lnaFaDN93vwjHhksKJUG3rqlb1TCFC__oPBw&s', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -315,7 +315,7 @@ export const providersConfig: ProvidersConfig = { docsUrl: '', authBaseUrl: '', apiUrl: '', - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -394,12 +394,12 @@ export const providersConfig: ProvidersConfig = { scopes: '', urls: { docsUrl: 'https://docs.gitlab.com/ee/api/rest/#', - apiUrl: '/api/v4', - authBaseUrl: '/oauth/authorize', + apiUrl: 'https://gitlab.com/api/v4', + authBaseUrl: 'https://gitlab.com/oauth/authorize', }, logoPath: '', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', - active: false, + active: true, authStrategy: AuthStrategy.oauth2 }, 'clickup': { @@ -467,7 +467,7 @@ export const providersConfig: ProvidersConfig = { docsUrl: '', apiUrl: '', authBaseUrl: '', - }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, }, @@ -478,7 +478,7 @@ export const providersConfig: ProvidersConfig = { docsUrl: '', apiUrl: '', authBaseUrl: '', - }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, }, @@ -487,7 +487,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://docs.dixa.io/docs/', apiUrl: 'https://dev.dixa.io', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, @@ -512,7 +512,7 @@ export const providersConfig: ProvidersConfig = { docsUrl: '', apiUrl: '', authBaseUrl: '', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, @@ -602,7 +602,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, @@ -613,7 +613,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, @@ -623,7 +623,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://www.reamaze.com/api', apiUrl: '/api/v1', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, @@ -635,7 +635,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, @@ -646,7 +646,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, @@ -656,7 +656,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://developer.shortcut.com/api/rest/v3', apiUrl: 'https://api.app.shortcut.com', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, @@ -668,7 +668,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, @@ -679,7 +679,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, @@ -690,7 +690,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: 'https://api.app.shortcut.com', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, @@ -701,7 +701,7 @@ export const providersConfig: ProvidersConfig = { docsUrl: 'https://developers.wrike.com/overview/', apiUrl: '/api/v4', authBaseUrl: 'https://login.wrike.com/oauth2/authorize/v4', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, @@ -712,7 +712,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, @@ -722,7 +722,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '', - }, + }, logoPath: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRqz0aID6B-InxK_03P7tCtqpXNXdawBcro67CyEE0I5g&s', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: false, @@ -795,7 +795,7 @@ export const providersConfig: ProvidersConfig = { docsUrl: '', apiUrl: '', authBaseUrl: '', - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -807,7 +807,7 @@ export const providersConfig: ProvidersConfig = { docsUrl: '', apiUrl: '', authBaseUrl: '', - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -831,7 +831,7 @@ export const providersConfig: ProvidersConfig = { docsUrl: '', apiUrl: '', authBaseUrl: '', - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -891,7 +891,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://customer.io/docs/api/track/', apiUrl: 'https://track.customer.io/api/' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -901,7 +901,7 @@ export const providersConfig: ProvidersConfig = { authBaseUrl: 'https://app.getresponse.com/oauth2_authorize.html', docsUrl: 'https://apidocs.getresponse.com/v3', apiUrl: 'https://api.getresponse.com/v3' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -913,7 +913,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -925,18 +925,18 @@ export const providersConfig: ProvidersConfig = { authBaseUrl: 'https://accounts.infusionsoft.com/app/oauth/authorize', docsUrl: 'https://developer.infusionsoft.com/docs/rest/', apiUrl: 'https://api.infusionsoft.com/crm/rest/v1/account/profile' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, authStrategy: AuthStrategy.oauth2 }, - 'klaviyo': { + 'klaviyo': { scopes: '', urls: { docsUrl: 'https://developers.klaviyo.com/en/reference/api_overview', apiUrl: 'https://a.klaviyo.com/api' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -948,7 +948,7 @@ export const providersConfig: ProvidersConfig = { authBaseUrl: 'https://login.mailchimp.com/oauth2/authorize', docsUrl: 'https://mailchimp.com/developer/marketing/api/', apiUrl: '' // todo - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -959,7 +959,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://developers.messagebird.com/api/', apiUrl: 'https://rest.messagebird.com' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -971,7 +971,7 @@ export const providersConfig: ProvidersConfig = { authBaseUrl: 'https://api.podium.com/oauth/authorize', docsUrl: 'https://docs.podium.com/reference/introduction', apiUrl: 'https://api.podium.com/v4' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -982,7 +982,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://docs.sendgrid.com/for-developers/sending-email/api-getting-started', apiUrl: 'https://api.sendgrid.com/v3' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -993,7 +993,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://developers.brevo.com/docs/getting-started', apiUrl: 'https://api.brevo.com/v3' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1008,7 +1008,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1018,7 +1018,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://developers.ashbyhq.com', apiUrl: 'https://api.ashbyhq.com' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1030,7 +1030,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://documentation.bamboohr.com/docs/getting-started', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1041,7 +1041,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://developer.breezy.hr/reference/overview', apiUrl: 'https://api.breezy.hr/v3' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1053,7 +1053,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://bullhorn.github.io/rest-api-docs/', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1063,7 +1063,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://docs.catsone.com/api/v3/', apiUrl: 'https://api.catsone.com/v3' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1074,7 +1074,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://clayhr.readme.io/', apiUrl: '/rm/api/v3' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1086,7 +1086,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1097,7 +1097,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1107,7 +1107,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: 'https://developer.lumesse-talenthub.com/rest-api-developers-guide/1.21.33/index.html?page=rest-api&subpage=introduction', apiUrl: 'https://apiproxy.shared.lumessetalentlink.com/tlk/rest' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1118,7 +1118,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1128,7 +1128,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1138,7 +1138,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1148,7 +1148,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1158,7 +1158,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1168,7 +1168,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1178,7 +1178,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1188,7 +1188,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1198,7 +1198,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1208,7 +1208,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1218,7 +1218,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1228,7 +1228,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1238,7 +1238,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1248,7 +1248,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1258,7 +1258,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1268,7 +1268,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1278,7 +1278,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1288,7 +1288,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1298,7 +1298,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1308,7 +1308,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1318,7 +1318,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1328,7 +1328,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1338,7 +1338,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1348,7 +1348,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1358,7 +1358,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1368,7 +1368,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1378,7 +1378,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1388,7 +1388,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1398,7 +1398,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1408,7 +1408,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1418,7 +1418,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1428,7 +1428,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1438,7 +1438,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1448,7 +1448,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1458,7 +1458,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1468,7 +1468,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1478,7 +1478,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1491,7 +1491,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1501,7 +1501,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1511,7 +1511,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1521,7 +1521,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1531,7 +1531,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1541,7 +1541,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1551,7 +1551,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1561,7 +1561,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1571,7 +1571,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1581,7 +1581,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1591,7 +1591,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1601,7 +1601,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1611,7 +1611,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1621,7 +1621,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1631,7 +1631,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1641,7 +1641,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1651,7 +1651,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1661,7 +1661,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1671,7 +1671,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1681,7 +1681,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1691,7 +1691,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1701,7 +1701,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1711,7 +1711,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1721,7 +1721,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1731,7 +1731,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1741,7 +1741,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1751,7 +1751,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1761,7 +1761,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1771,7 +1771,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1781,7 +1781,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1791,7 +1791,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1801,7 +1801,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1811,7 +1811,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1821,7 +1821,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1831,7 +1831,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1841,7 +1841,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1851,7 +1851,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1861,7 +1861,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1871,7 +1871,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1881,7 +1881,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1891,7 +1891,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1901,7 +1901,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1911,7 +1911,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1921,7 +1921,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1931,7 +1931,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1941,7 +1941,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1951,7 +1951,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1961,7 +1961,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1971,7 +1971,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1981,7 +1981,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -1991,7 +1991,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -2001,7 +2001,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -2011,7 +2011,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -2021,7 +2021,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -2031,7 +2031,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -2041,7 +2041,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -2051,7 +2051,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -2061,7 +2061,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -2071,7 +2071,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -2081,7 +2081,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -2091,7 +2091,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -2101,7 +2101,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -2111,7 +2111,7 @@ export const providersConfig: ProvidersConfig = { urls: { docsUrl: '', apiUrl: '' - }, + }, logoPath: 'https://play-lh.googleusercontent.com/EMobDJKabP1eY_63QHgPS_-TK3eRfxXaeOnERbcRaWAw573iaV74pXS9xOv997dRZtM', description: 'Sync & Create contacts, deals, companies, notes, engagements, stages, tasks and users', active: false, @@ -2161,15 +2161,15 @@ export function providersArray(vertical: string): Provider[] { const activeProviders = getActiveProvidersForVertical(vertical); return Object.entries(activeProviders).map(([providerName, config]) => ({ - name: providerName, - urls: { - docsUrl: config.urls.docsUrl, - apiUrl: config.urls.apiUrl, - authBaseUrl: config.urls.authBaseUrl, - }, - scopes: config.scopes, - logoPath: config.logoPath, - description: config.description, + name: providerName, + urls: { + docsUrl: config.urls.docsUrl, + apiUrl: config.urls.apiUrl, + authBaseUrl: config.urls.authBaseUrl, + }, + scopes: config.scopes, + logoPath: config.logoPath, + description: config.description, })); } From b6120116a7c88f5b28471dd51b2531f07e080c59 Mon Sep 17 00:00:00 2001 From: mit-27 Date: Sun, 5 May 2024 18:40:42 -0400 Subject: [PATCH 02/14] =?UTF-8?q?=E2=9E=95=20Add=20collection=20pull=20sco?= =?UTF-8?q?pe=20for=20webhook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/shared/src/webhookScopes.ts | 53 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/packages/shared/src/webhookScopes.ts b/packages/shared/src/webhookScopes.ts index 972b27aa9..0d34c3133 100644 --- a/packages/shared/src/webhookScopes.ts +++ b/packages/shared/src/webhookScopes.ts @@ -1,30 +1,31 @@ export const scopes = [ - 'crm.contact.created', - 'crm.contact.pulled', - 'crm.company.created', - 'crm.company.pulled', - 'crm.deal.created', - 'crm.deal.pulled', - 'crm.engagement.created', - 'crm.engagement.pulled', - 'crm.note.created', - 'crm.note.pulled', - 'crm.stage.pulled', - 'crm.task.pulled', - 'crm.task.created', - 'crm.user.pulled', - - 'ticketing.ticket.created', - 'ticketing.ticket.pulled', - 'ticketing.comment.created', - 'ticketing.comment.pulled', - 'ticketing.attachment.created', - 'ticketing.attachment.pulled', - 'ticketing.account.pulled', - 'ticketing.contact.pulled', - 'ticketing.tag.pulled', - 'ticketing.team.pulled', - 'ticketing.user.pulled', + 'crm.contact.created', + 'crm.contact.pulled', + 'crm.company.created', + 'crm.company.pulled', + 'crm.deal.created', + 'crm.deal.pulled', + 'crm.engagement.created', + 'crm.engagement.pulled', + 'crm.note.created', + 'crm.note.pulled', + 'crm.stage.pulled', + 'crm.task.pulled', + 'crm.task.created', + 'crm.user.pulled', + + 'ticketing.ticket.created', + 'ticketing.ticket.pulled', + 'ticketing.comment.created', + 'ticketing.comment.pulled', + 'ticketing.attachment.created', + 'ticketing.attachment.pulled', + 'ticketing.collection.pulled', + 'ticketing.account.pulled', + 'ticketing.contact.pulled', + 'ticketing.tag.pulled', + 'ticketing.team.pulled', + 'ticketing.user.pulled', 'connection.created' ]; From 41e8104fc90e77ce1a8fd97ca012e3d15c4184db Mon Sep 17 00:00:00 2001 From: mit-27 Date: Mon, 6 May 2024 01:14:16 -0400 Subject: [PATCH 03/14] =?UTF-8?q?=E2=9E=95=20Add=20gitlab/user?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ticketing/user/services/gitlab/index.ts | 64 +++++++++++++++++++ .../ticketing/user/services/gitlab/mappers.ts | 58 +++++++++++++++++ .../ticketing/user/services/gitlab/types.ts | 42 ++++++++++++ .../src/ticketing/user/types/mappingsTypes.ts | 22 ++++++- .../api/src/ticketing/user/user.module.ts | 2 + 5 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 packages/api/src/ticketing/user/services/gitlab/index.ts create mode 100644 packages/api/src/ticketing/user/services/gitlab/mappers.ts create mode 100644 packages/api/src/ticketing/user/services/gitlab/types.ts diff --git a/packages/api/src/ticketing/user/services/gitlab/index.ts b/packages/api/src/ticketing/user/services/gitlab/index.ts new file mode 100644 index 000000000..ddc4ee269 --- /dev/null +++ b/packages/api/src/ticketing/user/services/gitlab/index.ts @@ -0,0 +1,64 @@ +import { Injectable } from '@nestjs/common'; +import { LoggerService } from '@@core/logger/logger.service'; +import { PrismaService } from '@@core/prisma/prisma.service'; +import { EncryptionService } from '@@core/encryption/encryption.service'; +import { TicketingObject } from '@ticketing/@lib/@types'; +import { ApiResponse } from '@@core/utils/types'; +import axios from 'axios'; +import { ActionType, handleServiceError } from '@@core/utils/errors'; +import { ServiceRegistry } from '../registry.service'; +import { IUserService } from '@ticketing/user/types'; +import { GitlabUserOutput } from './types'; + +@Injectable() +export class GitlabService implements IUserService { + constructor( + private prisma: PrismaService, + private logger: LoggerService, + private cryptoService: EncryptionService, + private registry: ServiceRegistry, + ) { + this.logger.setContext( + TicketingObject.user.toUpperCase() + ':' + GitlabService.name, + ); + this.registry.registerService('gitlab', this); + } + + async syncUsers( + linkedUserId: string, + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'gitlab', + vertical: 'ticketing', + }, + }); + + const resp = await axios.get(`${connection.account_url}/users`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }); + this.logger.log(`Synced gitlab users !`); + + return { + data: resp.data._results, + message: 'gitlab users retrieved', + statusCode: 200, + }; + } catch (error) { + handleServiceError( + error, + this.logger, + 'Gitlab', + TicketingObject.user, + ActionType.GET, + ); + } + } +} diff --git a/packages/api/src/ticketing/user/services/gitlab/mappers.ts b/packages/api/src/ticketing/user/services/gitlab/mappers.ts new file mode 100644 index 000000000..2da090622 --- /dev/null +++ b/packages/api/src/ticketing/user/services/gitlab/mappers.ts @@ -0,0 +1,58 @@ +import { IUserMapper } from '@ticketing/user/types'; +import { + UnifiedUserInput, + UnifiedUserOutput, +} from '@ticketing/user/types/model.unified'; +import { GitlabUserInput, GitlabUserOutput } from './types'; + +export class GitlabUserMapper implements IUserMapper { + desunify( + source: UnifiedUserInput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): GitlabUserInput { + return; + } + + unify( + source: GitlabUserOutput | GitlabUserOutput[], + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedUserOutput | UnifiedUserOutput[] { + const sourcesArray = Array.isArray(source) ? source : [source]; + return sourcesArray.map((user) => + this.mapSingleUserToUnified(user, customFieldMappings), + ); + } + + private mapSingleUserToUnified( + user: GitlabUserOutput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedUserOutput { + // Initialize field_mappings array from customFields, if provided + const field_mappings = customFieldMappings + ? customFieldMappings + .map((mapping) => ({ + key: mapping.slug, + value: user ? user[mapping.remote_id] : undefined, + })) + .filter((mapping) => mapping.value !== undefined) + : []; + + const unifiedUser: UnifiedUserOutput = { + remote_id: String(user.id), + name: user.name, + email_address: user.email, + field_mappings, + }; + + return unifiedUser; + } +} diff --git a/packages/api/src/ticketing/user/services/gitlab/types.ts b/packages/api/src/ticketing/user/services/gitlab/types.ts new file mode 100644 index 000000000..e703b372c --- /dev/null +++ b/packages/api/src/ticketing/user/services/gitlab/types.ts @@ -0,0 +1,42 @@ +interface GitlabUser { + id: number + username: string + email: string + name: string + state: string + locked: boolean + avatar_url: string + web_url: string + created_at: string + is_admin: boolean + bio: string + location: any + skype: string + linkedin: string + twitter: string + discord: string + website_url: string + organization: string + job_title: string + last_sign_in_at: any + confirmed_at: string + theme_id: number + last_activity_on: string + color_scheme_id: number + projects_limit: number + current_sign_in_at: string + identities: any[] + can_create_group: boolean + can_create_project: boolean + two_factor_enabled: boolean + external: boolean + private_profile: boolean + current_sign_in_ip: string + last_sign_in_ip: string + namespace_id: number + created_by: any + email_reset_offered_at: any +} + +export type GitlabUserInput = Partial; +export type GitlabUserOutput = GitlabUserInput; diff --git a/packages/api/src/ticketing/user/types/mappingsTypes.ts b/packages/api/src/ticketing/user/types/mappingsTypes.ts index 4ad24ef23..ff8e49da1 100644 --- a/packages/api/src/ticketing/user/types/mappingsTypes.ts +++ b/packages/api/src/ticketing/user/types/mappingsTypes.ts @@ -1,16 +1,34 @@ +import { GitlabUserMapper } from '../services/gitlab/mappers'; +import { GorgiasUserMapper } from '../services/gorgias/mappers'; +import { JiraUserMapper } from '../services/jira/mappers'; import { FrontUserMapper } from '../services/front/mappers'; import { ZendeskUserMapper } from '../services/zendesk/mappers'; const zendeskUserMapper = new ZendeskUserMapper(); const frontUserMapper = new FrontUserMapper(); +const gitlabUserMapper = new GitlabUserMapper(); +const gorgiasUserMapper = new GorgiasUserMapper(); +const jiraUserMapper = new JiraUserMapper(); export const userUnificationMapping = { zendesk: { unify: zendeskUserMapper.unify.bind(zendeskUserMapper), - desunify: zendeskUserMapper.desunify, + desunify: zendeskUserMapper.desunify.bind(zendeskUserMapper), }, front: { unify: frontUserMapper.unify.bind(frontUserMapper), - desunify: frontUserMapper.desunify, + desunify: frontUserMapper.desunify.bind(frontUserMapper), + }, + gitlab: { + unify: gitlabUserMapper.unify.bind(gitlabUserMapper), + desunify: gitlabUserMapper.desunify.bind(gitlabUserMapper), + }, + gorgias: { + unify: gorgiasUserMapper.unify.bind(gorgiasUserMapper), + desunify: gorgiasUserMapper.desunify.bind(gorgiasUserMapper), + }, + jira: { + unify: jiraUserMapper.unify.bind(jiraUserMapper), + desunify: jiraUserMapper.desunify.bind(jiraUserMapper), }, }; diff --git a/packages/api/src/ticketing/user/user.module.ts b/packages/api/src/ticketing/user/user.module.ts index f00b064e1..64a06f491 100644 --- a/packages/api/src/ticketing/user/user.module.ts +++ b/packages/api/src/ticketing/user/user.module.ts @@ -1,3 +1,4 @@ +import { GitlabService } from './services/gitlab'; import { Module } from '@nestjs/common'; import { UserController } from './user.controller'; import { SyncService } from './sync/sync.service'; @@ -38,6 +39,7 @@ import { GorgiasService } from './services/gorgias'; FrontService, JiraService, GorgiasService, + GitlabService, ], exports: [ SyncService, From 0dbf75522f72985c0e48e023c24d723498b90358 Mon Sep 17 00:00:00 2001 From: mit-27 Date: Mon, 6 May 2024 01:58:42 -0400 Subject: [PATCH 04/14] =?UTF-8?q?=F0=9F=94=A7=20Add=20gitlab=20scope?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/shared/src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/utils.ts b/packages/shared/src/utils.ts index 1d2f61480..96518cf1c 100644 --- a/packages/shared/src/utils.ts +++ b/packages/shared/src/utils.ts @@ -391,7 +391,7 @@ export const providersConfig: ProvidersConfig = { authStrategy: AuthStrategy.oauth2 }, 'gitlab': { - scopes: '', + scopes: 'api read_api read_user create_runner k8s_proxy read_repository write_repository sudo admin_mode read_service_ping openid profile email', urls: { docsUrl: 'https://docs.gitlab.com/ee/api/rest/#', apiUrl: 'https://gitlab.com/api/v4', From d0746fc2793e047db17b43aaa90b3076d5d21b2e Mon Sep 17 00:00:00 2001 From: mit-27 Date: Mon, 6 May 2024 19:01:49 -0400 Subject: [PATCH 05/14] =?UTF-8?q?=F0=9F=90=9B=20Fix=20gitlab/user?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/api/src/ticketing/user/services/gitlab/index.ts | 4 +++- .../api/src/ticketing/user/services/gitlab/mappers.ts | 2 +- packages/api/src/ticketing/user/sync/sync.service.ts | 9 ++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/api/src/ticketing/user/services/gitlab/index.ts b/packages/api/src/ticketing/user/services/gitlab/index.ts index ddc4ee269..15d1ff254 100644 --- a/packages/api/src/ticketing/user/services/gitlab/index.ts +++ b/packages/api/src/ticketing/user/services/gitlab/index.ts @@ -46,8 +46,10 @@ export class GitlabService implements IUserService { }); this.logger.log(`Synced gitlab users !`); + // console.log("Users Data : ", resp.data); + return { - data: resp.data._results, + data: resp.data, message: 'gitlab users retrieved', statusCode: 200, }; diff --git a/packages/api/src/ticketing/user/services/gitlab/mappers.ts b/packages/api/src/ticketing/user/services/gitlab/mappers.ts index 2da090622..a24971b87 100644 --- a/packages/api/src/ticketing/user/services/gitlab/mappers.ts +++ b/packages/api/src/ticketing/user/services/gitlab/mappers.ts @@ -49,7 +49,7 @@ export class GitlabUserMapper implements IUserMapper { const unifiedUser: UnifiedUserOutput = { remote_id: String(user.id), name: user.name, - email_address: user.email, + email_address: user.email ? user.email : '', field_mappings, }; diff --git a/packages/api/src/ticketing/user/sync/sync.service.ts b/packages/api/src/ticketing/user/sync/sync.service.ts index c2c457d8b..06129515d 100644 --- a/packages/api/src/ticketing/user/sync/sync.service.ts +++ b/packages/api/src/ticketing/user/sync/sync.service.ts @@ -60,7 +60,7 @@ export class SyncService implements OnModuleInit { } //function used by sync worker which populate our tcg_users table //its role is to fetch all users from providers 3rd parties and save the info inside our db - //@Cron('*/2 * * * *') // every 2 minutes (for testing) + // @Cron('*/2 * * * *') // every 2 minutes (for testing) @Cron('0 */8 * * *') // every 8 hours async syncUsers(user_id?: string) { try { @@ -157,7 +157,8 @@ export class SyncService implements OnModuleInit { ); const sourceObject: OriginalUserOutput[] = resp.data; - //this.logger.log('SOURCE OBJECT DATA = ' + JSON.stringify(sourceObject)); + // this.logger.log('SOURCE OBJECT DATA = ' + JSON.stringify(sourceObject)); + // console.log("Source Data ", sourceObject) //unify the data according to the target obj wanted const unifiedObject = (await unify({ sourceObject, @@ -253,10 +254,12 @@ export class SyncService implements OnModuleInit { created_at: new Date(), modified_at: new Date(), id_linked_user: linkedUserId, - id_tcg_account: user.account_id || '', + // id_tcg_account: user.account_id || '', remote_id: originId, remote_platform: originSource, }; + + // console.log("Tcg user Data: ", data) const res = await this.prisma.tcg_users.create({ data: data, }); From cbc2f560af42859b2fc89434317f5d96de1264c0 Mon Sep 17 00:00:00 2001 From: mit-27 Date: Mon, 6 May 2024 20:41:40 -0400 Subject: [PATCH 06/14] =?UTF-8?q?=F0=9F=94=A5=20Remove=20addCollection=20m?= =?UTF-8?q?ethod=20for=20ticketing/collection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../collection/services/gitlab/index.ts | 45 ------------------- .../collection/services/jira/index.ts | 7 --- .../src/ticketing/collection/types/index.ts | 4 -- 3 files changed, 56 deletions(-) diff --git a/packages/api/src/ticketing/collection/services/gitlab/index.ts b/packages/api/src/ticketing/collection/services/gitlab/index.ts index c55d015ba..93bfdc38d 100644 --- a/packages/api/src/ticketing/collection/services/gitlab/index.ts +++ b/packages/api/src/ticketing/collection/services/gitlab/index.ts @@ -37,7 +37,6 @@ export class GitlabService implements ICollectionService { }, }); - console.log("xzx : ", `${connection.account_url}/projects`) const resp = await axios.get(`${connection.account_url}/projects`, { headers: { @@ -69,49 +68,5 @@ export class GitlabService implements ICollectionService { } } - async addCollection( - commentData: DesunifyReturnType, - linkedUserId: string - ): Promise> { - try { - const connection = await this.prisma.connections.findFirst({ - where: { - id_linked_user: linkedUserId, - provider_slug: 'gitlab', - vertical: 'ticketing', - }, - }); - - const resp = await axios.post( - `${connection.account_url}/projects`, - JSON.stringify({ - data: commentData, - }), - { - headers: { - Authorization: `Bearer ${this.cryptoService.decrypt( - connection.access_token, - )}`, - 'Content-Type': 'application/json', - }, - }, - ); - - return { - data: resp.data, - message: 'Gitlab Collection created', - statusCode: 201, - }; - } catch (error) { - handleServiceError( - error, - this.logger, - 'Gitlab', - TicketingObject.collection, - ActionType.POST, - ); - } - - } } diff --git a/packages/api/src/ticketing/collection/services/jira/index.ts b/packages/api/src/ticketing/collection/services/jira/index.ts index ef3f48913..7b09a4856 100644 --- a/packages/api/src/ticketing/collection/services/jira/index.ts +++ b/packages/api/src/ticketing/collection/services/jira/index.ts @@ -63,12 +63,5 @@ export class JiraService implements ICollectionService { } } - async addCollection( - commentData: DesunifyReturnType, - linkedUserId: string - ): Promise> { - return null; - - } } diff --git a/packages/api/src/ticketing/collection/types/index.ts b/packages/api/src/ticketing/collection/types/index.ts index 894240e42..812aca6e3 100644 --- a/packages/api/src/ticketing/collection/types/index.ts +++ b/packages/api/src/ticketing/collection/types/index.ts @@ -12,10 +12,6 @@ export interface ICollectionService { custom_properties?: string[], ): Promise>; - addCollection( - collectionData: DesunifyReturnType, - linkedUserId: string, - ): Promise>; } export interface ICollectionMapper { From f2404a214b78f660eb27a6de4ed59cb73c43a710 Mon Sep 17 00:00:00 2001 From: mit-27 Date: Tue, 7 May 2024 02:42:28 -0400 Subject: [PATCH 07/14] =?UTF-8?q?=F0=9F=90=9B=20Add=20gitlab/tag=20and=20f?= =?UTF-8?q?ix=20gitlab/collection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../services/gitlab/gitlab.service.ts | 7 +- .../collection/services/gitlab/index.ts | 22 +++++- .../ticketing/tag/services/gitlab/index.ts | 70 +++++++++++++++++++ .../ticketing/tag/services/gitlab/mappers.ts | 48 +++++++++++++ .../ticketing/tag/services/gitlab/types.ts | 33 +++++++++ packages/api/src/ticketing/tag/tag.module.ts | 2 + .../src/ticketing/tag/types/mappingsTypes.ts | 18 ++++- 7 files changed, 193 insertions(+), 7 deletions(-) create mode 100644 packages/api/src/ticketing/tag/services/gitlab/index.ts create mode 100644 packages/api/src/ticketing/tag/services/gitlab/mappers.ts create mode 100644 packages/api/src/ticketing/tag/services/gitlab/types.ts diff --git a/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts b/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts index 9930bb6ee..67b60d3c6 100644 --- a/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts +++ b/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts @@ -80,6 +80,8 @@ export class GitlabConnectionService implements ITicketingConnectionService { 'OAuth credentials : gitlab ticketing ' + JSON.stringify(data), ); + // console.log("Gitlab Credentials : ", data) + let db_res; const connection_token = uuidv4(); @@ -153,6 +155,7 @@ export class GitlabConnectionService implements ITicketingConnectionService { }, ); const data: GitlabOAuthResponse = res.data; + // console.log("Gitlab Credentials (In refresh) : ", data) await this.prisma.connections.update({ where: { id_connection: connectionId, @@ -165,9 +168,9 @@ export class GitlabConnectionService implements ITicketingConnectionService { ), }, }); - this.logger.log('OAuth credentials updated : jira '); + this.logger.log('OAuth credentials updated : gitlab '); } catch (error) { - handleServiceError(error, this.logger, 'jira', Action.oauthRefresh); + handleServiceError(error, this.logger, 'gitlab', Action.oauthRefresh); } } } diff --git a/packages/api/src/ticketing/collection/services/gitlab/index.ts b/packages/api/src/ticketing/collection/services/gitlab/index.ts index 93bfdc38d..492093cf9 100644 --- a/packages/api/src/ticketing/collection/services/gitlab/index.ts +++ b/packages/api/src/ticketing/collection/services/gitlab/index.ts @@ -37,15 +37,33 @@ export class GitlabService implements ICollectionService { }, }); + // It fetches all project from gitlab + // const resp = await axios.get(`${connection.account_url}/projects`, { + // headers: { + // 'Content-Type': 'application/json', + // Authorization: `Bearer ${this.cryptoService.decrypt( + // connection.access_token, + // )}`, + // }, + // }); - const resp = await axios.get(`${connection.account_url}/projects`, { + const currentUser = await axios.get(`${connection.account_url}/user`, { headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${this.cryptoService.decrypt( connection.access_token, )}`, }, - }); + }) + + const resp = await axios.get(`${connection.account_url}/users/${currentUser.data.id}/projects`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }) this.logger.log(`Synced gitlab collections !`); diff --git a/packages/api/src/ticketing/tag/services/gitlab/index.ts b/packages/api/src/ticketing/tag/services/gitlab/index.ts new file mode 100644 index 000000000..5c2ef5760 --- /dev/null +++ b/packages/api/src/ticketing/tag/services/gitlab/index.ts @@ -0,0 +1,70 @@ +import { Injectable } from '@nestjs/common'; +import { LoggerService } from '@@core/logger/logger.service'; +import { PrismaService } from '@@core/prisma/prisma.service'; +import { EncryptionService } from '@@core/encryption/encryption.service'; +import { TicketingObject } from '@ticketing/@lib/@types'; +import { ApiResponse } from '@@core/utils/types'; +import axios from 'axios'; +import { ActionType, handleServiceError } from '@@core/utils/errors'; +import { ServiceRegistry } from '../registry.service'; +import { ITagService } from '@ticketing/tag/types'; +import { GitlabTagOutput } from './types'; + +@Injectable() +export class GitlabService implements ITagService { + constructor( + private prisma: PrismaService, + private logger: LoggerService, + private cryptoService: EncryptionService, + private registry: ServiceRegistry, + ) { + this.logger.setContext( + TicketingObject.tag.toUpperCase() + ':' + GitlabService.name, + ); + this.registry.registerService('gitlab', this); + } + + + // Here id_ticket ==> id_project + async syncTags( + linkedUserId: string, + id_project: string, + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'gitlab', + vertical: 'ticketing', + }, + }); + + + const resp = await axios.get(`${connection.account_url}/projects/${id_project}/repository/tags`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }); + this.logger.log(`Synced gitlab tags !`); + + + + return { + data: resp.data, + message: 'Gitlab tags retrieved', + statusCode: 200, + }; + } catch (error) { + handleServiceError( + error, + this.logger, + 'Gitlab', + TicketingObject.tag, + ActionType.GET, + ); + } + } +} diff --git a/packages/api/src/ticketing/tag/services/gitlab/mappers.ts b/packages/api/src/ticketing/tag/services/gitlab/mappers.ts new file mode 100644 index 000000000..0acee286d --- /dev/null +++ b/packages/api/src/ticketing/tag/services/gitlab/mappers.ts @@ -0,0 +1,48 @@ +import { ITagMapper } from '@ticketing/tag/types'; +import { GitlabTagInput, GitlabTagOutput } from './types'; +import { + UnifiedTagInput, + UnifiedTagOutput, +} from '@ticketing/tag/types/model.unified'; + +export class GitlabTagMapper implements ITagMapper { + desunify( + source: UnifiedTagInput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): GitlabTagInput { + return; + } + + unify( + source: GitlabTagOutput | GitlabTagOutput[], + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedTagOutput | UnifiedTagOutput[] { + // If the source is not an array, convert it to an array for mapping + const sourcesArray = Array.isArray(source) ? source : [source]; + + return sourcesArray.map((tag) => + this.mapSingleTagToUnified(tag, customFieldMappings), + ); + } + + private mapSingleTagToUnified( + tag: GitlabTagOutput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): UnifiedTagOutput { + const unifiedTag: UnifiedTagOutput = { + remote_id: String(tag.name), + name: tag.name, + }; + + return unifiedTag; + } +} diff --git a/packages/api/src/ticketing/tag/services/gitlab/types.ts b/packages/api/src/ticketing/tag/services/gitlab/types.ts new file mode 100644 index 000000000..99568cf55 --- /dev/null +++ b/packages/api/src/ticketing/tag/services/gitlab/types.ts @@ -0,0 +1,33 @@ +interface GitlabTag { + commit: Commit + release: Release + name: string + target: string + message: any + protected: boolean + created_at: string +} + +export interface Commit { + id: string + short_id: string + title: string + created_at: string + parent_ids: string[] + message: string + author_name: string + author_email: string + authored_date: string + committer_name: string + committer_email: string + committed_date: string +} + +export interface Release { + tag_name: string + description: string +} + + +export type GitlabTagInput = Partial; +export type GitlabTagOutput = GitlabTagInput; \ No newline at end of file diff --git a/packages/api/src/ticketing/tag/tag.module.ts b/packages/api/src/ticketing/tag/tag.module.ts index 1e2983fab..ed7a0ae20 100644 --- a/packages/api/src/ticketing/tag/tag.module.ts +++ b/packages/api/src/ticketing/tag/tag.module.ts @@ -1,3 +1,4 @@ +import { GitlabService } from './services/gitlab'; import { Module } from '@nestjs/common'; import { TagController } from './tag.controller'; import { SyncService } from './sync/sync.service'; @@ -38,6 +39,7 @@ import { GorgiasService } from './services/gorgias'; FrontService, JiraService, GorgiasService, + GitlabService, ], exports: [ SyncService, diff --git a/packages/api/src/ticketing/tag/types/mappingsTypes.ts b/packages/api/src/ticketing/tag/types/mappingsTypes.ts index 0e89c936a..d401c3378 100644 --- a/packages/api/src/ticketing/tag/types/mappingsTypes.ts +++ b/packages/api/src/ticketing/tag/types/mappingsTypes.ts @@ -1,3 +1,5 @@ +import { GitlabTagMapper } from '../services/gitlab/mappers'; +import { JiraTagMapper } from '../services/jira/mappers'; import { FrontTagMapper } from '../services/front/mappers'; import { GorgiasTagMapper } from '../services/gorgias/mappers'; import { ZendeskTagMapper } from '../services/zendesk/mappers'; @@ -6,17 +8,27 @@ const zendeskTagMapper = new ZendeskTagMapper(); const frontTagMapper = new FrontTagMapper(); const gorgiasTagMapper = new GorgiasTagMapper(); +const gitlabTagMapper = new GitlabTagMapper(); +const jiraTagMapper = new JiraTagMapper(); export const tagUnificationMapping = { zendesk: { unify: zendeskTagMapper.unify.bind(zendeskTagMapper), - desunify: zendeskTagMapper.desunify, + desunify: zendeskTagMapper.desunify.bind(zendeskTagMapper), }, front: { unify: frontTagMapper.unify.bind(frontTagMapper), - desunify: frontTagMapper.desunify, + desunify: frontTagMapper.desunify.bind(frontTagMapper), }, gorgias: { unify: gorgiasTagMapper.unify.bind(gorgiasTagMapper), - desunify: gorgiasTagMapper.desunify, + desunify: gorgiasTagMapper.desunify.bind(gorgiasTagMapper), + }, + gitlab: { + unify: gitlabTagMapper.unify.bind(gitlabTagMapper), + desunify: gitlabTagMapper.desunify.bind(gitlabTagMapper), + }, + jira: { + unify: jiraTagMapper.unify.bind(jiraTagMapper), + desunify: jiraTagMapper.desunify.bind(jiraTagMapper), }, }; From 3143f5cff77363e96fa5780d0795b2a7e17d9d24 Mon Sep 17 00:00:00 2001 From: mit-27 Date: Tue, 7 May 2024 03:48:08 -0400 Subject: [PATCH 08/14] =?UTF-8?q?=F0=9F=92=9A=20Fix=20build?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../@core/utils/types/original/original.ticketing.ts | 11 +++++++++-- .../api/src/ticketing/tag/services/gitlab/mappers.ts | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/api/src/@core/utils/types/original/original.ticketing.ts b/packages/api/src/@core/utils/types/original/original.ticketing.ts index f334bf131..951602da0 100644 --- a/packages/api/src/@core/utils/types/original/original.ticketing.ts +++ b/packages/api/src/@core/utils/types/original/original.ticketing.ts @@ -116,6 +116,10 @@ import { GitlabCollectionInput, GitlabCollectionOutput, } from '@ticketing/collection/services/gitlab/types'; +import { + GitlabTagInput, + GitlabTagOutput, +} from '@ticketing/tag/services/gitlab/types'; /* INPUT */ /* ticket */ @@ -155,7 +159,9 @@ export type OriginalTagInput = | ZendeskTagInput | FrontTagInput | GorgiasTagInput - | JiraTagInput; + | JiraTagInput + | GitlabTagInput; + /* team */ export type OriginalTeamInput = | ZendeskTeamInput @@ -214,7 +220,8 @@ export type OriginalTagOutput = | ZendeskTagOutput | FrontTagOutput | GorgiasTagOutput - | JiraTagOutput; + | JiraTagOutput + | GitlabTagOutput; /* team */ export type OriginalTeamOutput = diff --git a/packages/api/src/ticketing/tag/services/gitlab/mappers.ts b/packages/api/src/ticketing/tag/services/gitlab/mappers.ts index 0acee286d..8aef3582a 100644 --- a/packages/api/src/ticketing/tag/services/gitlab/mappers.ts +++ b/packages/api/src/ticketing/tag/services/gitlab/mappers.ts @@ -39,7 +39,7 @@ export class GitlabTagMapper implements ITagMapper { }[], ): UnifiedTagOutput { const unifiedTag: UnifiedTagOutput = { - remote_id: String(tag.name), + remote_id: tag.name, name: tag.name, }; From e3c2d16cf7e6874fe0fb515c647c7b6b1ef384ec Mon Sep 17 00:00:00 2001 From: mit-27 Date: Wed, 8 May 2024 00:01:36 -0400 Subject: [PATCH 09/14] =?UTF-8?q?=F0=9F=94=A5=20Remove=20gitlab/tag?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../types/original/original.ticketing.ts | 11 +-- .../ticketing/tag/services/gitlab/index.ts | 70 ------------------- .../ticketing/tag/services/gitlab/mappers.ts | 48 ------------- .../ticketing/tag/services/gitlab/types.ts | 33 --------- packages/api/src/ticketing/tag/tag.module.ts | 4 +- .../src/ticketing/tag/types/mappingsTypes.ts | 6 -- 6 files changed, 4 insertions(+), 168 deletions(-) delete mode 100644 packages/api/src/ticketing/tag/services/gitlab/index.ts delete mode 100644 packages/api/src/ticketing/tag/services/gitlab/mappers.ts delete mode 100644 packages/api/src/ticketing/tag/services/gitlab/types.ts diff --git a/packages/api/src/@core/utils/types/original/original.ticketing.ts b/packages/api/src/@core/utils/types/original/original.ticketing.ts index 951602da0..b000a15eb 100644 --- a/packages/api/src/@core/utils/types/original/original.ticketing.ts +++ b/packages/api/src/@core/utils/types/original/original.ticketing.ts @@ -116,10 +116,7 @@ import { GitlabCollectionInput, GitlabCollectionOutput, } from '@ticketing/collection/services/gitlab/types'; -import { - GitlabTagInput, - GitlabTagOutput, -} from '@ticketing/tag/services/gitlab/types'; + /* INPUT */ /* ticket */ @@ -159,8 +156,7 @@ export type OriginalTagInput = | ZendeskTagInput | FrontTagInput | GorgiasTagInput - | JiraTagInput - | GitlabTagInput; + | JiraTagInput; /* team */ export type OriginalTeamInput = @@ -220,8 +216,7 @@ export type OriginalTagOutput = | ZendeskTagOutput | FrontTagOutput | GorgiasTagOutput - | JiraTagOutput - | GitlabTagOutput; + | JiraTagOutput; /* team */ export type OriginalTeamOutput = diff --git a/packages/api/src/ticketing/tag/services/gitlab/index.ts b/packages/api/src/ticketing/tag/services/gitlab/index.ts deleted file mode 100644 index 5c2ef5760..000000000 --- a/packages/api/src/ticketing/tag/services/gitlab/index.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { LoggerService } from '@@core/logger/logger.service'; -import { PrismaService } from '@@core/prisma/prisma.service'; -import { EncryptionService } from '@@core/encryption/encryption.service'; -import { TicketingObject } from '@ticketing/@lib/@types'; -import { ApiResponse } from '@@core/utils/types'; -import axios from 'axios'; -import { ActionType, handleServiceError } from '@@core/utils/errors'; -import { ServiceRegistry } from '../registry.service'; -import { ITagService } from '@ticketing/tag/types'; -import { GitlabTagOutput } from './types'; - -@Injectable() -export class GitlabService implements ITagService { - constructor( - private prisma: PrismaService, - private logger: LoggerService, - private cryptoService: EncryptionService, - private registry: ServiceRegistry, - ) { - this.logger.setContext( - TicketingObject.tag.toUpperCase() + ':' + GitlabService.name, - ); - this.registry.registerService('gitlab', this); - } - - - // Here id_ticket ==> id_project - async syncTags( - linkedUserId: string, - id_project: string, - ): Promise> { - try { - const connection = await this.prisma.connections.findFirst({ - where: { - id_linked_user: linkedUserId, - provider_slug: 'gitlab', - vertical: 'ticketing', - }, - }); - - - const resp = await axios.get(`${connection.account_url}/projects/${id_project}/repository/tags`, { - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${this.cryptoService.decrypt( - connection.access_token, - )}`, - }, - }); - this.logger.log(`Synced gitlab tags !`); - - - - return { - data: resp.data, - message: 'Gitlab tags retrieved', - statusCode: 200, - }; - } catch (error) { - handleServiceError( - error, - this.logger, - 'Gitlab', - TicketingObject.tag, - ActionType.GET, - ); - } - } -} diff --git a/packages/api/src/ticketing/tag/services/gitlab/mappers.ts b/packages/api/src/ticketing/tag/services/gitlab/mappers.ts deleted file mode 100644 index 8aef3582a..000000000 --- a/packages/api/src/ticketing/tag/services/gitlab/mappers.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { ITagMapper } from '@ticketing/tag/types'; -import { GitlabTagInput, GitlabTagOutput } from './types'; -import { - UnifiedTagInput, - UnifiedTagOutput, -} from '@ticketing/tag/types/model.unified'; - -export class GitlabTagMapper implements ITagMapper { - desunify( - source: UnifiedTagInput, - customFieldMappings?: { - slug: string; - remote_id: string; - }[], - ): GitlabTagInput { - return; - } - - unify( - source: GitlabTagOutput | GitlabTagOutput[], - customFieldMappings?: { - slug: string; - remote_id: string; - }[], - ): UnifiedTagOutput | UnifiedTagOutput[] { - // If the source is not an array, convert it to an array for mapping - const sourcesArray = Array.isArray(source) ? source : [source]; - - return sourcesArray.map((tag) => - this.mapSingleTagToUnified(tag, customFieldMappings), - ); - } - - private mapSingleTagToUnified( - tag: GitlabTagOutput, - customFieldMappings?: { - slug: string; - remote_id: string; - }[], - ): UnifiedTagOutput { - const unifiedTag: UnifiedTagOutput = { - remote_id: tag.name, - name: tag.name, - }; - - return unifiedTag; - } -} diff --git a/packages/api/src/ticketing/tag/services/gitlab/types.ts b/packages/api/src/ticketing/tag/services/gitlab/types.ts deleted file mode 100644 index 99568cf55..000000000 --- a/packages/api/src/ticketing/tag/services/gitlab/types.ts +++ /dev/null @@ -1,33 +0,0 @@ -interface GitlabTag { - commit: Commit - release: Release - name: string - target: string - message: any - protected: boolean - created_at: string -} - -export interface Commit { - id: string - short_id: string - title: string - created_at: string - parent_ids: string[] - message: string - author_name: string - author_email: string - authored_date: string - committer_name: string - committer_email: string - committed_date: string -} - -export interface Release { - tag_name: string - description: string -} - - -export type GitlabTagInput = Partial; -export type GitlabTagOutput = GitlabTagInput; \ No newline at end of file diff --git a/packages/api/src/ticketing/tag/tag.module.ts b/packages/api/src/ticketing/tag/tag.module.ts index ed7a0ae20..07981bdd5 100644 --- a/packages/api/src/ticketing/tag/tag.module.ts +++ b/packages/api/src/ticketing/tag/tag.module.ts @@ -1,4 +1,3 @@ -import { GitlabService } from './services/gitlab'; import { Module } from '@nestjs/common'; import { TagController } from './tag.controller'; import { SyncService } from './sync/sync.service'; @@ -39,7 +38,6 @@ import { GorgiasService } from './services/gorgias'; FrontService, JiraService, GorgiasService, - GitlabService, ], exports: [ SyncService, @@ -50,4 +48,4 @@ import { GorgiasService } from './services/gorgias'; PrismaService, ], }) -export class TagModule {} +export class TagModule { } diff --git a/packages/api/src/ticketing/tag/types/mappingsTypes.ts b/packages/api/src/ticketing/tag/types/mappingsTypes.ts index d401c3378..7ee1b94f4 100644 --- a/packages/api/src/ticketing/tag/types/mappingsTypes.ts +++ b/packages/api/src/ticketing/tag/types/mappingsTypes.ts @@ -1,4 +1,3 @@ -import { GitlabTagMapper } from '../services/gitlab/mappers'; import { JiraTagMapper } from '../services/jira/mappers'; import { FrontTagMapper } from '../services/front/mappers'; import { GorgiasTagMapper } from '../services/gorgias/mappers'; @@ -8,7 +7,6 @@ const zendeskTagMapper = new ZendeskTagMapper(); const frontTagMapper = new FrontTagMapper(); const gorgiasTagMapper = new GorgiasTagMapper(); -const gitlabTagMapper = new GitlabTagMapper(); const jiraTagMapper = new JiraTagMapper(); export const tagUnificationMapping = { zendesk: { @@ -23,10 +21,6 @@ export const tagUnificationMapping = { unify: gorgiasTagMapper.unify.bind(gorgiasTagMapper), desunify: gorgiasTagMapper.desunify.bind(gorgiasTagMapper), }, - gitlab: { - unify: gitlabTagMapper.unify.bind(gitlabTagMapper), - desunify: gitlabTagMapper.desunify.bind(gitlabTagMapper), - }, jira: { unify: jiraTagMapper.unify.bind(jiraTagMapper), desunify: jiraTagMapper.desunify.bind(jiraTagMapper), From 6d88d1c6193970351b883371355052086d3f4f7b Mon Sep 17 00:00:00 2001 From: mit-27 Date: Wed, 8 May 2024 02:37:08 -0400 Subject: [PATCH 10/14] =?UTF-8?q?=E2=9E=95=20Add=20gitlab/ticket?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../types/original/original.ticketing.ts | 13 +- .../ticketing/ticket/services/gitlab/index.ts | 106 +++++++++++++++ .../ticket/services/gitlab/mappers.ts | 125 ++++++++++++++++++ .../ticketing/ticket/services/gitlab/types.ts | 82 ++++++++++++ .../api/src/ticketing/ticket/ticket.module.ts | 2 + .../ticketing/ticket/types/mappingsTypes.ts | 22 ++- packages/shared/src/enum.ts | 1 + packages/shared/src/providers.ts | 2 +- 8 files changed, 345 insertions(+), 8 deletions(-) create mode 100644 packages/api/src/ticketing/ticket/services/gitlab/index.ts create mode 100644 packages/api/src/ticketing/ticket/services/gitlab/mappers.ts create mode 100644 packages/api/src/ticketing/ticket/services/gitlab/types.ts diff --git a/packages/api/src/@core/utils/types/original/original.ticketing.ts b/packages/api/src/@core/utils/types/original/original.ticketing.ts index b000a15eb..e31d259a5 100644 --- a/packages/api/src/@core/utils/types/original/original.ticketing.ts +++ b/packages/api/src/@core/utils/types/original/original.ticketing.ts @@ -1,4 +1,5 @@ + import { FrontAccountInput, FrontAccountOutput, @@ -116,6 +117,10 @@ import { GitlabCollectionInput, GitlabCollectionOutput, } from '@ticketing/collection/services/gitlab/types'; +import { + GitlabTicketInput, + GitlabTicketOutput, +} from '@ticketing/ticket/services/gitlab/types'; /* INPUT */ @@ -126,7 +131,8 @@ export type OriginalTicketInput = | GithubTicketInput | HubspotTicketInput | GorgiasTicketInput - | JiraTicketInput; + | JiraTicketInput + | GitlabTicketInput; //| JiraServiceMgmtTicketInput; /* comment */ @@ -189,7 +195,8 @@ export type OriginalTicketOutput = | GithubTicketOutput | HubspotTicketOutput | GorgiasTicketOutput - | JiraTicketOutput; + | JiraTicketOutput + | GitlabTicketOutput; /* comment */ export type OriginalCommentOutput = @@ -249,3 +256,5 @@ export type TicketingObjectOutput = | OriginalCollectionOutput; + + diff --git a/packages/api/src/ticketing/ticket/services/gitlab/index.ts b/packages/api/src/ticketing/ticket/services/gitlab/index.ts new file mode 100644 index 000000000..36d2b8341 --- /dev/null +++ b/packages/api/src/ticketing/ticket/services/gitlab/index.ts @@ -0,0 +1,106 @@ +import { Injectable } from '@nestjs/common'; +import { LoggerService } from '@@core/logger/logger.service'; +import { PrismaService } from '@@core/prisma/prisma.service'; +import { EncryptionService } from '@@core/encryption/encryption.service'; +import { TicketingObject } from '@ticketing/@lib/@types'; +import { ITicketService } from '@ticketing/ticket/types'; +import { ApiResponse } from '@@core/utils/types'; +import axios from 'axios'; +import { ActionType, handleServiceError } from '@@core/utils/errors'; +import { ServiceRegistry } from '../registry.service'; +import { GitlabTicketInput, GitlabTicketOutput } from './types'; + + +@Injectable() +export class GitlabService implements ITicketService { + constructor( + private prisma: PrismaService, + private logger: LoggerService, + private cryptoService: EncryptionService, + private registry: ServiceRegistry, + ) { + this.logger.setContext( + TicketingObject.ticket.toUpperCase() + ':' + GitlabService.name, + ); + this.registry.registerService('gitlab', this); + } + async addTicket( + ticketData: GitlabTicketInput, + linkedUserId: string, + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'github', + vertical: 'ticketing', + }, + }); + const dataBody = ticketData; + + const resp = await axios.post( + `${connection.account_url}/projects/${ticketData.project_id}/issues`, + JSON.stringify(dataBody), + { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }, + ); + return { + data: resp.data, + message: 'Gitlab ticket created', + statusCode: 201, + }; + } catch (error) { + handleServiceError( + error, + this.logger, + 'Gitlab', + TicketingObject.ticket, + ActionType.POST, + ); + } + } + async syncTickets( + linkedUserId: string, + custom_properties?: string[], + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'github', + vertical: 'ticketing', + }, + }); + + const resp = await axios.get(`${connection.account_url}/issues?scope=created_by_me&scope=assigned_to_me`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }); + this.logger.log(`Synced gitlab tickets !`); + + return { + data: resp.data, + message: 'Gitlab tickets retrieved', + statusCode: 200, + }; + } catch (error) { + handleServiceError( + error, + this.logger, + 'Gitlab', + TicketingObject.ticket, + ActionType.GET, + ); + } + } +} diff --git a/packages/api/src/ticketing/ticket/services/gitlab/mappers.ts b/packages/api/src/ticketing/ticket/services/gitlab/mappers.ts new file mode 100644 index 000000000..5dbc6cbe6 --- /dev/null +++ b/packages/api/src/ticketing/ticket/services/gitlab/mappers.ts @@ -0,0 +1,125 @@ +import { ITicketMapper } from '@ticketing/ticket/types'; +import { GitlabTicketOutput, GitlabTicketInput } from './types'; +import { + UnifiedTicketInput, + UnifiedTicketOutput, +} from '@ticketing/ticket/types/model.unified'; +import { Utils } from '@ticketing/@lib/@utils'; + +export class GitlabTicketMapper implements ITicketMapper { + private readonly utils: Utils; + + constructor() { + this.utils = new Utils(); + } + + async desunify( + source: UnifiedTicketInput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): Promise { + const result: GitlabTicketInput = { + title: source.name, + description: source.description ? source.description : '', + project_id: Number(source.project_id) + }; + + if (source.status) { + result.type = source.status === "OPEN" ? "opened" : "closed"; + } + + if (source.assigned_to && source.assigned_to.length > 0) { + const data = await this.utils.getAsigneeRemoteIdFromUserUuid( + source.assigned_to[0], + ); + result.assignee = { + id: Number(data), + }; + } + + if (source.tags) { + result.labels = source.tags ? source.tags : [] + } + + // TODO - Custom fields mapping + // if (customFieldMappings && source.field_mappings) { + // result.meta = {}; // Ensure meta exists + // for (const [k, v] of Object.entries(source.field_mappings)) { + // const mapping = customFieldMappings.find( + // (mapping) => mapping.slug === k, + // ); + // if (mapping) { + // result.meta[mapping.remote_id] = v; + // } + // } + // } + + return result; + } + + async unify( + source: GitlabTicketOutput | GitlabTicketOutput[], + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): Promise { + const sourcesArray = Array.isArray(source) ? source : [source]; + return Promise.all( + sourcesArray.map(async (ticket) => + this.mapSingleTicketToUnified(ticket, customFieldMappings), + ), + ); + } + + private async mapSingleTicketToUnified( + ticket: GitlabTicketOutput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): Promise { + const field_mappings: { [key: string]: any } = {}; + if (customFieldMappings) { + for (const mapping of customFieldMappings) { + field_mappings[mapping.slug] = ticket[mapping.remote_id]; + } + } + + let opts: any; + if (ticket.type) { + opts.type = ticket.type === "opened" ? "OPEN" : "CLOSED" + } + + if (ticket.assignee) { + //fetch the right assignee uuid from remote id + const user_id = await this.utils.getUserUuidFromRemoteId( + String(ticket.assignee), + 'gitlab', + ); + if (user_id) { + opts = { assigned_to: [user_id] }; + } + } + + + + const unifiedTicket: UnifiedTicketOutput = { + remote_id: String(ticket.id), + name: ticket.title, + description: ticket.description ? ticket.description : '', + due_date: new Date(ticket.created_at), + project_id: String(ticket.project_id), + tags: ticket.labels ? ticket.labels : [], + field_mappings, + ...opts + + } + + return unifiedTicket; + + + } +} diff --git a/packages/api/src/ticketing/ticket/services/gitlab/types.ts b/packages/api/src/ticketing/ticket/services/gitlab/types.ts new file mode 100644 index 000000000..ad2e556ca --- /dev/null +++ b/packages/api/src/ticketing/ticket/services/gitlab/types.ts @@ -0,0 +1,82 @@ +interface GitlabTicket { + project_id: number + id: number + created_at: string + iid: number + title: string + state: string + assignees: any[] + weight: any + epic: Epic + health_status: string + assignee: any + type: string + labels: string[] + upvotes: number + downvotes: number + merge_requests_count: number + author: Author + description: any + updated_at: string + closed_at: any + closed_by: any + milestone: any + subscribed: boolean + user_notes_count: number + due_date: any + web_url: string + references: References + time_stats: TimeStats + confidential: boolean + discussion_locked: boolean + issue_type: string + severity: string + _links: Links + task_completion_status: TaskCompletionStatus +} + +interface Epic { + id: number + iid: number + title: string + url: string + group_id: number +} + +interface Author { + name: string + avatar_url: any + state: string + web_url: string + id: number + username: string +} + +interface References { + short: string + relative: string + full: string +} + +interface TimeStats { + time_estimate: number + total_time_spent: number + human_time_estimate: any + human_total_time_spent: any +} + +interface Links { + self: string + notes: string + award_emoji: string + project: string + closed_as_duplicate_of: string +} + +interface TaskCompletionStatus { + count: number + completed_count: number +} + +export type GitlabTicketInput = Partial; +export type GitlabTicketOutput = GitlabTicketInput; diff --git a/packages/api/src/ticketing/ticket/ticket.module.ts b/packages/api/src/ticketing/ticket/ticket.module.ts index 22195516f..08f1c02fd 100644 --- a/packages/api/src/ticketing/ticket/ticket.module.ts +++ b/packages/api/src/ticketing/ticket/ticket.module.ts @@ -1,3 +1,4 @@ +import { GitlabService } from './services/gitlab'; import { Module } from '@nestjs/common'; import { TicketController } from './ticket.controller'; import { TicketService } from './services/ticket.service'; @@ -42,6 +43,7 @@ import { GorgiasService } from './services/gorgias'; GithubService, JiraService, GorgiasService, + GitlabService, ], exports: [ SyncService, diff --git a/packages/api/src/ticketing/ticket/types/mappingsTypes.ts b/packages/api/src/ticketing/ticket/types/mappingsTypes.ts index e4819f66a..66d7908e0 100644 --- a/packages/api/src/ticketing/ticket/types/mappingsTypes.ts +++ b/packages/api/src/ticketing/ticket/types/mappingsTypes.ts @@ -1,3 +1,5 @@ +import { GitlabTicketMapper } from '../services/gitlab/mappers'; +import { JiraTicketMapper } from '../services/jira/mappers'; import { FrontTicketMapper } from '../services/front/mappers'; import { GithubTicketMapper } from '../services/github/mappers'; import { GorgiasTicketMapper } from '../services/gorgias/mappers'; @@ -10,25 +12,35 @@ const githubTicketMapper = new GithubTicketMapper(); const hubspotTicketMapper = new HubspotTicketMapper(); const gorgiasTicketMapper = new GorgiasTicketMapper(); +const gitlabTicketMapper = new GitlabTicketMapper(); +const jiraTicketMapper = new JiraTicketMapper(); export const ticketUnificationMapping = { zendesk: { unify: zendeskTicketMapper.unify.bind(zendeskTicketMapper), - desunify: zendeskTicketMapper.desunify, + desunify: zendeskTicketMapper.desunify.bind(zendeskTicketMapper), }, front: { unify: frontTicketMapper.unify.bind(frontTicketMapper), - desunify: frontTicketMapper.desunify, + desunify: frontTicketMapper.desunify.bind(frontTicketMapper), }, github: { unify: githubTicketMapper.unify.bind(githubTicketMapper), - desunify: githubTicketMapper.desunify, + desunify: githubTicketMapper.desunify.bind(githubTicketMapper), }, hubspot: { unify: hubspotTicketMapper.unify.bind(hubspotTicketMapper), - desunify: hubspotTicketMapper.desunify, + desunify: hubspotTicketMapper.desunify.bind(hubspotTicketMapper), }, gorgias: { unify: gorgiasTicketMapper.unify.bind(gorgiasTicketMapper), - desunify: gorgiasTicketMapper.desunify, + desunify: gorgiasTicketMapper.desunify.bind(gorgiasTicketMapper), + }, + gitlab: { + unify: gitlabTicketMapper.unify.bind(gitlabTicketMapper), + desunify: gitlabTicketMapper.desunify.bind(gitlabTicketMapper), + }, + jira: { + unify: jiraTicketMapper.unify.bind(jiraTicketMapper), + desunify: jiraTicketMapper.desunify.bind(jiraTicketMapper), }, }; diff --git a/packages/shared/src/enum.ts b/packages/shared/src/enum.ts index 97ac5c7a3..9246584f0 100644 --- a/packages/shared/src/enum.ts +++ b/packages/shared/src/enum.ts @@ -23,6 +23,7 @@ export enum TicketingProviders { JIRA = 'jira', GORGIAS = 'gorgias', GITLAB = 'gitlab', + HUBSPOT = 'hubspot', } export enum AccountingProviders { diff --git a/packages/shared/src/providers.ts b/packages/shared/src/providers.ts index 3c38156be..5892f9b59 100644 --- a/packages/shared/src/providers.ts +++ b/packages/shared/src/providers.ts @@ -7,7 +7,7 @@ export const CRM_PROVIDERS = ['zoho', 'zendesk', 'hubspot', 'pipedrive', 'attio' export const HRIS_PROVIDERS = ['']; export const ATS_PROVIDERS = ['']; export const ACCOUNTING_PROVIDERS = ['']; -export const TICKETING_PROVIDERS = ['zendesk', 'front', 'github', 'jira', 'gorgias', 'gitlab']; +export const TICKETING_PROVIDERS = ['zendesk', 'front', 'github', 'jira', 'gorgias', 'gitlab', 'hubspot']; export const MARKETINGAUTOMATION_PROVIDERS = ['']; export const FILESTORAGE_PROVIDERS = ['']; From d3a0199df60656809a29e2bf0c01a940281ae0d3 Mon Sep 17 00:00:00 2001 From: mit-27 Date: Thu, 9 May 2024 03:21:53 -0400 Subject: [PATCH 11/14] =?UTF-8?q?=F0=9F=90=9B=20Add=20gitlab/comment=20and?= =?UTF-8?q?=20fix=20bugs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../types/original/original.ticketing.ts | 10 +- .../api/src/ticketing/@lib/@utils/index.ts | 58 ++++++ .../src/ticketing/comment/comment.module.ts | 2 + .../comment/services/gitlab/index.ts | 177 ++++++++++++++++++ .../comment/services/gitlab/mappers.ts | 123 ++++++++++++ .../comment/services/gitlab/types.ts | 31 +++ .../ticketing/comment/sync/sync.service.ts | 1 + .../ticketing/comment/types/mappingsTypes.ts | 19 +- .../ticket/services/gitlab/mappers.ts | 21 ++- .../src/ticketing/ticket/sync/sync.service.ts | 3 + 10 files changed, 438 insertions(+), 7 deletions(-) create mode 100644 packages/api/src/ticketing/comment/services/gitlab/index.ts create mode 100644 packages/api/src/ticketing/comment/services/gitlab/mappers.ts create mode 100644 packages/api/src/ticketing/comment/services/gitlab/types.ts diff --git a/packages/api/src/@core/utils/types/original/original.ticketing.ts b/packages/api/src/@core/utils/types/original/original.ticketing.ts index e31d259a5..a67434042 100644 --- a/packages/api/src/@core/utils/types/original/original.ticketing.ts +++ b/packages/api/src/@core/utils/types/original/original.ticketing.ts @@ -121,6 +121,10 @@ import { GitlabTicketInput, GitlabTicketOutput, } from '@ticketing/ticket/services/gitlab/types'; +import { + GitlabCommentInput, + GitlabCommentOutput +} from '@ticketing/comment/services/gitlab/types' /* INPUT */ @@ -140,7 +144,8 @@ export type OriginalCommentInput = | ZendeskCommentInput | FrontCommentInput | GorgiasCommentInput - | JiraCommentInput; + | JiraCommentInput + | GitlabCommentInput; //| JiraCommentServiceMgmtInput; /* user */ export type OriginalUserInput = @@ -203,7 +208,8 @@ export type OriginalCommentOutput = | ZendeskCommentOutput | FrontCommentOutput | GorgiasCommentOutput - | JiraCommentOutput; + | JiraCommentOutput + | GitlabCommentOutput; /* user */ export type OriginalUserOutput = | ZendeskUserOutput diff --git a/packages/api/src/ticketing/@lib/@utils/index.ts b/packages/api/src/ticketing/@lib/@utils/index.ts index 0e243277e..0be052932 100644 --- a/packages/api/src/ticketing/@lib/@utils/index.ts +++ b/packages/api/src/ticketing/@lib/@utils/index.ts @@ -103,4 +103,62 @@ export class Utils { throw new Error(error); } } + + async getCollectionUuidFromRemoteId(remote_id: string, remote_platform: string) { + try { + const res = await this.prisma.tcg_collections.findFirst({ + where: { + remote_id: remote_id, + remote_platform: remote_platform, + }, + }); + if (!res) return; + return res.id_tcg_collection; + } catch (error) { + throw new Error(error); + } + } + + async getCollectionRemoteIdFromUuid(uuid: string) { + try { + const res = await this.prisma.tcg_collections.findFirst({ + where: { + id_tcg_collection: uuid, + }, + }); + if (!res) throw new Error(`tcg_contact not found for uuid ${uuid}`); + return res.remote_id; + } catch (error) { + throw new Error(error); + } + } + + async getTicketUuidFromRemoteId(remote_id: string, remote_platform: string) { + try { + const res = await this.prisma.tcg_tickets.findFirst({ + where: { + remote_id: remote_id, + remote_platform: remote_platform, + }, + }); + if (!res) return; + return res.id_tcg_ticket; + } catch (error) { + throw new Error(error); + } + } + + async getTicketRemoteIdFromUuid(uuid: string) { + try { + const res = await this.prisma.tcg_tickets.findFirst({ + where: { + id_tcg_ticket: uuid, + }, + }); + if (!res) throw new Error(`tcg_contact not found for uuid ${uuid}`); + return res.remote_id; + } catch (error) { + throw new Error(error); + } + } } diff --git a/packages/api/src/ticketing/comment/comment.module.ts b/packages/api/src/ticketing/comment/comment.module.ts index 42df81c12..332e08723 100644 --- a/packages/api/src/ticketing/comment/comment.module.ts +++ b/packages/api/src/ticketing/comment/comment.module.ts @@ -1,3 +1,4 @@ +import { GitlabService } from './services/gitlab'; import { Module } from '@nestjs/common'; import { SyncService } from './sync/sync.service'; import { WebhookService } from '@@core/webhook/webhook.service'; @@ -38,6 +39,7 @@ import { GorgiasService } from './services/gorgias'; FrontService, JiraService, GorgiasService, + GitlabService, ], exports: [ SyncService, diff --git a/packages/api/src/ticketing/comment/services/gitlab/index.ts b/packages/api/src/ticketing/comment/services/gitlab/index.ts new file mode 100644 index 000000000..80bfa23c9 --- /dev/null +++ b/packages/api/src/ticketing/comment/services/gitlab/index.ts @@ -0,0 +1,177 @@ +import { Injectable } from '@nestjs/common'; +import { LoggerService } from '@@core/logger/logger.service'; +import { PrismaService } from '@@core/prisma/prisma.service'; +import { EncryptionService } from '@@core/encryption/encryption.service'; +import { ApiResponse } from '@@core/utils/types'; +import axios from 'axios'; +import { ActionType, handleServiceError } from '@@core/utils/errors'; +import { ICommentService } from '@ticketing/comment/types'; +import { TicketingObject } from '@ticketing/@lib/@types'; +import { GitlabCommentInput, GitlabCommentOutput } from './types'; +import { ServiceRegistry } from '../registry.service'; +import { Utils } from '@ticketing/@lib/@utils';; +import * as fs from 'fs'; + +@Injectable() +export class GitlabService implements ICommentService { + private readonly utils: Utils; + + constructor( + private prisma: PrismaService, + private logger: LoggerService, + private cryptoService: EncryptionService, + private registry: ServiceRegistry, + ) { + this.logger.setContext( + TicketingObject.comment.toUpperCase() + ':' + GitlabService.name, + ); + this.registry.registerService('gitlab', this); + this.utils = new Utils(); + } + + async addComment( + commentData: GitlabCommentInput, + linkedUserId: string, + remoteIdTicket: string, + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'gitlab', + vertical: 'ticketing', + }, + }); + + let uploads = []; + const uuids = commentData.attachment as any[]; + if (uuids && uuids.length > 0) { + const attachmentPromises = uuids.map(async (uuid) => { + const res = await this.prisma.tcg_attachments.findUnique({ + where: { + id_tcg_attachment: uuid.extra, + }, + }); + if (!res) { + throw new Error(`tcg_attachment not found for uuid ${uuid}`); + } + // Assuming you want to construct the right binary attachment here + // For now, we'll just return the URL + const stats = fs.statSync(res.file_url); + return { + url: res.file_url, + name: res.file_name, + size: stats.size, + content_type: 'application/pdf', //todo + }; + }); + uploads = await Promise.all(attachmentPromises); + } + + // Assuming you want to modify the comment object here + // For now, we'll just add the uploads to the comment + const data = { + ...commentData, + attachments: uploads, + }; + + const ticket = await this.prisma.tcg_tickets.findUnique({ + where: { + id_tcg_ticket: remoteIdTicket, + }, + select: { + collections: true + }, + }); + + const remote_project_id = await this.utils.getCollectionRemoteIdFromUuid(ticket.collections[0]) + + + + + + + const resp = await axios.post( + `${connection.account_url}/projects/${remote_project_id}/issues/${remoteIdTicket}/notes`, + JSON.stringify(data), + { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }, + ); + + return { + data: resp.data, + message: 'Gitlab comment created', + statusCode: 201, + }; + } catch (error) { + handleServiceError( + error, + this.logger, + 'Gitlab', + TicketingObject.comment, + ActionType.POST, + ); + } + } + async syncComments( + linkedUserId: string, + id_ticket: string, + ): Promise> { + try { + const connection = await this.prisma.connections.findFirst({ + where: { + id_linked_user: linkedUserId, + provider_slug: 'gitlab', + vertical: 'ticketing', + }, + }); + //retrieve ticket remote id so we can retrieve the comments in the original software + const ticket = await this.prisma.tcg_tickets.findUnique({ + where: { + id_tcg_ticket: id_ticket, + }, + select: { + remote_id: true, + collections: true + }, + }); + + // retrieve the remote_id of project from collections + const remote_project_id = await this.utils.getCollectionRemoteIdFromUuid(ticket.collections[0]) + + + const resp = await axios.get( + `${connection.account_url}/projects/${remote_project_id}/issues/${ticket.remote_id}/notes`, + { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.cryptoService.decrypt( + connection.access_token, + )}`, + }, + }, + ); + this.logger.log(`Synced gitlab comments !`); + + return { + data: resp.data._results, + message: 'Gitlab comments retrieved', + statusCode: 200, + }; + } catch (error) { + handleServiceError( + error, + this.logger, + 'Gitlab', + TicketingObject.comment, + ActionType.GET, + ); + } + } +} diff --git a/packages/api/src/ticketing/comment/services/gitlab/mappers.ts b/packages/api/src/ticketing/comment/services/gitlab/mappers.ts new file mode 100644 index 000000000..72ee3df10 --- /dev/null +++ b/packages/api/src/ticketing/comment/services/gitlab/mappers.ts @@ -0,0 +1,123 @@ +import { ICommentMapper } from '@ticketing/comment/types'; +import { + UnifiedCommentInput, + UnifiedCommentOutput, +} from '@ticketing/comment/types/model.unified'; +import { GitlabCommentInput, GitlabCommentOutput } from './types'; +import { UnifiedAttachmentOutput } from '@ticketing/attachment/types/model.unified'; +import { TicketingObject } from '@ticketing/@lib/@types'; +import { unify } from '@@core/utils/unification/unify'; +import { OriginalAttachmentOutput } from '@@core/utils/types/original/original.ticketing'; +import { Utils } from '@ticketing/@lib/@utils';; + +export class GitlabCommentMapper implements ICommentMapper { + private readonly utils: Utils; + + constructor() { + this.utils = new Utils(); + } + + async desunify( + source: UnifiedCommentInput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): Promise { + + // project_id and issue_id will be extracted and used so We do not need to set user (author) field here + + // TODO - Add attachments attribute + + + const result: GitlabCommentInput = { + body: source.body, + internal: source.is_private || false, + + }; + return result; + } + + async unify( + source: GitlabCommentOutput | GitlabCommentOutput[], + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): Promise { + if (!Array.isArray(source)) { + return await this.mapSingleCommentToUnified(source, customFieldMappings); + } + return Promise.all( + source.map((comment) => + this.mapSingleCommentToUnified(comment, customFieldMappings), + ), + ); + } + + private async mapSingleCommentToUnified( + comment: GitlabCommentOutput, + customFieldMappings?: { + slug: string; + remote_id: string; + }[], + ): Promise { + let opts; + + // TODO - Unify attachment attribute + if (comment.attachment && comment.attachment.length > 0) { + const unifiedObject = (await unify({ + sourceObject: comment.attachment, + targetType: TicketingObject.attachment, + providerName: 'gitlab', + vertical: 'ticketing', + customFieldMappings: [], + })) as UnifiedAttachmentOutput[]; + + opts = { ...opts, attachments: unifiedObject }; + } + + + if (comment.author.id) { + const user_id = await this.utils.getUserUuidFromRemoteId( + String(comment.author.id), + 'gitlab', + ); + opts.user_id = user_id; + } + + // if (user_id) { + // opts = { user_id: user_id, creator_type: 'user' }; + // } else { + // const contact_id = await this.utils.getContactUuidFromRemoteId( + // String(comment.sender.id), + // 'gorgias', + // ); + // if (contact_id) { + // opts = { creator_type: 'CONTACT', contact_id: contact_id }; + // } + // } + // } + if (comment.noteable_id) { + const ticket_id = await this.utils.getTicketUuidFromRemoteId( + String(comment.noteable_id), + 'gitlab' + ) + opts.ticket_id = ticket_id; + } + + const res: UnifiedCommentOutput = { + remote_id: String(comment.id), + body: comment.body ? comment.body : '', + is_private: comment.internal, + creator_type: 'USER', + ...opts + }; + + return { + remote_id: String(comment.id), + ...res + }; + + } +} diff --git a/packages/api/src/ticketing/comment/services/gitlab/types.ts b/packages/api/src/ticketing/comment/services/gitlab/types.ts new file mode 100644 index 000000000..2316ee065 --- /dev/null +++ b/packages/api/src/ticketing/comment/services/gitlab/types.ts @@ -0,0 +1,31 @@ +interface GitlabComment { + id: number + body: string + attachment: any + author: Author + created_at: string + updated_at: string + system: boolean + noteable_id: number + noteable_type: string + project_id: number + noteable_iid: number + resolvable: boolean + confidential: boolean + internal: boolean + imported: boolean + imported_from: string +} + +interface Author { + id: number + username: string + email: string + name: string + state: string + created_at: string +} + + +export type GitlabCommentInput = Partial; +export type GitlabCommentOutput = GitlabCommentInput; \ No newline at end of file diff --git a/packages/api/src/ticketing/comment/sync/sync.service.ts b/packages/api/src/ticketing/comment/sync/sync.service.ts index 9fe245d12..d180fb8df 100644 --- a/packages/api/src/ticketing/comment/sync/sync.service.ts +++ b/packages/api/src/ticketing/comment/sync/sync.service.ts @@ -298,6 +298,7 @@ export class SyncService implements OnModuleInit { if (comment.creator_type) { data = { ...data, creator_type: comment.creator_type }; } + data = { ...data, ...opts }; const res = await this.prisma.tcg_comments.create({ diff --git a/packages/api/src/ticketing/comment/types/mappingsTypes.ts b/packages/api/src/ticketing/comment/types/mappingsTypes.ts index 9b996cee6..f21d5948a 100644 --- a/packages/api/src/ticketing/comment/types/mappingsTypes.ts +++ b/packages/api/src/ticketing/comment/types/mappingsTypes.ts @@ -1,3 +1,5 @@ +import { GitlabCommentMapper } from '../services/gitlab/mappers'; +import { JiraCommentMapper } from '../services/jira/mappers'; import { FrontCommentMapper } from '../services/front/mappers'; import { GorgiasCommentMapper } from '../services/gorgias/mappers'; import { ZendeskCommentMapper } from '../services/zendesk/mappers'; @@ -6,17 +8,28 @@ const zendeskCommentMapper = new ZendeskCommentMapper(); const frontCommentMapper = new FrontCommentMapper(); const gorgiasCommentMapper = new GorgiasCommentMapper(); +const gitlabCommentMapper = new GitlabCommentMapper(); +const jiraCommentMapper = new JiraCommentMapper(); + export const commentUnificationMapping = { zendesk: { unify: zendeskCommentMapper.unify.bind(zendeskCommentMapper), - desunify: zendeskCommentMapper.desunify, + desunify: zendeskCommentMapper.desunify.bind(zendeskCommentMapper), }, front: { unify: frontCommentMapper.unify.bind(frontCommentMapper), - desunify: frontCommentMapper.desunify, + desunify: frontCommentMapper.desunify.bind(frontCommentMapper), }, gorgias: { unify: gorgiasCommentMapper.unify.bind(gorgiasCommentMapper), - desunify: gorgiasCommentMapper.desunify, + desunify: gorgiasCommentMapper.desunify.bind(gorgiasCommentMapper), + }, + gitlab: { + unify: gitlabCommentMapper.unify.bind(gitlabCommentMapper), + desunify: gitlabCommentMapper.desunify.bind(gitlabCommentMapper), + }, + jira: { + unify: jiraCommentMapper.unify.bind(jiraCommentMapper), + desunify: jiraCommentMapper.desunify.bind(jiraCommentMapper), }, }; diff --git a/packages/api/src/ticketing/ticket/services/gitlab/mappers.ts b/packages/api/src/ticketing/ticket/services/gitlab/mappers.ts index 5dbc6cbe6..8008809ed 100644 --- a/packages/api/src/ticketing/ticket/services/gitlab/mappers.ts +++ b/packages/api/src/ticketing/ticket/services/gitlab/mappers.ts @@ -20,10 +20,18 @@ export class GitlabTicketMapper implements ITicketMapper { remote_id: string; }[], ): Promise { + + // TODO - Project_id should be mandatory field for gitlab provider + + const remote_project_id = await this.utils.getCollectionRemoteIdFromUuid(source.project_id); + + + + const result: GitlabTicketInput = { title: source.name, description: source.description ? source.description : '', - project_id: Number(source.project_id) + project_id: Number(remote_project_id) }; if (source.status) { @@ -104,6 +112,16 @@ export class GitlabTicketMapper implements ITicketMapper { } } + if (ticket.project_id) { + const tcg_collection_id = await this.utils.getCollectionUuidFromRemoteId( + String(ticket.project_id), + 'gitlab' + ); + if (tcg_collection_id) { + opts = { project_id: tcg_collection_id } + } + } + const unifiedTicket: UnifiedTicketOutput = { @@ -111,7 +129,6 @@ export class GitlabTicketMapper implements ITicketMapper { name: ticket.title, description: ticket.description ? ticket.description : '', due_date: new Date(ticket.created_at), - project_id: String(ticket.project_id), tags: ticket.labels ? ticket.labels : [], field_mappings, ...opts diff --git a/packages/api/src/ticketing/ticket/sync/sync.service.ts b/packages/api/src/ticketing/ticket/sync/sync.service.ts index 4a77008bc..9b7aeaf33 100644 --- a/packages/api/src/ticketing/ticket/sync/sync.service.ts +++ b/packages/api/src/ticketing/ticket/sync/sync.service.ts @@ -301,6 +301,9 @@ export class SyncService implements OnModuleInit { if (ticket.assigned_to) { data = { ...data, assigned_to: ticket.assigned_to }; } + if (ticket.project_id) { + data = { ...data, collections: [ticket.project_id] } + } /* parent_ticket: ticket.parent_ticket || 'd', */ From 7f12892303c59a088c290b91aa6c75ba18c19bcf Mon Sep 17 00:00:00 2001 From: mit-27 Date: Fri, 10 May 2024 12:04:45 -0400 Subject: [PATCH 12/14] =?UTF-8?q?=F0=9F=90=9B=20Fix=20bugs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../comment/services/gitlab/index.ts | 47 ++++++++++++++----- .../comment/services/gitlab/mappers.ts | 11 +++-- .../ticketing/comment/sync/sync.service.ts | 17 +++---- .../ticketing/ticket/services/gitlab/index.ts | 4 +- .../ticket/services/gitlab/mappers.ts | 6 +-- .../ticket/services/ticket.service.ts | 1 + .../src/ticketing/ticket/sync/sync.service.ts | 10 ++-- 7 files changed, 64 insertions(+), 32 deletions(-) diff --git a/packages/api/src/ticketing/comment/services/gitlab/index.ts b/packages/api/src/ticketing/comment/services/gitlab/index.ts index 80bfa23c9..e045cfb27 100644 --- a/packages/api/src/ticketing/comment/services/gitlab/index.ts +++ b/packages/api/src/ticketing/comment/services/gitlab/index.ts @@ -75,24 +75,38 @@ export class GitlabService implements ICommentService { attachments: uploads, }; - const ticket = await this.prisma.tcg_tickets.findUnique({ + const ticket = await this.prisma.tcg_tickets.findFirst({ where: { - id_tcg_ticket: remoteIdTicket, + remote_id: remoteIdTicket, + remote_platform: 'gitlab', }, select: { - collections: true - }, + collections: true, + id_tcg_ticket: true + } }); - const remote_project_id = await this.utils.getCollectionRemoteIdFromUuid(ticket.collections[0]) - - - + // const ticket = await this.prisma.tcg_tickets.findUnique({ + // where: { + // id_tcg_ticket: remoteIdTicket, + // }, + // select: { + // collections: true + // }, + // }); + const remote_project_id = await this.utils.getCollectionRemoteIdFromUuid(ticket.collections[0]); + // Retrieve the uuid of issue from remote_data + const remote_data = await this.prisma.remote_data.findFirst({ + where: { + ressource_owner_id: ticket.id_tcg_ticket, + }, + }); + const { iid } = JSON.parse(remote_data.data); const resp = await axios.post( - `${connection.account_url}/projects/${remote_project_id}/issues/${remoteIdTicket}/notes`, + `${connection.account_url}/projects/${remote_project_id}/issues/${iid}/notes`, JSON.stringify(data), { headers: { @@ -145,9 +159,19 @@ export class GitlabService implements ICommentService { // retrieve the remote_id of project from collections const remote_project_id = await this.utils.getCollectionRemoteIdFromUuid(ticket.collections[0]) + // Retrieve the uuid of issue from remote_data + const remote_data = await this.prisma.remote_data.findFirst({ + where: { + ressource_owner_id: id_ticket, + }, + }); + const { iid } = JSON.parse(remote_data.data); + + console.log("Requested URL : ", `${connection.account_url}/projects/${remote_project_id}/issues/${iid}/notes`) + const resp = await axios.get( - `${connection.account_url}/projects/${remote_project_id}/issues/${ticket.remote_id}/notes`, + `${connection.account_url}/projects/${remote_project_id}/issues/${iid}/notes`, { headers: { 'Content-Type': 'application/json', @@ -158,9 +182,10 @@ export class GitlabService implements ICommentService { }, ); this.logger.log(`Synced gitlab comments !`); + console.log(resp.data) return { - data: resp.data._results, + data: resp.data, message: 'Gitlab comments retrieved', statusCode: 200, }; diff --git a/packages/api/src/ticketing/comment/services/gitlab/mappers.ts b/packages/api/src/ticketing/comment/services/gitlab/mappers.ts index 72ee3df10..086bdec7c 100644 --- a/packages/api/src/ticketing/comment/services/gitlab/mappers.ts +++ b/packages/api/src/ticketing/comment/services/gitlab/mappers.ts @@ -83,7 +83,9 @@ export class GitlabCommentMapper implements ICommentMapper { String(comment.author.id), 'gitlab', ); - opts.user_id = user_id; + if (user_id) { + opts.user_id = user_id; + } } // if (user_id) { @@ -100,10 +102,13 @@ export class GitlabCommentMapper implements ICommentMapper { // } if (comment.noteable_id) { const ticket_id = await this.utils.getTicketUuidFromRemoteId( - String(comment.noteable_id), + String(comment.noteable_iid), 'gitlab' ) - opts.ticket_id = ticket_id; + if (ticket_id) { + opts.ticket_id = ticket_id; + + } } const res: UnifiedCommentOutput = { diff --git a/packages/api/src/ticketing/comment/sync/sync.service.ts b/packages/api/src/ticketing/comment/sync/sync.service.ts index d180fb8df..98f13c20a 100644 --- a/packages/api/src/ticketing/comment/sync/sync.service.ts +++ b/packages/api/src/ticketing/comment/sync/sync.service.ts @@ -60,7 +60,7 @@ export class SyncService implements OnModuleInit { } //function used by sync worker which populate our tcg_comments table //its role is to fetch all comments from providers 3rd parties and save the info inside our db - //@Cron('*/2 * * * *') // every 2 minutes (for testing) + // @Cron('*/2 * * * *') // every 2 minutes (for testing) @Cron('0 */8 * * *') // every 8 hours async syncComments(user_id?: string) { try { @@ -189,9 +189,9 @@ export class SyncService implements OnModuleInit { data: { id_event: uuidv4(), status: 'success', - type: 'ticketing.comment.synced', - method: 'SYNC', - url: '/sync', + type: 'ticketing.comment.pulled', + method: 'PULL', + url: '/pull', provider: integrationId, direction: '0', timestamp: new Date(), @@ -200,7 +200,7 @@ export class SyncService implements OnModuleInit { }); await this.webhook.handleWebhook( comments_data, - 'ticketing.comment.synced', + 'ticketing.comment.pulled', id_project, event.id_event, ); @@ -236,15 +236,16 @@ export class SyncService implements OnModuleInit { let unique_ticketing_comment_id: string; const opts = - comment.creator_type === 'contact' + (comment.creator_type === 'CONTACT' && comment.contact_id) ? { id_tcg_contact: comment.contact_id, } - : comment.creator_type === 'user' + : (comment.creator_type === 'USER' && comment.user_id) ? { id_tcg_user: comment.user_id, } - : {}; //case where nothing is passed for creator or a not authorized value; + : {}; + //case where nothing is passed for creator or a not authorized value; if (existingComment) { // Update the existing comment diff --git a/packages/api/src/ticketing/ticket/services/gitlab/index.ts b/packages/api/src/ticketing/ticket/services/gitlab/index.ts index 36d2b8341..b3552c9df 100644 --- a/packages/api/src/ticketing/ticket/services/gitlab/index.ts +++ b/packages/api/src/ticketing/ticket/services/gitlab/index.ts @@ -32,7 +32,7 @@ export class GitlabService implements ITicketService { const connection = await this.prisma.connections.findFirst({ where: { id_linked_user: linkedUserId, - provider_slug: 'github', + provider_slug: 'gitlab', vertical: 'ticketing', }, }); @@ -73,7 +73,7 @@ export class GitlabService implements ITicketService { const connection = await this.prisma.connections.findFirst({ where: { id_linked_user: linkedUserId, - provider_slug: 'github', + provider_slug: 'gitlab', vertical: 'ticketing', }, }); diff --git a/packages/api/src/ticketing/ticket/services/gitlab/mappers.ts b/packages/api/src/ticketing/ticket/services/gitlab/mappers.ts index 8008809ed..31adc9029 100644 --- a/packages/api/src/ticketing/ticket/services/gitlab/mappers.ts +++ b/packages/api/src/ticketing/ticket/services/gitlab/mappers.ts @@ -98,7 +98,7 @@ export class GitlabTicketMapper implements ITicketMapper { let opts: any; if (ticket.type) { - opts.type = ticket.type === "opened" ? "OPEN" : "CLOSED" + opts = { ...opts, type: ticket.type === "opened" ? "OPEN" : "CLOSED" } } if (ticket.assignee) { @@ -108,7 +108,7 @@ export class GitlabTicketMapper implements ITicketMapper { 'gitlab', ); if (user_id) { - opts = { assigned_to: [user_id] }; + opts = { ...opts, assigned_to: [user_id] }; } } @@ -118,7 +118,7 @@ export class GitlabTicketMapper implements ITicketMapper { 'gitlab' ); if (tcg_collection_id) { - opts = { project_id: tcg_collection_id } + opts = { ...opts, project_id: tcg_collection_id } } } diff --git a/packages/api/src/ticketing/ticket/services/ticket.service.ts b/packages/api/src/ticketing/ticket/services/ticket.service.ts index e1f819edf..ceeb62afc 100644 --- a/packages/api/src/ticketing/ticket/services/ticket.service.ts +++ b/packages/api/src/ticketing/ticket/services/ticket.service.ts @@ -468,6 +468,7 @@ export class TicketService { completed_at: ticket.completed_at || null, priority: ticket.priority || '', assigned_to: ticket.assigned_to || [], + collections: ticket.collections || [], field_mappings: field_mappings, }; }), diff --git a/packages/api/src/ticketing/ticket/sync/sync.service.ts b/packages/api/src/ticketing/ticket/sync/sync.service.ts index 9b7aeaf33..6cac7cf2a 100644 --- a/packages/api/src/ticketing/ticket/sync/sync.service.ts +++ b/packages/api/src/ticketing/ticket/sync/sync.service.ts @@ -60,7 +60,7 @@ export class SyncService implements OnModuleInit { } //function used by sync worker which populate our tcg_tickets table //its role is to fetch all contacts from providers 3rd parties and save the info inside our db - //@Cron('*/2 * * * *') // every 2 minutes (for testing) + // @Cron('*/2 * * * *') // every 2 minutes (for testing) @Cron('0 */8 * * *') // every 8 hours async syncTickets(user_id?: string) { try { @@ -178,9 +178,9 @@ export class SyncService implements OnModuleInit { data: { id_event: uuidv4(), status: 'success', - type: 'ticketing.ticket.synced', - method: 'SYNC', - url: '/sync', + type: 'ticketing.ticket.pulled', + method: 'PULL', + url: '/pull', provider: integrationId, direction: '0', timestamp: new Date(), @@ -190,7 +190,7 @@ export class SyncService implements OnModuleInit { await this.webhook.handleWebhook( tickets_data, - 'ticketing.ticket.synced', + 'ticketing.ticket.pulled', id_project, event.id_event, ); From 96d022be8444d6b648292532efef6553deb7845f Mon Sep 17 00:00:00 2001 From: mit-27 Date: Fri, 10 May 2024 15:51:56 -0400 Subject: [PATCH 13/14] =?UTF-8?q?=F0=9F=90=9B=20Add=20gitlab=20logo=20and?= =?UTF-8?q?=20fix=20displaying=20of=20logos=20in=20connection=20and=20even?= =?UTF-8?q?t=20table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client-ts/src/components/Connection/columns.tsx | 9 ++------- apps/client-ts/src/components/Events/columns.tsx | 9 ++------- packages/shared/src/utils.ts | 2 +- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/apps/client-ts/src/components/Connection/columns.tsx b/apps/client-ts/src/components/Connection/columns.tsx index 32e142b53..23fad47b4 100644 --- a/apps/client-ts/src/components/Connection/columns.tsx +++ b/apps/client-ts/src/components/Connection/columns.tsx @@ -10,6 +10,7 @@ import { DataTableColumnHeader } from "./../shared/data-table-column-header" import React,{ useState } from "react" import { ClipboardIcon } from '@radix-ui/react-icons' import { toast } from "sonner" +import { getLogoURL } from "@panora/shared" function truncateMiddle(str: string, maxLength: number) { @@ -112,13 +113,7 @@ export const columns: ColumnDef[] = [ return (
- {provider} diff --git a/apps/client-ts/src/components/Events/columns.tsx b/apps/client-ts/src/components/Events/columns.tsx index 912838b15..5f5bfd020 100644 --- a/apps/client-ts/src/components/Events/columns.tsx +++ b/apps/client-ts/src/components/Events/columns.tsx @@ -7,6 +7,7 @@ import { Checkbox } from "@/components/ui/checkbox" import { DataTableColumnHeader } from "../shared/data-table-column-header" import { Event } from "./data/schema" +import { getLogoURL } from "@panora/shared" export const columns: ColumnDef[] = [ { @@ -140,13 +141,7 @@ export const columns: ColumnDef[] = [
{row.getValue("integration") ? - {provider} diff --git a/packages/shared/src/utils.ts b/packages/shared/src/utils.ts index 53085c5d5..ffbfc2020 100644 --- a/packages/shared/src/utils.ts +++ b/packages/shared/src/utils.ts @@ -397,7 +397,7 @@ export const providersConfig: ProvidersConfig = { apiUrl: 'https://gitlab.com/api/v4', authBaseUrl: 'https://gitlab.com/oauth/authorize', }, - logoPath: '', + logoPath: 'https://asset.brandfetch.io/idw382nG0m/idVn6myaqy.png', description: 'Sync & Create accounts, tickets, comments, attachments, contacts, tags, teams and users', active: true, authStrategy: AuthStrategy.oauth2 From 7cb986317c2e5d37c8f06605033f2572a8e15605 Mon Sep 17 00:00:00 2001 From: mit-27 Date: Sun, 12 May 2024 20:32:12 -0400 Subject: [PATCH 14/14] =?UTF-8?q?=F0=9F=90=9B=20Fix=20handleTokenRefresh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../connections/ticketing/services/gitlab/gitlab.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts b/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts index 67b60d3c6..929c6de18 100644 --- a/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts +++ b/packages/api/src/@core/connections/ticketing/services/gitlab/gitlab.service.ts @@ -143,7 +143,7 @@ export class GitlabConnectionService implements ITicketingConnectionService { this.type, )) as OAuth2AuthData; const res = await axios.post( - `https://api.gitlab.app/oauth/token`, + `https://gitlab.com/oauth/token`, formData.toString(), { headers: {