Skip to content

Commit

Permalink
Renames cloud integrations
Browse files Browse the repository at this point in the history
  • Loading branch information
eamodio committed Apr 21, 2024
1 parent a17c324 commit 4f7313e
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 52 deletions.
20 changes: 10 additions & 10 deletions src/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { AccountAuthenticationProvider } from './plus/gk/account/authenticationP
import { OrganizationService } from './plus/gk/account/organizationService';
import { SubscriptionService } from './plus/gk/account/subscriptionService';
import { ServerConnection } from './plus/gk/serverConnection';
import type { CloudIntegrationsApi } from './plus/integrations/authentication/cloudIntegrationsApi';
import type { CloudIntegrationService } from './plus/integrations/authentication/cloudIntegrationService';
import { IntegrationAuthenticationService } from './plus/integrations/authentication/integrationAuthentication';
import { IntegrationService } from './plus/integrations/integrationService';
import type { GitHubApi } from './plus/integrations/providers/github/github';
Expand Down Expand Up @@ -432,27 +432,27 @@ export class Container {
return this._cache;
}

private _cloudIntegrationsApi: Promise<CloudIntegrationsApi | undefined> | undefined;
get cloudIntegrationsApi() {
if (this._cloudIntegrationsApi == null) {
private _cloudIntegrations: Promise<CloudIntegrationService | undefined> | undefined;
get cloudIntegrations() {
if (this._cloudIntegrations == null) {
async function load(this: Container) {
try {
const cloudIntegrationsApi = new (
const cloudIntegrations = new (
await import(
/* webpackChunkName: "integrations" */ './plus/integrations/authentication/cloudIntegrationsApi'
/* webpackChunkName: "integrations" */ './plus/integrations/authentication/cloudIntegrationService'
)
).CloudIntegrationsApi(this, this._connection);
return cloudIntegrationsApi;
).CloudIntegrationService(this, this._connection);
return cloudIntegrations;
} catch (ex) {
Logger.error(ex);
return undefined;
}
}

this._cloudIntegrationsApi = load.call(this);
this._cloudIntegrations = load.call(this);
}

return this._cloudIntegrationsApi;
return this._cloudIntegrations;
}

private _drafts: DraftService | undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ import type { Container } from '../../../container';
import { Logger } from '../../../system/logger';
import type { ServerConnection } from '../../gk/serverConnection';
import type { IntegrationId } from '../providers/models';
import type { CloudIntegrationAuthorization, CloudIntegrationConnection, ConnectedCloudIntegration } from './models';
import type {
CloudIntegrationAuthenticationSession,
CloudIntegrationAuthorization,
CloudIntegrationConnection,
} from './models';
import { CloudIntegrationAuthenticationUriPathPrefix } from './models';

export class CloudIntegrationsApi {
export class CloudIntegrationService {
constructor(
private readonly container: Container,
private readonly connection: ServerConnection,
) {}

async getConnectedProvidersData(): Promise<ConnectedCloudIntegration[] | undefined> {
async getConnections(): Promise<CloudIntegrationConnection[] | undefined> {
const providersRsp = await this.connection.fetchGkDevApi(
'v1/provider-tokens',
{ method: 'GET' },
Expand All @@ -26,10 +30,13 @@ export class CloudIntegrationsApi {
return undefined;
}

return (await providersRsp.json())?.data as Promise<ConnectedCloudIntegration[] | undefined>;
return (await providersRsp.json())?.data as Promise<CloudIntegrationConnection[] | undefined>;
}

async getTokenData(id: IntegrationId, refresh: boolean = false): Promise<CloudIntegrationConnection | undefined> {
async getConnectionSession(
id: IntegrationId,
refresh: boolean = false,
): Promise<CloudIntegrationAuthenticationSession | undefined> {
const tokenRsp = await this.connection.fetchGkDevApi(
`v1/provider-tokens/${id}${refresh ? '/refresh' : ''}`,
{ method: refresh ? 'POST' : 'GET' },
Expand All @@ -43,7 +50,7 @@ export class CloudIntegrationsApi {
return undefined;
}

return (await tokenRsp.json())?.data as Promise<CloudIntegrationConnection | undefined>;
return (await tokenRsp.json())?.data as Promise<CloudIntegrationAuthenticationSession | undefined>;
}

async authorize(id: IntegrationId): Promise<CloudIntegrationAuthorization | undefined> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ export class IntegrationAuthenticationService implements Disposable {
case IssueIntegrationId.Jira:
provider = new (
await import(/* webpackChunkName: "integrations" */ './jira')
).JiraAuthenticationProvider(this.container, await this.container.cloudIntegrationsApi);
).JiraAuthenticationProvider(this.container);
break;
default:
throw new Error(`Provider '${providerId}' is not supported`);
Expand Down
30 changes: 14 additions & 16 deletions src/plus/integrations/authentication/jira.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,14 @@ import type { DeferredEventExecutor } from '../../../system/event';
import { promisifyDeferred } from '../../../system/event';
import { openUrl } from '../../../system/utils';
import { IssueIntegrationId } from '../providers/models';
import type { CloudIntegrationsApi } from './cloudIntegrationsApi';
import type {
IntegrationAuthenticationProvider,
IntegrationAuthenticationSessionDescriptor,
} from './integrationAuthentication';
import type { ProviderAuthenticationSession } from './models';

export class JiraAuthenticationProvider implements IntegrationAuthenticationProvider {
constructor(
private readonly container: Container,
private readonly cloudIntegrationsApi: CloudIntegrationsApi | undefined,
) {}
constructor(private readonly container: Container) {}

private readonly authProviderId = IssueIntegrationId.Jira;

Expand All @@ -28,15 +24,17 @@ export class JiraAuthenticationProvider implements IntegrationAuthenticationProv
descriptor?: IntegrationAuthenticationSessionDescriptor,
options?: { authorizeIfNeeded?: boolean },
): Promise<ProviderAuthenticationSession | undefined> {
if (this.cloudIntegrationsApi == null) return undefined;
let tokenData = await this.cloudIntegrationsApi.getTokenData(this.authProviderId);
const cloudIntegrations = await this.container.cloudIntegrations;
if (cloudIntegrations == null) return undefined;

if (tokenData != null && tokenData.expiresIn < 60) {
tokenData = await this.cloudIntegrationsApi.getTokenData(this.authProviderId, true);
let session = await cloudIntegrations.getConnectionSession(this.authProviderId);

if (session != null && session.expiresIn < 60) {
session = await cloudIntegrations.getConnectionSession(this.authProviderId, true);
}

if (!tokenData && options?.authorizeIfNeeded) {
const authorizeJiraUrl = (await this.cloudIntegrationsApi.authorize(this.authProviderId))?.url;
if (!session && options?.authorizeIfNeeded) {
const authorizeJiraUrl = (await cloudIntegrations.authorize(this.authProviderId))?.url;

if (!authorizeJiraUrl) return undefined;

Expand All @@ -58,27 +56,27 @@ export class JiraAuthenticationProvider implements IntegrationAuthenticationProv
),
new Promise<string>((_, reject) => setTimeout(reject, 120000, 'Cancelled')),
]);
tokenData = await this.cloudIntegrationsApi.getTokenData(this.authProviderId);
session = await cloudIntegrations.getConnectionSession(this.authProviderId);
} catch {
tokenData = undefined;
session = undefined;
} finally {
cancellation.cancel();
cancellation.dispose();
deferredCallback.cancel();
}
}

if (!tokenData) return undefined;
if (!session) return undefined;

return {
id: this.getSessionId(descriptor),
accessToken: tokenData.accessToken,
accessToken: session.accessToken,
scopes: descriptor?.scopes ?? [],
account: {
id: '',
label: '',
},
expiresAt: new Date(tokenData.expiresIn * 1000 + Date.now()),
expiresAt: new Date(session.expiresIn * 1000 + Date.now()),
};
}

Expand Down
20 changes: 11 additions & 9 deletions src/plus/integrations/authentication/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,29 @@ export interface ProviderAuthenticationSession extends AuthenticationSession {
readonly expiresAt?: Date;
}

export type CloudIntegrationConnection = {
export interface CloudIntegrationAuthenticationSession {
type: CloudIntegrationAuthType;
accessToken: string;
type: CloudIntegrationConnectionType;
domain: string;
expiresIn: number;
scopes: string;
};
}

export type CloudIntegrationAuthorization = {
export interface CloudIntegrationAuthorization {
url: string;
};
}

export type ConnectedCloudIntegration = {
type: CloudIntegrationConnectionType;
export interface CloudIntegrationConnection {
type: CloudIntegrationAuthType;
provider: CloudIntegrationType;
domain: string;
};
}

// TODO@axosoft-ramint these constants don't match [IntegrationId](https://github.com/gitkraken/vscode-gitlens/blob/c3a5cf55d92ab4ca090f6f7d047be50414daa824/src/plus/integrations/providers/models.ts#L53)
export type CloudIntegrationType = 'jira' | 'trello' | 'gitlab' | 'github' | 'bitbucket' | 'azure';

export type CloudIntegrationConnectionType = 'oauth' | 'personal_access_token';
// TODO@axosoft-ramint these constants don't match the docs
export type CloudIntegrationAuthType = 'oauth' | 'personal_access_token';

export const CloudIntegrationAuthenticationUriPathPrefix = 'did-authenticate-cloud-integration';

Expand Down
20 changes: 10 additions & 10 deletions src/plus/integrations/integrationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,25 +67,25 @@ export class IntegrationService implements Disposable {
}

private async syncCloudIntegrations(_options?: { force?: boolean }) {
const session = await this.container.subscription.getAuthenticationSession();
let connectedProviders = new Set<string>();

const session = await this.container.subscription.getAuthenticationSession();
if (session != null) {
const api = await this.container.cloudIntegrationsApi;
const connectedProviderData = (await api?.getConnectedProvidersData()) ?? [];
connectedProviders = new Set(connectedProviderData.map(p => p.provider));
const cloudIntegrations = await this.container.cloudIntegrations;
const connections = (await cloudIntegrations?.getConnections()) ?? [];
connectedProviders = new Set(connections.map(p => p.provider));
}

for (const cloudIntegrationId of supportedCloudIntegrationIds) {
const integration = await this.get(cloudIntegrationId);
const isConnected = integration.maybeConnected ?? (await integration.isConnected());
if (connectedProviders.has(cloudIntegrationId)) {
if (isConnected) {
continue;
}
if (isConnected) continue;

await integration.connect();
} else {
if (!isConnected) {
continue;
}
if (!isConnected) continue;

await integration.disconnect({ silent: true });
}
}
Expand Down

0 comments on commit 4f7313e

Please sign in to comment.