Skip to content

Commit

Permalink
expose markdown content as view
Browse files Browse the repository at this point in the history
  • Loading branch information
TamiTakamiya authored and goneri committed Jul 18, 2024
1 parent 9d9a45d commit bd33e95
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 20 deletions.
1 change: 1 addition & 0 deletions src/definitions/lightspeed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export const LIGHTSPEED_SUGGESTION_COMPLETION_URL = `${LIGHTSPEED_API_VERSION}/a
export const LIGHTSPEED_SUGGESTION_FEEDBACK_URL = `${LIGHTSPEED_API_VERSION}/ai/feedback/`;
export const LIGHTSPEED_SUGGESTION_CONTENT_MATCHES_URL = `${LIGHTSPEED_API_VERSION}/ai/contentmatches/`;
export const LIGHTSPEED_ME_AUTH_URL = `/api/${LIGHTSPEED_API_VERSION}/me/`;
export const LIGHTSPEED_MARKDOWN_ME_AUTH_URL = `/api/${LIGHTSPEED_API_VERSION}/me/summary/`;

export const LIGHTSPEED_FEEDBACK_FORM_URL =
"https://red.ht/ansible-ai-feedback";
Expand Down
19 changes: 5 additions & 14 deletions src/features/lightspeed/explorerWebviewViewProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
} from "./utils/explorerView";
import { LightspeedUser } from "./lightspeedUser";

import { getLoggedInUserDetails } from "./utils/webUtils";
import { isPlaybook } from "./playbookExplanation";

export class LightspeedExplorerWebviewViewProvider
Expand Down Expand Up @@ -69,22 +68,14 @@ export class LightspeedExplorerWebviewViewProvider
}

private async _getWebviewContent(webview: Webview, extensionUri: Uri) {
const userDetails =
await this.lightspeedAuthenticatedUser.getLightspeedUserDetails(false);
if (userDetails) {
const sessionInfo = getLoggedInUserDetails(userDetails);
const userName = userDetails.displayNameWithUserType;
const userType = sessionInfo.userInfo?.userType || "";
const userRole =
sessionInfo.userInfo?.role !== undefined
? sessionInfo.userInfo?.role
: "";
const content =
await this.lightspeedAuthenticatedUser.getLightspeedUserContent();

if (content !== "undefined") {
return getWebviewContentWithActiveSession(
webview,
extensionUri,
userName,
userType,
userRole,
String(content),
this.hasPlaybookOpened(),
);
} else {
Expand Down
108 changes: 108 additions & 0 deletions src/features/lightspeed/lightspeedUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import {
ANSIBLE_LIGHTSPEED_AUTH_ID,
getBaseUri,
getUserTypeLabel,
getLoggedInUserDetails,
} from "./utils/webUtils";
import {
LIGHTSPEED_MARKDOWN_ME_AUTH_URL,
LIGHTSPEED_ME_AUTH_URL,
LightSpeedCommands,
} from "../../definitions/lightspeed";
Expand All @@ -17,6 +19,7 @@ import {
isSupportedCallback,
} from "./lightSpeedOAuthProvider";
import { Log } from "../../utils/logger";
import * as marked from "marked";

export class LightspeedAccessDenied extends Error {
constructor(message: string) {
Expand Down Expand Up @@ -54,6 +57,7 @@ export class LightspeedUser {
private _userDetails: LightspeedUserDetails | undefined;
private _logger: Log;
private _extensionHost: ExtensionHostType;
private _markdownUserDetails: string | undefined;

constructor(
private readonly context: vscode.ExtensionContext,
Expand Down Expand Up @@ -136,6 +140,45 @@ export class LightspeedUser {
}
}

public async getUserInfoFromMarkdown(token: string) {
this._logger.info(
"[ansible-lightspeed-user] Sending request for logged-in user info...",
);

try {
const { data } = await axios.get(
`${getBaseUri(this._settingsManager)}${LIGHTSPEED_MARKDOWN_ME_AUTH_URL}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
},
);

const markdownData = marked.parse(data.content) as string;

return markdownData;
} catch (error) {
if (
axios.isAxiosError(error) &&
error.response &&
error.response.status === 401
) {
throw new LightspeedAccessDenied(error.message);
} else if (axios.isAxiosError(error)) {
this._logger.error(
`[ansible-lightspeed-user] error message: ${error.message}`,
);
throw new Error(error.message);
} else {
this._logger.error(
`[ansible-lightspeed-user] unexpected error: ${error}`,
);
throw new Error("An unexpected error occurred");
}
}
}

