diff --git a/src/common/services/AuthenticationProvider.ts b/src/common/services/AuthenticationProvider.ts index f8ad53d54..cd4d913c9 100644 --- a/src/common/services/AuthenticationProvider.ts +++ b/src/common/services/AuthenticationProvider.ts @@ -23,7 +23,7 @@ import { VSCODE_EXTENSION_PPAPI_WEBSITES_AUTHENTICATION_FAILED } from "./TelemetryConstants"; import { ERROR_CONSTANTS } from "../ErrorConstants"; -import { BAP_SERVICE_SCOPE_DEFAULT, INTELLIGENCE_SCOPE_DEFAULT, PPAPI_WEBSITES_SERVICE_SCOPE_DEFAULT, PROVIDER_ID, SCOPE_OPTION_CONTACTS_READ, SCOPE_OPTION_DEFAULT, SCOPE_OPTION_OFFLINE_ACCESS, SCOPE_OPTION_USERS_READ_BASIC_ALL } from "./Constants"; +import { BAP_SERVICE_SCOPE_DEFAULT, INTELLIGENCE_SCOPE_DEFAULT, PROVIDER_ID, SCOPE_OPTION_CONTACTS_READ, SCOPE_OPTION_DEFAULT, SCOPE_OPTION_OFFLINE_ACCESS, SCOPE_OPTION_USERS_READ_BASIC_ALL } from "./Constants"; import jwt_decode from 'jwt-decode'; import { showErrorDialog } from "../utilities/errorHandlerUtil"; @@ -296,10 +296,14 @@ export function getOIDFromToken(token: string, telemetry: ITelemetry) { export async function powerPlatformAPIAuthentication( telemetry: ITelemetry, + ppapiEndpoint: string, firstTimeAuth = false ): Promise { let accessToken = ""; try { + + ppapiEndpoint = ppapiEndpoint.split("/powerpages")[0]; + const PPAPI_WEBSITES_SERVICE_SCOPE_DEFAULT = `${ppapiEndpoint}${SCOPE_OPTION_DEFAULT}`; let session = await vscode.authentication.getSession( PROVIDER_ID, [PPAPI_WEBSITES_SERVICE_SCOPE_DEFAULT], diff --git a/src/common/services/PPAPIService.ts b/src/common/services/PPAPIService.ts index 1b9f959a3..4e5d33765 100644 --- a/src/common/services/PPAPIService.ts +++ b/src/common/services/PPAPIService.ts @@ -5,17 +5,19 @@ import { ITelemetry } from "../OneDSLoggerTelemetry/telemetry/ITelemetry"; import { getCommonHeaders, powerPlatformAPIAuthentication } from "./AuthenticationProvider"; -import { VSCODE_EXTENSION_GET_CROSS_GEO_DATA_MOVEMENT_ENABLED_FLAG_FAILED, VSCODE_EXTENSION_GET_PPAPI_WEBSITES_ENDPOINT_UNSUPPORTED_REGION, VSCODE_EXTENSION_PPAPI_GET_WEBSITE_BY_ID_COMPLETED } from "./TelemetryConstants"; +import { VSCODE_EXTENSION_GET_CROSS_GEO_DATA_MOVEMENT_ENABLED_FLAG_FAILED, VSCODE_EXTENSION_GET_PPAPI_WEBSITES_ENDPOINT_UNSUPPORTED_REGION, VSCODE_EXTENSION_PPAPI_CREATE_WEBSITE_COMPLETED, VSCODE_EXTENSION_PPAPI_CREATE_WEBSITE_FAILED, VSCODE_EXTENSION_PPAPI_GET_WEBSITE_BY_ID_COMPLETED } from "./TelemetryConstants"; import { ServiceEndpointCategory, PPAPI_WEBSITES_ENDPOINT, PPAPI_WEBSITES_API_VERSION } from "./Constants"; import { sendTelemetryEvent } from "../copilot/telemetry/copilotTelemetry"; import { IWebsiteDetails } from "./Interfaces"; +import { v4 as uuidv4 } from 'uuid' export class PPAPIService { public static async getWebsiteDetailsById(serviceEndpointStamp: ServiceEndpointCategory, environmentId: string, websitePreviewId: string, telemetry: ITelemetry): Promise { // websitePreviewId aka portalId try { - const accessToken = await powerPlatformAPIAuthentication(telemetry, true); - const response = await fetch(await PPAPIService.getPPAPIServiceEndpoint(serviceEndpointStamp, telemetry, environmentId, websitePreviewId), { + const ppapiEndpoint = await PPAPIService.getPPAPIServiceEndpoint(serviceEndpointStamp, telemetry, environmentId); + const accessToken = await powerPlatformAPIAuthentication(telemetry, ppapiEndpoint, true); + const response = await fetch(ppapiEndpoint, { method: 'GET', headers: getCommonHeaders(accessToken) }); @@ -33,6 +35,46 @@ export class PPAPIService { return null; } + public static async createWebsite(serviceEndpointStamp: ServiceEndpointCategory, + environmentId: string, + orgId: string, + websiteName: string, + websiteLanguage: number, + telemetry: ITelemetry) { // websitePreviewId aka portalId + + const ppapiEndpoint = await PPAPIService.getPPAPIServiceEndpoint(serviceEndpointStamp, telemetry, environmentId); + + try { + console.log("Creating website"); + const accessToken = await powerPlatformAPIAuthentication(telemetry, ppapiEndpoint, true); + const siteSuffix = uuidv4(); + const response = await fetch(ppapiEndpoint, { + method: 'POST', + headers: getCommonHeaders(accessToken), + body: JSON.stringify({ + dataverseOrganizationId: orgId, + name: websiteName, // Add name sanitization function + selectedBaseLanguage: websiteLanguage, + subDomain: websiteName + `-${siteSuffix.slice(siteSuffix.length - 6, siteSuffix.length)}`, // Add name sanitization function + templateName: "DefaultPortalTemplate", + websiteRecordId: siteSuffix // If this ID is passed package installation is not done and portal is associated with the passed ID - we should use this option + }) + }); + + if (response.ok) { + sendTelemetryEvent(telemetry, { eventName: VSCODE_EXTENSION_PPAPI_CREATE_WEBSITE_COMPLETED, data: `environmentId:${environmentId}, orgId:${orgId}, websiteName:${websiteName}` }); + } + else { + sendTelemetryEvent(telemetry, { eventName: VSCODE_EXTENSION_PPAPI_CREATE_WEBSITE_FAILED, errorMsg: `Failed to create website. Response status: ${response.status}` }); + } + } + catch (error) { + sendTelemetryEvent(telemetry, { eventName: VSCODE_EXTENSION_PPAPI_CREATE_WEBSITE_FAILED, errorMsg: (error as Error).message }); + } + + return null; + } + static async getPPAPIServiceEndpoint(serviceEndpointStamp: ServiceEndpointCategory, telemetry: ITelemetry, environmentId: string, websitePreviewId?: string): Promise { let ppapiEndpoint = ""; diff --git a/src/common/services/TelemetryConstants.ts b/src/common/services/TelemetryConstants.ts index 4d4d26404..be53bc3cb 100644 --- a/src/common/services/TelemetryConstants.ts +++ b/src/common/services/TelemetryConstants.ts @@ -24,3 +24,5 @@ export const VSCODE_EXTENSION_GET_PPAPI_WEBSITES_ENDPOINT_UNSUPPORTED_REGION = " export const VSCODE_EXTENSION_DECODE_JWT_TOKEN_FAILED = "VSCodeExtensionDecodeJWTTokenFailed"; export const VSCODE_EXTENSION_PPAPI_GET_WEBSITE_BY_ID_COMPLETED = "VSCodeExtensionPPAPIGetWebsiteByIdCompleted"; export const VSCODE_EXTENSION_PPAPI_GET_WEBSITE_BY_ID_FAILED = "VSCodeExtensionPPAPIGetWebsiteByIdFailed"; +export const VSCODE_EXTENSION_PPAPI_CREATE_WEBSITE_COMPLETED = "VSCodeExtensionPPAPICreateWebsiteCompleted"; +export const VSCODE_EXTENSION_PPAPI_CREATE_WEBSITE_FAILED = "VSCodeExtensionPPAPICreateWebsiteFailed"; diff --git a/src/web/client/utilities/commonUtil.ts b/src/web/client/utilities/commonUtil.ts index 7d890fb6e..7ac27eb9a 100644 --- a/src/web/client/utilities/commonUtil.ts +++ b/src/web/client/utilities/commonUtil.ts @@ -307,7 +307,7 @@ export function getRangeForMultilineMatch(text: string, pattern: string, index: } export async function validateWebsitePreviewURL(): Promise { - const envId = WebExtensionContext.urlParametersMap?.get(queryParameters.ENV_ID); + const envId = getEnvironmentIdFromUrl(); const serviceEndpointStamp = WebExtensionContext.serviceEndpointCategory; const websitePreviewId = WebExtensionContext.urlParametersMap?.get(queryParameters.PORTAL_ID); @@ -322,6 +322,9 @@ export async function validateWebsitePreviewURL(): Promise { const siteDetails = await PPAPIService.getWebsiteDetailsById(serviceEndpointStamp, envId, websitePreviewId, WebExtensionContext.telemetry.getTelemetryReporter()); + // test site create + await PPAPIService.createWebsite(serviceEndpointStamp, envId, WebExtensionContext.urlParametersMap?.get(queryParameters.ORG_ID) ?? "", "testWebName", 1033, WebExtensionContext.telemetry.getTelemetryReporter()); + if (siteDetails == null) { WebExtensionContext.telemetry.sendErrorTelemetry( webExtensionTelemetryEventNames.WEB_EXTENSION_WEBSITE_PREVIEW_URL_VALIDATION_SITE_DETAILS_FETCH_FAILED,