Skip to content

Commit

Permalink
Support permission_denied__can_apply_for_trial error code (#1426)
Browse files Browse the repository at this point in the history
  • Loading branch information
TamiTakamiya authored Jul 16, 2024
1 parent 1caeea2 commit 0be13a4
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 42 deletions.
7 changes: 7 additions & 0 deletions packages/ansible-language-server/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,13 @@ ERRORS.addError(
"You don't have access to IBM watsonx Code Assistant. Please contact your administrator.",
),
);
ERRORS.addError(
403,
new Error(
"permission_denied__can_apply_for_trial",
"Access denied but user can apply for a trial period.",
),
);
ERRORS.addError(
403,
new Error(
Expand Down
13 changes: 10 additions & 3 deletions src/features/lightspeed/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ import { IError } from "@ansible/ansible-language-server/src/interfaces/lightspe
import { lightSpeedManager } from "../../extension";
import { LightspeedUser } from "./lightspeedUser";
import { inlineSuggestionHideHandler } from "./inlineSuggestions";
import { showTrialInfoPopup } from "./utils/oneClickTrial";
import {
getOneClickTrialProvider,
OneClickTrialProvider,
} from "./utils/oneClickTrial";

const UNKNOWN_ERROR: string = "An unknown error occurred.";

Expand All @@ -48,6 +51,7 @@ export class LightSpeedAPI {
private lightspeedAuthenticatedUser: LightspeedUser;
private _suggestionFeedbacks: string[];
private _extensionVersion: string;
private _oneClickTrialProvider: OneClickTrialProvider;

constructor(
settingsManager: SettingsManager,
Expand All @@ -58,6 +62,7 @@ export class LightSpeedAPI {
this.lightspeedAuthenticatedUser = lightspeedAuthenticatedUser;
this._suggestionFeedbacks = [];
this._extensionVersion = context.extension.packageJSON.version;
this._oneClickTrialProvider = getOneClickTrialProvider();
}

private async getApiInstance(): Promise<AxiosInstance | undefined> {
Expand Down Expand Up @@ -147,8 +152,10 @@ export class LightSpeedAPI {
} catch (error) {
isCompletionSuccess = false;
const err = error as AxiosError;
const mappedError: IError = await mapError(err);
if (!(await showTrialInfoPopup(mappedError))) {
const mappedError: IError = this._oneClickTrialProvider.mapError(
await mapError(err),
);
if (!(await this._oneClickTrialProvider.showPopup(mappedError))) {
vscode.window.showErrorMessage(mappedError.message ?? UNKNOWN_ERROR);
}
return {} as CompletionResponseParams;
Expand Down
6 changes: 4 additions & 2 deletions src/features/lightspeed/playbookExplanation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { LightspeedUser } from "./lightspeedUser";
import { ExplanationResponse } from "@ansible/ansible-language-server/src/interfaces/lightspeedApi";
import { v4 as uuidv4 } from "uuid";
import * as yaml from "yaml";
import { showTrialInfoPopup } from "./utils/oneClickTrial";
import { getOneClickTrialProvider } from "./utils/oneClickTrial";

function getObjectKeys(content: string): string[] {
try {
Expand Down Expand Up @@ -105,7 +105,9 @@ export const playbookExplanation = async (
settingsManager,
).then(async (response: ExplanationResponse) => {
if (isError(response)) {
if (!(await showTrialInfoPopup(response))) {
const oneClickTrialProvider = getOneClickTrialProvider();
response = oneClickTrialProvider.mapError(response);
if (!(await oneClickTrialProvider.showPopup(response))) {
vscode.window.showErrorMessage(response.message ?? UNKNOWN_ERROR);
currentPanel.setContent(
`<p><span class="codicon codicon-error"></span>The operation has failed:<p>${response.message}</p></p>`,
Expand Down
6 changes: 4 additions & 2 deletions src/features/lightspeed/playbookGeneration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
PlaybookGenerationActionType,
} from "../../definitions/lightspeed";
import { isError, UNKNOWN_ERROR } from "./utils/errors";
import { showTrialInfoPopup } from "./utils/oneClickTrial";
import { getOneClickTrialProvider } from "./utils/oneClickTrial";

let currentPanel: WebviewPanel | undefined;
let wizardId: string | undefined;
Expand Down Expand Up @@ -166,7 +166,9 @@ export async function showPlaybookGenerationPage(
panel,
).then(async (response: GenerationResponse) => {
if (isError(response)) {
if (!(await showTrialInfoPopup(response))) {
const oneClickTrialProvider = getOneClickTrialProvider();
response = oneClickTrialProvider.mapError(response);
if (!(await oneClickTrialProvider.showPopup(response))) {
vscode.window.showErrorMessage(
response.message ?? UNKNOWN_ERROR,
);
Expand Down
52 changes: 36 additions & 16 deletions src/features/lightspeed/utils/oneClickTrial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,43 @@ import { IError } from "@ansible/ansible-language-server/src/interfaces/lightspe
import { lightSpeedManager } from "../../../extension";
import { LightSpeedCommands } from "../../../definitions/lightspeed";

export async function showTrialInfoPopup(error?: IError): Promise<boolean> {
if (
lightSpeedManager.lightspeedExplorerProvider
.lightspeedExperimentalEnabled &&
error?.code === "permission_denied__user_has_no_subscription"
) {
const buttonLabel = "Start my Trial period, It's free!";
const selection = await vscode.window.showInformationMessage(
"Oh! You don't have an active Lightspeed Subscription",
buttonLabel,
);
if (selection === buttonLabel) {
vscode.commands.executeCommand(
LightSpeedCommands.LIGHTSPEED_OPEN_TRIAL_PAGE,
export class OneClickTrialProvider {
public mapError(mappedError: IError): IError {
// Don't show "Apply for Trial" message if experimental features are not enabled
if (
mappedError?.code === "permission_denied__can_apply_for_trial" &&
!lightSpeedManager.lightspeedExplorerProvider
.lightspeedExperimentalEnabled
) {
return {
code: "permission_denied__user_has_no_subscription",
message:
"Your organization does not have a subscription. Please contact your administrator.",
};
}
return mappedError;
}

public async showPopup(error?: IError): Promise<boolean> {
if (error?.code === "permission_denied__can_apply_for_trial") {
const buttonLabel = "Start my Trial period, It's free!";
const selection = await vscode.window.showInformationMessage(
"Oh! You don't have an active Lightspeed Subscription",
buttonLabel,
);
if (selection === buttonLabel) {
vscode.commands.executeCommand(
LightSpeedCommands.LIGHTSPEED_OPEN_TRIAL_PAGE,
);
}
return true; // This suppresses to show the standard error message.
}
return true; // This suppresses to show the standard error message.
return false;
}
return false;
}

const oneClickTrialProvider = new OneClickTrialProvider();

export function getOneClickTrialProvider(): OneClickTrialProvider {
return oneClickTrialProvider;
}
4 changes: 2 additions & 2 deletions test/mockLightspeedServer/completion.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { v4 as uuidv4 } from "uuid";
import { options, permissionDeniedUserHasNoSubscription } from "./server";
import { options, permissionDeniedCanApplyForTrial } from "./server";

// Default model ID
const DEFAULT_MODEL_ID = "ABCD-1234-5678";
Expand Down Expand Up @@ -79,7 +79,7 @@ export function completions(
}

if (options.oneClick) {
return res.status(403).json(permissionDeniedUserHasNoSubscription());
return res.status(403).json(permissionDeniedCanApplyForTrial());
}

const model = req.body.model ? req.body.model : DEFAULT_MODEL_ID;
Expand Down
4 changes: 2 additions & 2 deletions test/mockLightspeedServer/explanations.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { v4 as uuidv4 } from "uuid";
import { logger } from "./server";
import { options, permissionDeniedUserHasNoSubscription } from "./server";
import { options, permissionDeniedCanApplyForTrial } from "./server";

export function explanations(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -16,7 +16,7 @@ export function explanations(
logger.info(`content: ${playbook}`);

if (options.oneClick) {
return res.status(403).json(permissionDeniedUserHasNoSubscription());
return res.status(403).json(permissionDeniedCanApplyForTrial());
}

// Special case to replicate the feature being unavailable
Expand Down
5 changes: 0 additions & 5 deletions test/mockLightspeedServer/feedback.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { logger } from "./server";
import { Request, Response } from "express";
import { options, permissionDeniedUserHasNoSubscription } from "./server";

let feedbacks: object[] = [];

Expand All @@ -9,10 +8,6 @@ export function feedback(req: Request, res: Response): Response {
logger.info(JSON.stringify(body, null, 2));
feedbacks.push(body);

if (options.oneClick) {
return res.status(403).json(permissionDeniedUserHasNoSubscription());
}

// If a sentimentFeedback is received and it's feedback starts with
// "permission_denied__" respond with a 403 error with the specified code.
if (body?.sentimentFeedback?.feedback.startsWith("permission_denied__")) {
Expand Down
8 changes: 2 additions & 6 deletions test/mockLightspeedServer/generations.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { v4 as uuidv4 } from "uuid";
import {
logger,
options,
permissionDeniedUserHasNoSubscription,
} from "./server";
import { logger, options, permissionDeniedCanApplyForTrial } from "./server";

export function generations(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -20,7 +16,7 @@ export function generations(
logger.info(`wizardId: ${wizardId}`);

if (options.oneClick) {
return res.status(403).json(permissionDeniedUserHasNoSubscription());
return res.status(403).json(permissionDeniedCanApplyForTrial());
}

// Special case to replicate the feature being unavailable
Expand Down
7 changes: 3 additions & 4 deletions test/mockLightspeedServer/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,13 @@ if (process.platform !== "darwin" && process.env.TEST_LIGHTSPEED_URL) {
url = new URL(process.env.TEST_LIGHTSPEED_URL);
}

export function permissionDeniedUserHasNoSubscription(): {
export function permissionDeniedCanApplyForTrial(): {
code: string;
message: string;
} {
return {
code: "permission_denied__user_has_no_subscription",
message:
"Your organization does not have a subscription. Please contact your administrator.",
code: "permission_denied__can_apply_for_trial",
message: "Access denied but user can apply for a trial period.",
};
}

Expand Down

0 comments on commit 0be13a4

Please sign in to comment.