Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 179 additions & 0 deletions AppSrc/cDocuPipeClient.pkg
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
Use cdtJsonHttpTransfer.pkg
Use cBase64Attachment_mixin.pkg
Use cJsonObject.pkg
Use docupipeai.h

Class cDocuPipeClient is a cdtJsonHttpTransfer
Import_Class_Protocol cBase64Attachment_mixin

Procedure Construct_Object
Forward Send Construct_Object

Send Define_cBase64Attachment_mixin

Property String psApiKey ""
Property String psBaseUrl "https://app.docupipe.ai"
Property Integer piTimeoutSeconds 90
Property Integer piRetryCount 1
Property Boolean pbLogRawJson False
Property String psLastError ""

Set peTransferFlags to ifSecure
Set piRemotePort to rpHttpSSL
Comment on lines +21 to +22

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor base URL scheme when configuring transport security

The client strips both https:// and http:// from psBaseUrl, but transport is always forced to ifSecure/rpHttpSSL and never updated from the configured URL. If a caller provides an http:// base URL (for local/staging/proxy endpoints), requests will still attempt TLS on port 443 and fail to connect.

Useful? React with 👍 / 👎.

End_Procedure

Procedure Configure tDocuPipeConfig cfg
If (cfg.sApiKey<>'') Set psApiKey to cfg.sApiKey
If (cfg.sBaseUrl<>'') Set psBaseUrl to cfg.sBaseUrl
If (cfg.iTimeoutSeconds>0) Set piTimeoutSeconds to cfg.iTimeoutSeconds
If (cfg.iRetryCount>=0) Set piRetryCount to cfg.iRetryCount

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve default retry count when config leaves it unset

Configure applies cfg.iRetryCount whenever it is >= 0, but tDocuPipeConfig integers default to 0, so callers that only populate sApiKey unintentionally override the class default of one retry with zero retries. In that common path, transient transport failures, 429s, and 5xxs stop retrying even though the object is initialized with retry support.

Useful? React with 👍 / 👎.

Set pbLogRawJson to cfg.bLogRawJson
Send SetTimeout (piTimeoutSeconds(Self))
End_Procedure

Function HostFromBaseUrl Returns String
String sBase sHost

Get psBaseUrl to sBase
Move (Replace("https://",sBase,"")) to sHost
Move (Replace("http://",sHost,"")) to sHost
If (Right(sHost,1)='/') Move (Left(sHost,Length(sHost)-1)) to sHost

Function_Return sHost
End_Function

Function NormalizePath String sPath Returns String
String sRet
Move sPath to sRet
While (Left(sRet,1)='/')
Move (Right(sRet,Length(sRet)-1)) to sRet
Loop
Function_Return sRet
End_Function

Procedure AddStandardHeaders Boolean bJsonBody
Integer iRetVal

Set pbClearHeaders to False
Send ClearHeaders

Get AddHeader "Accept" "application/json" to iRetVal
Get AddHeader "X-API-Key" (psApiKey(Self)) to iRetVal
If (bJsonBody) Get AddHeader "Content-Type" "application/json" to iRetVal
End_Procedure

Function ShouldRetry Boolean bTransferOk Integer iStatus Returns Boolean
Boolean bRetry

Move False to bRetry
If (not(bTransferOk)) Move True to bRetry
Else If (iStatus=429) Move True to bRetry
Else If (iStatus>=500 and iStatus<=599) Move True to bRetry

Function_Return bRetry
End_Function

Function ExecuteJsonRequest String sVerb String sPath Handle hoRequest Returns tDocuPipeResult
tDocuPipeResult Result
Handle hoResponse
String sHost sRawJson sPathOnly
Boolean bTransferOk bJsonBody bRetry
Integer iAttempt iAttempts iStatus

Move (Trim(sVerb)) to sVerb
Move (Uppercase(sVerb)) to sVerb
Move (NormalizePath(Self,sPath)) to sPathOnly
Move (HostFromBaseUrl(Self)) to sHost
Move (piRetryCount(Self)+1) to iAttempts
Move (hoRequest<>0) to bJsonBody