public async getAuthProviderOrder() {
// NOTE: We can't gate this check on if this extension is active,
// because it only activates on an authentication request.
Expand Down Expand Up @@ -234,6 +277,16 @@ export class LightspeedUser {
);
this._session = session;

let markdownUserInfo: string = "";
try {
markdownUserInfo = await this.getUserInfoFromMarkdown(
session.accessToken,
);
} catch (error) {
markdownUserInfo = "";
}
this._markdownUserDetails = markdownUserInfo;

const displayName =
userinfo.external_username || userinfo.username || "";
const userTypeLabel = getUserTypeLabel(
Expand Down Expand Up @@ -271,12 +324,14 @@ export class LightspeedUser {

this._session = undefined;
this._userDetails = undefined;
this._markdownUserDetails = undefined;
this._userType = undefined;
}

public async refreshLightspeedUser() {
this._session = undefined;
this._userDetails = undefined;
this._markdownUserDetails = undefined;
await this.setLightspeedUser(false);
}

Expand All @@ -300,6 +355,59 @@ export class LightspeedUser {
return this._userDetails;
}

public async getMarkdownLightspeedUserDetails(
createIfNone: boolean,
useProviderType: AuthProviderType | undefined = undefined,
) {
// Ensure we don't try to get a lightspeed auth session when the provider is not initialized
if (!this._settingsManager.settings.lightSpeedService.enabled) {
return undefined;
}
if (
this._markdownUserDetails &&
(!useProviderType || useProviderType === this._userType)
) {
return this._markdownUserDetails;
}

await this.setLightspeedUser(createIfNone, useProviderType);

return this._markdownUserDetails;
}

public async getLightspeedUserContent() {
// Ensure we don't try to get a lightspeed auth session when the provider is not initialized
if (!this._settingsManager.settings.lightSpeedService.enabled) {
return undefined;
}

const markdownUserDetails =
await this.getMarkdownLightspeedUserDetails(false);
const userDetails = await this.getLightspeedUserDetails(false);

let content = "undefined";
if (markdownUserDetails !== "") {
content = String(markdownUserDetails);
} else {
if (userDetails) {
const sessionInfo = getLoggedInUserDetails(userDetails);
const userName = userDetails.displayNameWithUserType;
const userType = sessionInfo.userInfo?.userType || "";
const userRole =
sessionInfo.userInfo?.role !== undefined
? sessionInfo.userInfo?.role
: "";
content = `
<p>Logged in as: ${userName}</p>
<p>User Type: ${userType}</p>
${userRole ? "Role: " + userRole : ""}
`;
}
}

return content;
}

public async rhUserHasSeat(): Promise<boolean | undefined> {
const userDetails = await this.getLightspeedUserDetails(false);

Expand Down
8 changes: 2 additions & 6 deletions src/features/lightspeed/utils/explorerView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ export function getWebviewContentWithLoginForm(
export function getWebviewContentWithActiveSession(
webview: Webview,
extensionUri: Uri,
userName: string,
userType: string,
userRole: string,
content: string,
has_playbook_opened: boolean,
) {
const webviewUri = getUri(webview, extensionUri, [
Expand Down Expand Up @@ -98,9 +96,7 @@ export function getWebviewContentWithActiveSession(
<body>
<body>
<div id="lightspeedExplorerView">
Logged in as: ${userName}<br />
User Type: ${userType}<br />
${userRole ? "Role: " + userRole : ""}
${content}
${explainForm}
</div>
</body>
Expand Down
7 changes: 7 additions & 0 deletions test/mockLightspeedServer/meMarkdown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// import { options } from "./server";
export function meMarkdown() {
return {
content:
"Logged in as: ONE_CLICK_USER (unlicensed)\n\n User Type: Unlicensed",
};
}
5 changes: 5 additions & 0 deletions test/mockLightspeedServer/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import morgan from "morgan";
import fs from "fs";
import path from "path";
import yargs from "yargs";
import { meMarkdown } from "./meMarkdown";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export let options: any = readOptions(process.argv.splice(2));
Expand Down Expand Up @@ -100,6 +101,10 @@ export default class Server {
return res.send(me());
});

app.get(`${API_ROOT}/me/summary`, (req, res) => {
return res.send(meMarkdown());
});

app.get("/o/authorize", (req: { query: { redirect_uri: string } }, res) => {
logger.info(req.query);
const redirectUri = decodeURIComponent(req.query.redirect_uri);
Expand Down
41 changes: 41 additions & 0 deletions test/testScripts/lightspeed/testLightspeedUser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,44 @@ function testGetUserInfo() {
});
}

function testGetUserInfoFromMarkdown() {
describe("Test LightspeedUser.getUserInfoFromMarkdown", function () {
it("Returns /me/summary endpoint results with valid access token", async function () {
const accessToken =
(await lightSpeedManager.lightspeedAuthenticatedUser.getLightspeedUserAccessToken()) as string;
const markdownUserInfo: string =
await lightSpeedManager.lightspeedAuthenticatedUser.getUserInfoFromMarkdown(
accessToken,
);

assert.isNotNull(markdownUserInfo);
});
});
}

function testGetMarkdownLightspeedUserDetails() {
describe("test LightspeedUser.getMarkdownLightspeedUserDetails", function () {
it("Returns formatted content from /me/summary endpoint", async function () {
const markdownUserDetails =
await lightSpeedManager.lightspeedAuthenticatedUser.getMarkdownLightspeedUserDetails(
false,
);

assert.isNotNull(markdownUserDetails);
});
});
}

function testGetLightspeedUserContent() {
describe("test LightspeedUser.getLightspeedUserContent", function () {
it("Returns proper HTML markdown based on whether /me/summary is available", async function () {
const content =
await lightSpeedManager.lightspeedAuthenticatedUser.getLightspeedUserContent();
assert.isNotNull(content);
});
});
}

function testGetAuthProviderOrder() {
describe("Test LightspeedUser.getAuthProviderOrder", function () {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down Expand Up @@ -234,6 +272,9 @@ export function testLightspeedUser(): void {
testIsSupportedCallback();
testIsLightspeedUserAuthProviderType();
testGetUserInfo();
testGetUserInfoFromMarkdown();
testGetMarkdownLightspeedUserDetails();
testGetLightspeedUserContent();
testGetAuthProviderOrder();
testRedHatSignInCommand();
}

0 comments on commit bd33e95

Please sign in to comment.