From e2402e99108cf2f2c6311da94bed8a45baee9276 Mon Sep 17 00:00:00 2001 From: marcello Date: Thu, 8 Nov 2018 22:06:01 +0000 Subject: [PATCH] transport creation! --- src/adt/AdtConnection.ts | 5 +- src/adt/AdtLockParser.ts | 4 +- src/adt/AdtNodeStructParser.ts | 8 +-- src/adt/AdtServer.ts | 13 ++--- src/adt/AdtTransports.ts | 95 ++++++++++++++++++++++++++++++++++ src/functions.ts | 2 +- 6 files changed, 108 insertions(+), 19 deletions(-) create mode 100644 src/adt/AdtTransports.ts diff --git a/src/adt/AdtConnection.ts b/src/adt/AdtConnection.ts index 96bf4b0..3f75dc1 100644 --- a/src/adt/AdtConnection.ts +++ b/src/adt/AdtConnection.ts @@ -73,9 +73,10 @@ export class AdtConnection { }, method, headers: { - ...headers, "x-csrf-token": this._csrftoken, - Accept: "*/*" + "X-sap-adt-sessiontype": "stateful", + Accept: "*/*", + ...headers } } diff --git a/src/adt/AdtLockParser.ts b/src/adt/AdtLockParser.ts index c0a6417..569989e 100644 --- a/src/adt/AdtLockParser.ts +++ b/src/adt/AdtLockParser.ts @@ -1,4 +1,4 @@ -import { defaultVal, mapWidth } from "../functions" +import { defaultVal, mapWith } from "../functions" import { getNode, recxml2js } from "./AdtParserBase" @@ -13,5 +13,5 @@ interface AdtLock { } export const adtLockParser = defaultVal( [], - getNode("asx:abap/asx:values/DATA", mapWidth(recxml2js), (x: any[]) => x[0]) + getNode("asx:abap/asx:values/DATA", mapWith(recxml2js), (x: any[]) => x[0]) ) as (xml: string) => AdtLock diff --git a/src/adt/AdtNodeStructParser.ts b/src/adt/AdtNodeStructParser.ts index 4a9e36d..fd86b0b 100644 --- a/src/adt/AdtNodeStructParser.ts +++ b/src/adt/AdtNodeStructParser.ts @@ -1,6 +1,6 @@ import { getNode, recxml2js, parsetoPromise } from "./AdtParserBase" -import { mapWidth, ArrayToMap, filterComplex, defaultVal } from "../functions" +import { mapWith, ArrayToMap, filterComplex, defaultVal } from "../functions" import { convertableToString } from "xml2js" export interface ObjectNode { @@ -35,7 +35,7 @@ const treecontentParser = defaultVal( getNode( "asx:abap/asx:values/DATA/TREE_CONTENT/SEU_ADT_REPOSITORY_OBJ_NODE", filterComplex(true), - mapWidth(recxml2js) + mapWith(recxml2js) ) ) as (xml: string) => Array const categoryNodeParser: (a: string) => Map = defaultVal( @@ -44,7 +44,7 @@ const categoryNodeParser: (a: string) => Map = defaultVal( "asx:abap/asx:values/DATA/CATEGORIES", filterComplex(true), "SEU_ADT_OBJECT_CATEGORY_INFO", - mapWidth(recxml2js), + mapWith(recxml2js), ArrayToMap("CATEGORY") ) ) @@ -55,7 +55,7 @@ const ObjectTypeParser: (a: string) => Map = defaultVal( "asx:abap/asx:values/DATA/OBJECT_TYPES", filterComplex(true), "SEU_ADT_OBJECT_TYPE_INFO", - mapWidth(recxml2js), + mapWith(recxml2js), ArrayToMap("OBJECT_TYPE") ) ) diff --git a/src/adt/AdtServer.ts b/src/adt/AdtServer.ts index a8bb607..9aff429 100644 --- a/src/adt/AdtServer.ts +++ b/src/adt/AdtServer.ts @@ -4,7 +4,7 @@ import { MetaFolder } from "../fs/MetaFolder" import { AbapObjectNode, AbapNode, isAbap } from "../fs/AbapNode" import { AbapObject, TransportStatus } from "../abap/AbapObject" import { getRemoteList } from "../config" -import { JSON2AbapXML } from "../abap/JSONToAbapXml" +import { selectTransport } from "./AdtTransports" export const ADTBASEURL = "/sap/bc/adt/repository/nodestructure" // visual studio paths are hierarchic, adt ones aren't @@ -59,15 +59,8 @@ export class AdtServer { const conn = await this.connectionP await file.abapObject.lock(conn) if (file.abapObject.transport === TransportStatus.REQUIRED) { - const response = await conn.request( - conn.createUri("/sap/bc/adt/cts/transportchecks"), - "POST", - { - body: JSON2AbapXML({ URI: file.abapObject.getContentsUri(conn).path }) - } - ) - console.log(response.body) - throw new Error("transport selection not supported(yet)") + const transport = await selectTransport(file.abapObject, conn) + if (transport) file.abapObject.transport = transport } await file.abapObject.setContents(conn, content) diff --git a/src/adt/AdtTransports.ts b/src/adt/AdtTransports.ts new file mode 100644 index 0000000..1bef46a --- /dev/null +++ b/src/adt/AdtTransports.ts @@ -0,0 +1,95 @@ +import { AbapObject } from "../abap/AbapObject" +import { JSON2AbapXML } from "../abap/JSONToAbapXml" +import { parsetoPromise, getNode, recxml2js } from "./AdtParserBase" +import { mapWith, flat } from "../functions" +import { AdtConnection } from "./AdtConnection" +import { window } from "vscode" + +interface TransportHeader { + TRKORR: string + TRFUNCTION: string + TRSTATUS: string + TARSYSTEM: string + AS4USER: string + AS4DATE: string + AS4TIME: string + AS4TEXT: string + CLIENT: string +} +interface TransportInfo { + PGMID: string + OBJECT: string + OBJECTNAME: string + OPERATION: string + DEVCLASS: string + CTEXT: string + KORRFLAG: string + AS4USER: string + PDEVCLASS: string + DLVUNIT: string + NAMESPACE: string + RESULT: string + RECORDING: string + EXISTING_REQ_ONLY: string + TRANSPORTS: TransportHeader[] +} + +export async function getTransportCandidates( + obj: AbapObject, + conn: AdtConnection +): Promise { + const response = await conn.request( + conn.createUri("/sap/bc/adt/cts/transportchecks"), + "POST", + { + body: JSON2AbapXML({ URI: obj.getContentsUri(conn).path }) + } + ) + const rawdata = await parsetoPromise()(response.body) + const header = getNode( + "asx:abap/asx:values/DATA", + mapWith(recxml2js), + rawdata + )[0] + + const TRANSPORTS = getNode( + "asx:abap/asx:values/DATA/REQUESTS/CTS_REQUEST", + mapWith(getNode("REQ_HEADER")), + flat, + mapWith(recxml2js), + rawdata + ) + return { ...header, TRANSPORTS } +} + +export async function selectTransport( + obj: AbapObject, + conn: AdtConnection +): Promise { + const ti = await getTransportCandidates(obj, conn) + const CREATENEW = "Create a new transport" + let selection = await window.showQuickPick([ + CREATENEW, + ...ti.TRANSPORTS.map(t => `${t.TRKORR} ${t.AS4TEXT}`) + ]) + + if (!selection) return "" + if (selection === CREATENEW) { + const text = await window.showInputBox({ prompt: "Request text" }) + if (!text) return "" + return createTransport(conn, obj, text, ti.DEVCLASS) + } else return selection.split(" ")[0] +} +async function createTransport( + conn: AdtConnection, + obj: AbapObject, + REQUEST_TEXT: string, + DEVCLASS: string +): Promise { + let uri = obj.getContentsUri(conn) + const body = JSON2AbapXML({ DEVCLASS, REQUEST_TEXT, REF: uri.path }) + uri = uri.with({ path: "/sap/bc/adt/cts/transports" }) + const response = await conn.request(uri, "POST", { body }) + const transport = response.body.split("/").pop() + return transport +} diff --git a/src/functions.ts b/src/functions.ts index be693bc..c9b71d8 100644 --- a/src/functions.ts +++ b/src/functions.ts @@ -50,7 +50,7 @@ export const composePromise = ( //returns a function that maps an array yo the given function // mapWith(f)(array) is the same of array.map(f), but composable -export const mapWidth = (func: any, target?: any[]) => { +export const mapWith = (func: any, target?: any[]) => { const fn = (x: any[]) => x.map(func) return target ? fn(target) : fn }