If (psApiKey(Self)="") Begin
Move "DocuPipe API key is not configured." to Result.sError
Function_Return Result
End

For iAttempt from 1 to iAttempts
Send AddStandardHeaders bJsonBody

Move False to bTransferOk
If (sVerb="GET") Begin
Get HttpGetJson sHost sPathOnly (&bTransferOk) to hoResponse
End
Else Begin
Get HttpVerbJson sHost sPathOnly hoRequest sVerb (&bTransferOk) to hoResponse
End

Get ResponseStatusCode to iStatus
Move iStatus to Result.iHttpStatus

If (hoResponse) Begin
Move (Stringify(hoResponse)) to sRawJson
Send Destroy of hoResponse
Move 0 to hoResponse
End
Else Begin
Get DataReceived to sRawJson
End

Move sRawJson to Result.sRawJson
Move (bTransferOk and iStatus>=200 and iStatus<300) to Result.bOk

If (Result.bOk) Function_Return Result

Move (ShouldRetry(Self,bTransferOk,iStatus)) to bRetry
If (not(bRetry) or iAttempt=iAttempts) Begin
If (sRawJson<>'') Move sRawJson to Result.sError
Else If (not(bTransferOk)) Move (TransferErrorDescription(Self)) to Result.sError
Else Move ('HTTP error '+String(iStatus)) to Result.sError
Function_Return Result
End
Loop

Move "DocuPipe request failed after retries." to Result.sError
Function_Return Result
End_Function


Function ExtractJsonStringValue String sJson String sKey Returns String
Integer iKey iColon iStart iStop
String sNeedle sTail sValue

Move ('"'+sKey+'"') to sNeedle
Move (Pos(sNeedle,sJson)) to iKey
If (iKey=0) Function_Return ""

Move (Mid(sJson,Length(sJson)-iKey+1,iKey)) to sTail
Move (Pos(':',sTail)) to iColon
If (iColon=0) Function_Return ""

Move (Mid(sTail,Length(sTail)-iColon+1,iColon)) to sTail
Move (Pos('"',sTail)) to iStart
If (iStart=0) Function_Return ""

Move (Mid(sTail,Length(sTail)-iStart,iStart+1)) to sTail
Move (Pos('"',sTail)) to iStop
If (iStop=0) Function_Return ""

Move (Left(sTail,iStop-1)) to sValue
Function_Return sValue
End_Function

Function BuildDocumentFileRequest String sFilePath String sDataset String sWorkflowId Returns Handle
Handle hoReq
tAIAttachment Attachment

Get Create (RefClass(cJsonObject)) to hoReq
Send InitializeJsonType of hoReq jsonTypeObject

Get CreateAttachment sFilePath to Attachment

Send SetMemberValue of hoReq "contentBase64" jsonTypeString (UCharArrayToString(Attachment.uBase64File))
Send SetMemberValue of hoReq "mimeType" jsonTypeString Attachment.sMimeType
Send SetMemberValue of hoReq "filename" jsonTypeString sFilePath

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Send only basename in document filename field

The request payload sets "filename" to sFilePath, which commonly contains an absolute local path; this leaks local directory/user information to the external API and can break integrations that validate filename tokens without path separators. The field should be derived from the file basename, not the full path.

Useful? React with 👍 / 👎.


If (sDataset<>'') Send SetMemberValue of hoReq "dataset" jsonTypeString sDataset
If (sWorkflowId<>'') Send SetMemberValue of hoReq "workflowId" jsonTypeString sWorkflowId

Function_Return hoReq
End_Function
End_Class
65 changes: 65 additions & 0 deletions AppSrc/cDocuPipeDocumentService.pkg
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
Use cJsonObject.pkg
Use docupipeai.h
Use cDocuPipeClient.pkg

Class cDocuPipeDocumentService is a cObject

Function SubmitDocumentFromFile Handle hoClient String sFilePath String sDataset String sWorkflowId Returns tDocuPipeDocumentSubmitResponse
tDocuPipeDocumentSubmitResponse Response
tDocuPipeResult Result
Handle hoReq

Get BuildDocumentFileRequest of hoClient sFilePath sDataset sWorkflowId to hoReq
Get ExecuteJsonRequest of hoClient "POST" "/document" hoReq to Result
Send Destroy of hoReq

Move Result.bOk to Response.bOk
Move Result.iHttpStatus to Response.iHttpStatus
Move Result.sError to Response.sError
Move Result.sRawJson to Response.sRawJson

If (Result.sRawJson<>'') Begin
Get ExtractJsonStringValue of hoClient Result.sRawJson "documentId" to Response.sDocumentId
If (Response.sDocumentId='') Get ExtractJsonStringValue of hoClient Result.sRawJson "document_id" to Response.sDocumentId
If (Response.sDocumentId='') Get ExtractJsonStringValue of hoClient Result.sRawJson "id" to Response.sDocumentId
End

Function_Return Response
End_Function

Function SubmitDocumentFromUrl Handle hoClient String sUrl String sDataset String sWorkflowId Returns tDocuPipeDocumentSubmitResponse
tDocuPipeDocumentSubmitResponse Response
tDocuPipeResult Result
Handle hoReq

Get Create (RefClass(cJsonObject)) to hoReq
Send InitializeJsonType of hoReq jsonTypeObject
Send SetMemberValue of hoReq "url" jsonTypeString sUrl
If (sDataset<>'') Send SetMemberValue of hoReq "dataset" jsonTypeString sDataset
If (sWorkflowId<>'') Send SetMemberValue of hoReq "workflowId" jsonTypeString sWorkflowId

Get ExecuteJsonRequest of hoClient "POST" "/document" hoReq to Result
Send Destroy of hoReq

Move Result.bOk to Response.bOk
Move Result.iHttpStatus to Response.iHttpStatus
Move Result.sError to Response.sError
Move Result.sRawJson to Response.sRawJson

If (Result.sRawJson<>'') Begin
Get ExtractJsonStringValue of hoClient Result.sRawJson "documentId" to Response.sDocumentId
If (Response.sDocumentId='') Get ExtractJsonStringValue of hoClient Result.sRawJson "document_id" to Response.sDocumentId
If (Response.sDocumentId='') Get ExtractJsonStringValue of hoClient Result.sRawJson "id" to Response.sDocumentId
End

Function_Return Response
End_Function

Function GetDocument Handle hoClient String sDocumentId Returns tDocuPipeResult
tDocuPipeResult Result

Get ExecuteJsonRequest of hoClient "GET" ("/document/"+sDocumentId) 0 to Result
Function_Return Result
End_Function

End_Class
37 changes: 37 additions & 0 deletions AppSrc/cDocuPipeJobService.pkg
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Use docupipeai.h
Use cDocuPipeClient.pkg

Class cDocuPipeJobService is a cObject

Function GetJob Handle hoClient String sJobId Returns tDocuPipeJobResponse
tDocuPipeJobResponse Response
tDocuPipeResult Result

Get ExecuteJsonRequest of hoClient "GET" ("/job/"+sJobId) 0 to Result

Move Result.bOk to Response.bOk
Move Result.iHttpStatus to Response.iHttpStatus
Move Result.sError to Response.sError
Move Result.sRawJson to Response.sRawJson
Move sJobId to Response.sJobId

If (Result.sRawJson<>'') Begin
Get ExtractJsonStringValue of hoClient Result.sRawJson "jobId" to Response.sJobId
If (Response.sJobId='') Get ExtractJsonStringValue of hoClient Result.sRawJson "job_id" to Response.sJobId

Get ExtractJsonStringValue of hoClient Result.sRawJson "status" to Response.sStatus
Get ExtractJsonStringValue of hoClient Result.sRawJson "standardizationId" to Response.sStandardizationId
If (Response.sStandardizationId='') Get ExtractJsonStringValue of hoClient Result.sRawJson "standardization_id" to Response.sStandardizationId
End

Function_Return Response
End_Function

Function IsTerminalJobStatus String sStatus Returns Boolean
String sCompare

Move (Lowercase(Trim(sStatus))) to sCompare
Function_Return (sCompare="completed" or sCompare="complete" or sCompare="failed" or sCompare="error" or sCompare="cancelled" or sCompare="canceled")
End_Function

End_Class
74 changes: 74 additions & 0 deletions AppSrc/cDocuPipeStandardizationService.pkg
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
Use cJsonObject.pkg
Use docupipeai.h
Use cDocuPipeClient.pkg

Class cDocuPipeStandardizationService is a cObject

Function Standardize Handle hoClient String[] aDocumentIds String sSchemaId String sGuidelines String sDisplayMode String sSplitMode String sEffortLevel Returns tDocuPipeStandardizeResponse
tDocuPipeStandardizeResponse Response
tDocuPipeResult Result
Handle hoReq hoIds hoId
Integer i iCount

Get Create (RefClass(cJsonObject)) to hoReq
Send InitializeJsonType of hoReq jsonTypeObject

Get Create (RefClass(cJsonObject)) to hoIds
Send InitializeJsonType of hoIds jsonTypeArray

Move (SizeOfArray(aDocumentIds)) to iCount
For i from 0 to (iCount-1)
Get Create (RefClass(cJsonObject)) to hoId
Send InitializeJsonType of hoId jsonTypeString
Send SetStringValue of hoId aDocumentIds[i]
Send AddMember of hoIds hoId
Send Destroy of hoId
Loop

Send SetMember of hoReq "documentIds" hoIds
Send Destroy of hoIds

If (sSchemaId<>'') Send SetMemberValue of hoReq "schemaId" jsonTypeString sSchemaId
If (sGuidelines<>'') Send SetMemberValue of hoReq "guidelines" jsonTypeString sGuidelines
If (sDisplayMode<>'') Send SetMemberValue of hoReq "displayMode" jsonTypeString sDisplayMode
If (sSplitMode<>'') Send SetMemberValue of hoReq "splitMode" jsonTypeString sSplitMode
If (sEffortLevel<>'') Send SetMemberValue of hoReq "effortLevel" jsonTypeString sEffortLevel

Get ExecuteJsonRequest of hoClient "POST" "/v2/standardize/batch" hoReq to Result
Send Destroy of hoReq

Move Result.bOk to Response.bOk
Move Result.iHttpStatus to Response.iHttpStatus
Move Result.sError to Response.sError
Move Result.sRawJson to Response.sRawJson

If (Result.sRawJson<>'') Begin
Get ExtractJsonStringValue of hoClient Result.sRawJson "jobId" to Response.sJobId
If (Response.sJobId='') Get ExtractJsonStringValue of hoClient Result.sRawJson "job_id" to Response.sJobId
If (Response.sJobId='') Get ExtractJsonStringValue of hoClient Result.sRawJson "id" to Response.sJobId
End

Function_Return Response
End_Function

Function GetStandardization Handle hoClient String sStandardizationId Returns tDocuPipeStandardizationGetResponse
tDocuPipeStandardizationGetResponse Response
tDocuPipeResult Result

Get ExecuteJsonRequest of hoClient "GET" ("/standardization/"+sStandardizationId) 0 to Result

Move Result.bOk to Response.bOk
Move Result.iHttpStatus to Response.iHttpStatus
Move Result.sError to Response.sError
Move Result.sRawJson to Response.sRawJson
Move sStandardizationId to Response.sStandardizationId

If (Result.sRawJson<>'') Begin
Get ExtractJsonStringValue of hoClient Result.sRawJson "standardizationId" to Response.sStandardizationId
If (Response.sStandardizationId='') Get ExtractJsonStringValue of hoClient Result.sRawJson "standardization_id" to Response.sStandardizationId
Move Result.sRawJson to Response.sDataJson
End

Function_Return Response
End_Function
End_Class
Loading