PC SOFT

FORUMS PROFESSIONNELS
WINDEVWEBDEV et WINDEV Mobile

Accueil → WINDEV 25 → WD - Exemplo de aplicação consumindo o Twitter via Windev, usando metodos http get, put, post, delete, codigo OOP Json e Twitter
WD - Exemplo de aplicação consumindo o Twitter via Windev, usando metodos http get, put, post, delete, codigo OOP Json e Twitter
Débuté par BOLLER ADRIANO, 14 juin 2016 14:51 - Aucune réponse
Membre enregistré
3 657 messages
Popularité : +175 (223 votes)
Posté le 14 juin 2016 - 14:51
Prezados,

Nesse post publicado pelo Hilario PEREZ CORONA, apresenta a programação necessária de como fazer um Client do Twitter.





Usa uma table do tipo programada

Código do botão Refresh
Refrescar()


Código do botão Send
IF NoSpace(EDT_Message) = "" THEN
Error("Type in a message")
ReturnToCapture(EDT_Message)
END

WHEN EXCEPTION IN
PostearMensaje(EDT_Message)
EDT_Message = ""

Refrescar()
DO
Error(ExceptionInfo())
END

ReturnToCapture(EDT_Message)







Código da janela:
Procedure WIN_Twitter_Verificacion(LOCAL gsURL is string)
EDT_Address = gsURL



Código do botão OpenBrowser
ShellExecute(EDT_Address, "open")


Código do Botão SET
// Step 3.

// In the WIN_Twitter_Verificacion window you will need to put a Text Field and a button.
// I'll assume that the field name is EDT_Verification and the button's name is EDT_Set.
// The Click code of the button must look like this:

// We set the Verification PIN to OAuth, so he can validate it...
gclOAuth:SetRequestVerifier(EDT_Verification)

WHEN EXCEPTION IN
// We validate the PIN given by the user with Twitter
// and request an Access token.
IF gclOAuth:ReqAccessToken() = False THEN
// No access token. Maybe the user typed in the PIN wrong,
// or the PIN expired...
Error("Ocurrió un error: " + gclOAuth:GetLastResponseText())
RETURN
END
DO
Error(ExceptionInfo())
RETURN
END

// If everything goes Ok, then, we get the Access Token values...
sAccessToken is string = gclOAuth:GetAccessToken()
sAccessTokenSecret is string = gclOAuth:GetAccessTokenSecret()

// OAuth has all values set, so we just change the status to "Authorized"
IF sAccessToken <> "" _AND_ sAccessTokenSecret <> "" THEN
gbTwitterAutorizado = True
END

// We save our access tokens on our INI files, so we can load
// them up when the application is started next time
INIWrite("twitter", "Token", sAccessToken, ".\twitter.ini")
INIWrite("twitter", "Secret", sAccessTokenSecret, ".\twitter.ini")

Close()



Para fazer funcionar altere o ConsumerKey (user) e ConsumerSecret (password) no Código de Projeto.

Segue códigos:

GLOBAL PROCEDURE CODE DO PROJETO - EMBED: INICIALIZING
// Step 1.

// Declare the global objects for OAuth and Twitter.
// This goes in your global project declaration.


// NOTE: AAAA is your ConsumerKey, wich NO BODY must know.
// BBBB is your ConsumerSecret, wich NO BODY must know.

// Declare the OAuth Object
gclOAuth is OAuth ("AAAA", "BBBB")

// Declare the Twitter object. This will automatically call
// the gclOAuth:Setup method with the appropiate parameters.
gclTwitt is Twitter("AAAA", gclOAuth)

// This variable is used to know if Twitter has been authorized by the user
gbTwitterAutorizado is boolean = False

// Initialize Twitter
InicializarTwitter()





INFORME NESSE CODIGO O SEU USUARIO E SENHA DO TWITTER
Procedure InicializarTwitter()

// Step 2.

// Lets see if we have Access Tokens (pre-authorized). If we do, we will just use them...
// This procedure will be called on the initialization of your program... Or on a menu item,
// or anywhere before a Twitter request is made.

// Initialize the Twitter API (maybe it's out-dated)
gclTwitt:LoadAPIFile("twitter.xml")

// We are reading an INI file, but you can read it from a FIC
// using HReadSeekFirst... It's up to you...
// It doesn't really matters if the user sees this information, he
// can't do anything with this information because he stills need
// the ConsumerKey and ConsumerSecret, so, it's safe to place
// it anywhere you like...
sAccessToken is string = INIRead("twitter", "Token", "", ".\twitter.ini")
sAccessTokenSecret is string = INIRead("twitter", "Secret", "", ".\twitter.ini")

// If we have an AccessToken, then we have Twitter Authorized on this program.
// We just have to tell our program the access tokens so OAuth can use them
// to login into the Twitter API service.
IF sAccessToken <> "" _AND_ sAccessTokenSecret <> "" THEN
gclOAuth:SetAccessTokens(sAccessToken, sAccessTokenSecret)
gbTwitterAutorizado = True
ELSE

// If we don't have our program authorized by the user...

WHEN EXCEPTION IN
// We request a Request token.
IF gclOAuth:ReqRequestToken() = False THEN
Error("Ocurrió un error: " + gclOAuth:GetLastResponseText())
RETURN
END

// We then generate a URL so the user can authorize our application
sURLAutorizacion is string = gclOAuth:GenAccessURL()

// We will open up a window and the internet browser...
// This way, the user can log into twitter and authorize
// this application for his account.
// If the user allows this application, then
// Twitter will present him a PIN, wich will have to type
// into the Text Field of the opened window
Open(WIN_Twitter_Verificacion, sURLAutorizacion)
DO
Error(ExceptionInfo())
RETURN
END
END




ENVIAR MENSAGEM
Procedure PostearMensaje(LOCAL sMensaje is string)

// We validate that twitter has been authorized
IF gbTwitterAutorizado = False THEN
Error("This application is not authorized, please restart...")
RETURN
END

// Send the message...
WHEN EXCEPTION IN
// We prepare the parameters
aaParams is associative array of strings
aaParams["status"] = NoSpace(sMensaje)

// We send the message
sJSon is string = gclTwitt:REST("POST", "statuses/update", aaParams)

// Validate that everything was ok
ValidaRespuesta(sJSon)
DO
ExceptionThrow(1, ExceptionInfo())
END




Procedure ValidaRespuesta(LOCAL sRespuesta is string)

// If the answer is "Incorrect signature", then it means
// that somebody changed the tokens, or they are not longer valid...
// We have to request new ones...
IF Position(sRespuesta, """error"":") > 0 THEN
clJSON is JSON(sRespuesta)
sError is string = clJSON.Read("error")

IF sError = "Incorrect signature" _OR_ sError = "Could not authenticate you." THEN
IF YesNo("The signature is not valid or the user has rejected the access to this application on his twitter account. Do you want to request new access tokens?") = No THEN
ExceptionThrow(1, "Twitter error response: " + sError)
END

// Clear the access tokens...
gclOAuth.SetAccessTokens("", "")
gbTwitterAutorizado = False
INIWrite("twitter", "Token", "", ".\twitter.ini")
INIWrite("twitter", "Secret", "", ".\twitter.ini")

Error("We need to request new signatures... Please authorize this application.")

// Request new access tokens
InicializarTwitter()

ExceptionThrow(1, "Please retry..." + CR + sError)
ELSE
ExceptionThrow(1, "Twitter error response: " + sError)
END
END





Procedure URLCoder(LOCAL URL is string)

URL = StringToUTF8(URL)

sNewURL is string = URLEncode(URL)
sToEncode is string = ";/?:@&=$,!~*'(|)#"

FOR i = 1 _TO_ Length(sToEncode)
HexNum is string = "%" + NumToString(Asc(sToEncode[[i]]), "02X")
sNewURL = Replace(sNewURL, sToEncode[[i]], HexNum)
END

RESULT sNewURL





Procedure URLDecoder(LOCAL URL is string)

sNewURL is string = URL
sToEncode is string = ";/?:@&=$,!~*'(|)#"

FOR i = 1 _TO_ Length(sToEncode)
HexNum is string = "%" + NumToString(Asc(sToEncode[[i]]), "02X")
sNewURL = Replace(sNewURL, HexNum, sToEncode[[i]])
END

sNewURL = URLDecode(sNewURL)

RESULT UTF8ToString(sNewURL)




PROCEDURE DA JANELA:
Procedure ObtenerDeCache(LOCAL sURL is string)

sCacheIMG is string = INIRead("Cache", sURL, "", ".\cache.ini")

IF fFileExist(sCacheIMG) THEN
RESULT sCacheIMG
END

HTTPRequest(sURL)
sCacheIMG = fTempFile()
fSaveText(sCacheIMG, HTTPGetResult(httpResult))
INIWrite("Cache", sURL, sCacheIMG, ".\cache.ini")

RESULT sCacheIMG





Procedure Refrescar()

// We validate that Twitter is authorized...
IF gbTwitterAutorizado = False THEN
Error("This application is not authorized by Twitter, please restart...")
RETURN
END

// We send the request...
WHEN EXCEPTION IN
// We pass the parameters
aaParams is associative array of strings
aaParams["count"] = 30 // Obtain only 30 messages

// We actually make the request (translated to a Twitter request using the twitter.xml file)
sJSon is string = gclTwitt:REST("GET", "statuses/home_timeline", aaParams)

// We validate that everything was ok
ValidaRespuesta(sJSon)

clJSON is JSON(sJSon)

// Delete all from our table
TableDeleteAll(TABLE_Table1)

// Display all the messages received using JSON
nTotalMsg is int = clJSON.Read("count")
FOR i = 1 _TO_ nTotalMsg
sMensaje is string = clJSON.Read("[%1].text", i)
sUsuario is string = clJSON.Read("[%1].user.name", i)
sImagen is string = clJSON.Read("[%1].user.profile_image_url", i)

TableAddLine(TABLE_Table1, ObtenerDeCache(sImagen), sUsuario, sMensaje)
END
DO
Error(ExceptionInfo())
END






CLASSES OOP

Classe Json
//--------------------------------------------------------------------------------------------------------//
//DECLARATION OF JSON

CONSTANT
JSON_TYPE_NULL = 0
JSON_TYPE_STRING = 1
JSON_TYPE_NUMERIC = 2
JSON_TYPE_OBJECT = 3
JSON_TYPE_ARRAY = 4

JSON_STATE_NONE = 0
JSON_STATE_NAME = 1
JSON_STATE_AFTERNAME = 2
JSON_STATE_VALUE = 3

JSON_SEEK_NONE = 0
JSON_SEEK_STRING = 1
JSON_SEEK_ATOM = 2
JSON_SEEK_OBJECT = 3
JSON_SEEK_ARRAY = 4
JSON_SEEK_ARRAYELEMENT = 5
END

JSON is Class

PRIVATE
Name is string
Type is int
Value is Variant
OriginalJSON is string
Properties is associative array of JSON dynamic
Items is array of 0 JSON dynamic

IsRoot is boolean
IsParsed is boolean
END


//CONSTRUCTOR
// Summary: <specify the procedure action>
// Syntax:
// Constructor (<sJSONCode> is string [, <sName> is string])
//
// Parameters:
// sJSONCode (string): <specify the role of sJSONCode>
// sName (string): <specify the role of sName>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure Constructor(LOCAL sJSONCode is string, LOCAL sName is string = "")

WHILE NOT sJSONCode[[1]] _IN_ ("{", "[", """", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "-", "t", "f", "n")
sJSONCode = sJSONCode[[2 TO]]
END

IF sName = "" THEN
:IsRoot = True
END
:Name = sName
:OriginalJSON = NoSpace(sJSONCode)
:IsParsed = True

IF :OriginalJSON _IN_ ("1", "t", "true") THEN
:Type = ::JSON_TYPE_NUMERIC
:Value = 1
ELSE IF :OriginalJSON _IN_ ("0", "f", "false") THEN
:Type = ::JSON_TYPE_NUMERIC
:Value = 0
ELSE IF :OriginalJSON = "null" THEN
:Type = ::JSON_TYPE_NULL
:Value = Null
ELSE
SWITCH :OriginalJSON[[1]]
CASE "{":
:Type = ::JSON_TYPE_OBJECT
:IsParsed = False
:Value = :OriginalJSON[[2 TO Length(:OriginalJSON) - 1]]
CASE "[":
:Type = ::JSON_TYPE_ARRAY
:IsParsed = False
CASE """":
:Type = ::JSON_TYPE_STRING
:Value = :FixString(:OriginalJSON[[2 TO Length(:OriginalJSON) - 1]])
OTHER CASE
:Type = ::JSON_TYPE_NUMERIC
xNumber is numeric = :OriginalJSON
:Value = xNumber
END
END

IF :IsParsed THEN
:OriginalJSON = ""
END



//DESTRUCTOR
// Summary: <specify the procedure action>
// Syntax:
// Destructor ()
//
// Parameters:
// None
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure Destructor()

:Release()



//PARSE
Procedure PRIVATE Parse()

IF :Type _IN_ (::JSON_TYPE_NULL, ::JSON_TYPE_NUMERIC, ::JSON_TYPE_STRING) THEN
:IsParsed = True
RETURN
END

bToSelf is boolean = False

nState is int = ::JSON_STATE_NONE
nSeek is int = ::JSON_SEEK_NONE

sChar is string = ""

sTokenName is string = ""
sTokenValue is string = ""
sLastToken is string = ""

bAllow is boolean = False
bFinished is boolean = False

nObjOpened is int
nArrOpened is int
bEscapeStr is boolean
bInsideString is boolean
bArrayFinished is boolean
bIsLastChar is boolean

pclItem is JSON dynamic

FOR i = 1 _TO_ Length(:OriginalJSON)
bIsLastChar = i = Length(:OriginalJSON)

sChar = :OriginalJSON[[i]]
bAllow = False

IF nState _IN_ (::JSON_STATE_NONE, ::JSON_STATE_AFTERNAME) THEN
IF NOT sChar _IN_ ("""", "{", "[", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "n", "t", "f", "-") THEN
CONTINUE
END

bEscapeStr = False
bInsideString = False
SWITCH sChar
CASE """":
bToSelf = False
IF nState = ::JSON_STATE_NONE THEN
sTokenName = """"
sTokenValue = ""
nState = ::JSON_STATE_NAME
nSeek = ::JSON_SEEK_STRING
sLastToken = sTokenName
ELSE
sTokenValue = """"
nState = ::JSON_STATE_VALUE
nSeek = ::JSON_SEEK_STRING
sLastToken = sTokenValue
END
bInsideString = True
CASE "{":
IF nState = ::JSON_STATE_NONE THEN
sTokenName = ""
bToSelf = True
END
nState = ::JSON_STATE_VALUE
nSeek = ::JSON_SEEK_OBJECT
sLastToken = ""
nObjOpened = 1
sTokenValue = ""
CASE "[":
IF nState = ::JSON_STATE_NONE THEN
sTokenName = ""
bToSelf = True
END
nState = ::JSON_STATE_VALUE
IF bToSelf THEN
nSeek = ::JSON_SEEK_ARRAYELEMENT
bArrayFinished = False
sTokenValue = ""
ELSE
nSeek = ::JSON_SEEK_ARRAY
sTokenValue = "["
END
sLastToken = ""
nArrOpened = 1
nObjOpened = 0
OTHER CASE
IF nState = ::JSON_STATE_NONE THEN
sTokenName = ""
bToSelf = True
END
sTokenValue = sChar
nState = ::JSON_STATE_VALUE
nSeek = ::JSON_SEEK_ATOM
sLastToken = sTokenValue
END
bFinished = False

IF bIsLastChar THEN
bFinished = True
bArrayFinished = True
sTokenValue = ""
ELSE
CONTINUE
END
END

IF bInsideString THEN
IF sChar = """" _AND_ bEscapeStr = False THEN
bInsideString = False
ELSE IF bEscapeStr = False _AND_ sChar = "\" THEN
IF nSeek <> ::JSON_SEEK_STRING THEN
bEscapeStr = True
END
ELSE IF bEscapeStr THEN
IF nSeek <> ::JSON_SEEK_STRING THEN
bEscapeStr = False
END
END
END

SWITCH nSeek
CASE ::JSON_SEEK_ARRAY:
bAllow = True
IF bInsideString = False THEN
IF sChar = "[" THEN
nArrOpened++
ELSE IF sChar = "]" THEN
nArrOpened--

IF nArrOpened = 0 THEN
bAllow = True
bFinished = True
END
END
END
CASE ::JSON_SEEK_ARRAYELEMENT:
bAllow = True
IF bInsideString = False THEN
IF sChar = "[" THEN
nArrOpened++
ELSE IF sChar = "{" THEN
nObjOpened++
ELSE IF sChar = "}" THEN
nObjOpened--
ELSE IF sChar = "]" THEN
nArrOpened--

IF nObjOpened = 0 AND nArrOpened = 0 THEN
bAllow = False
bFinished = True
bArrayFinished = True
END
END

IF nObjOpened = 0 AND nArrOpened = 1 _AND_ sChar = "," THEN
bAllow = False
bFinished = True
END
END
CASE ::JSON_SEEK_ATOM:
IF Position("truefalsenull0123456789.", sChar) < 1 THEN
bFinished = True
ELSE IF bIsLastChar THEN
bFinished = True
bAllow = True
ELSE
bAllow = True
END
CASE ::JSON_SEEK_OBJECT:
bAllow = True
IF bInsideString = False THEN
IF sChar = "{" THEN
nObjOpened++
ELSE IF sChar = "}" THEN
nObjOpened--

IF nObjOpened = 0 THEN
bAllow = False
bFinished = True
END
END
END
CASE ::JSON_SEEK_STRING:
IF bInsideString = False THEN
bAllow = True
bFinished = True
ELSE IF bEscapeStr = False _AND_ sChar = "\" THEN
bAllow = True
bEscapeStr = True
ELSE IF bEscapeStr THEN
IF NOT sChar _IN_ (Charact(13), Charact(10)) THEN
bAllow = True
END
bEscapeStr = False
ELSE
bAllow = True
END
OTHER CASE
END

IF bAllow THEN
IF nState = ::JSON_STATE_NAME THEN
sTokenName += sChar
sLastToken = sTokenName
ELSE IF nState = ::JSON_STATE_VALUE THEN
sTokenValue += sChar
sLastToken = sTokenValue
END
END
IF bFinished THEN
IF nState = ::JSON_STATE_VALUE THEN
IF bToSelf THEN
IF nSeek = ::JSON_SEEK_ARRAYELEMENT THEN
nNextElem is int = ArrayCount(:Items) + 1
pclItem = new JSON(sTokenValue, "[" + nNextElem + "]")
ArrayAdd(:Items, pclItem)

pclItem = :Properties["count"]
IF pclItem = Null THEN
pclItem = new JSON("1", "count")
:Properties["count"] = pclItem
ELSE
pclItem:Value = ArrayCount(:Items)
END

sTokenValue = ""
IF bArrayFinished THEN
nSeek = ::JSON_SEEK_NONE
ELSE
bFinished = False
END
ELSE IF nSeek = ::JSON_SEEK_OBJECT THEN
:OriginalJSON = sTokenValue
:Parse()
RETURN
ELSE
ExceptionThrow(1,"Bad seek for self")
END
ELSE
sItemName is string = sTokenName[[2 TO Length(sTokenName) - 1]]

pclItem = :Properties[sItemName]
IF pclItem <> Null THEN
ExceptionThrow(1,"Repeated property: " + sItemName + " under " + :Name)
END

IF nSeek = ::JSON_SEEK_OBJECT THEN
sTokenValue = "{" + sTokenValue + "}"
END

pclItem = new JSON(sTokenValue, sItemName)
:Properties[sItemName] = pclItem

nState = ::JSON_STATE_NONE
sTokenValue = ""
sTokenName = ""
END
ELSE IF nState = ::JSON_STATE_NAME THEN
nState = ::JSON_STATE_AFTERNAME
sTokenValue = ""
ELSE
ExceptionThrow(1,"Bad state")
END
END
END

:IsParsed = True
:OriginalJSON = ""



//RELEASE
Procedure PRIVATE Release()

sProp is string
pclVal is JSON dynamic
FOR EACH ELEMENT pclVal, sProp OF :Properties
Delete pclVal
END

ArrayDeleteAll(:Properties)

FOR i = 1 _TO_ :Items..Occurrence
pclVal = :Items[i]
Delete pclVal
END

ArrayDeleteAll(:Items)



//METHOD READ
// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] Read (<sPath> is string [, ...])
//
// Parameters:
// sPath (string): <specify the role of sPath>
// Return Value:
// Unspecified Type: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure Read(LOCAL sPath is string, *)

IF NOT :IsParsed THEN
:Parse()
END

IF sPath = "" THEN
RESULT :Value
END

IF MyParameters..Occurrence > 1 THEN
FOR i = MyParameters..Occurrence _TO_ 2 STEP -1
sPath = Replace(sPath, "%" + (i - 1), MyParameters[i])
END
END

pclValueToReturn is JSON dynamic

nIdx is int = 0
IF sPath[[1]] = "[" THEN
nCloseBrac is int = Position(sPath, "]")
nIdx = sPath[[2 TO nCloseBrac - 1]]
sPath = sPath[[nCloseBrac + 1 TO]]
IF sPath[[1]] = "." THEN
sPath = sPath[[2 TO]]
END
END

nFirstDot is int = Position(sPath, ".")
nFirstBracket is int = Position(sPath, "[")

nTo is int = nFirstDot
IF nFirstDot < 1 _OR_ (nFirstDot > nFirstBracket _AND_ nFirstBracket > 1) THEN
nTo = nFirstBracket
END
IF nTo < 1 THEN
nTo = Length(sPath)
ELSE
nTo -= 1
END


sFirstPart is string = sPath[[1 TO nTo]]
sLastPart is string = sPath[[nTo + 1 TO]]
IF sLastPart[[1]] = "." THEN
sLastPart = sLastPart[[2 TO]]
END

IF nIdx > 0 THEN
sFirstPart = ""
sLastPart = sPath
END

IF nIdx > 0 THEN
IF nIdx > ArrayCount(:Items) THEN
ExceptionThrow(1,"Array index overflow, asking for " + nIdx + " when i have only " + :Items..Occurrence)
END

pclValueToReturn = :Items[nIdx]
ELSE
pclValueToReturn = :Properties[sFirstPart]
END

IF pclValueToReturn = Null THEN
NUllValue is Variant = Null
RESULT NUllValue
END
RESULT pclValueToReturn:Read(sLastPart)



//FIX STRING
Procedure PRIVATE FixString(LOCAL sRawString is string)

sNewString is string = sRawString
vMyVari is Variant
nMy2byte is 2-byte unsigned int
nMyCurPos is int = Position(sNewString,"\u")
WHILE nMyCurPos > 0
sHexVal is string = sNewString[[nMyCurPos + 2 TO nMyCurPos + 5]]
nMy2byte = Val(sHexVal,"x")
vMyVari = nMy2byte
VariantConvert(vMyVari,wlBinaryString)
sMyUnistr is UNICODE string = vMyVari
sMyNormStr is string = UnicodeToAnsi(sMyUnistr)
sNewString = Replace(sNewString, "\u" + sHexVal, sMyNormStr[[1]])

nMyCurPos = Position(sNewString,"\u")
END

sNewString = Replace(sNewString, "\""", """")
sNewString = Replace(sNewString, "\n", CR)
sNewString = Replace(sNewString, "\t", TAB)
sNewString = Replace(sNewString, "\r", Charact(10))
sNewString = Replace(sNewString, "\/", "/")
sNewString = Replace(sNewString, "\b", "")
sNewString = Replace(sNewString, "\f", "")
sNewString = Replace(sNewString, "\\", "\")

RESULT sNewString

//--------------------------------------------------------------------------------------------------------//




Classe OAuth
//--------------------------------------------------------------------------------------------------------//
//DECLARATION
STOAuthResponse is structure

ErrorCode is int
ErrorMessage is string

Headers is string
response is string

END

OAuth is Class

PRIVATE

State is int
LastResponse is STOAuthResponse dynamic

// Datos de la aplicacion que lee del proveedor de servicio
ConsumerKey is string
ConsumerSecret is string

// Datos temporales para intercambiar por un token de acceso
RequestToken is string
RequestTokenSecret is string
CallbackConfirmed is boolean
RequestVerifier is string

// Token de acceso para realizar peticiones
AccessToken is string
AccessTokenSecret is string
UserID is string
ScreenName is string

Callback is string

RequestTokenURL is string
AccessTokenURL is string
AuthorizeURL is string

SignatureMethod is string = "HMAC-SHA1"
Version is string = "1.0"

CONSTANT
STATE_DEFAULT = 0
STATE_HAVEREQUEST_TOKEN = 1
STATE_ACCESS_GRANTED = 2

oauth_callback = "oauth_callback"
oauth_consumer_key = "oauth_consumer_key"
oauth_nonce = "oauth_nonce"
oauth_signature_method = "oauth_signature_method"
oauth_timestamp = "oauth_timestamp"
oauth_version = "oauth_version"
oauth_signature = "oauth_signature"
oauth_token = "oauth_token"
oauth_token_secret = "oauth_token_secret"
oauth_callback_confirmed = "oauth_callback_confirmed"
oauth_verifier = "oauth_verifier"
user_id = "user_id"
screen_name = "screen_name"
END
END


// Summary: <specify the procedure action>
// Syntax:
// Constructor (<sCunsomerKey> is string, <sCunsomerSecret> is string [, <sCallback> is string])
//
// Parameters:
// sCunsomerKey (string): <specify the role of sCunsomerKey>
// sCunsomerSecret (string): <specify the role of sCunsomerSecret>
// sCallback (string): <specify the role of sCallback>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure Constructor(LOCAL sCunsomerKey is string, LOCAL sCunsomerSecret is string, LOCAL sCallback is string = "")

:ConsumerKey = sCunsomerKey
:ConsumerSecret = sCunsomerSecret
:Callback = sCallback


//DESTRUCTOR
// Summary: <specify the procedure action>
// Syntax:
// Destructor ()
//
// Parameters:
// None
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure Destructor()
//NADA


//METHOD SETUP
// Summary: <specify the procedure action>
// Syntax:
// Setup (<sRequestTokenURL> is string, <sAccessTokenURL> is string, <sAuthorizeURL> is string, <sVersion> is string, <sSignatureMethod> is string)
//
// Parameters:
// sRequestTokenURL (string): <specify the role of sRequestTokenURL>
// sAccessTokenURL (string): <specify the role of sAccessTokenURL>
// sAuthorizeURL (string): <specify the role of sAuthorizeURL>
// sVersion (string): <specify the role of sVersion>
// sSignatureMethod (string): <specify the role of sSignatureMethod>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure Setup(LOCAL sRequestTokenURL is string, LOCAL sAccessTokenURL is string, LOCAL sAuthorizeURL is string, LOCAL sVersion is string, LOCAL sSignatureMethod is string)

:RequestTokenURL = sRequestTokenURL
:AccessTokenURL = sAccessTokenURL
:AuthorizeURL = sAuthorizeURL
:Version = sVersion
:SignatureMethod = sSignatureMethod


//METHOD SINGREQUEST
// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] SignRequest (<sRequest> is string)
//
// Parameters:
// sRequest (string): <specify the role of sRequest>
// Return Value:
// string: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure SignRequest(LOCAL sRequest is string)

sBinarySigned is string = HashString(HA_HMAC_SHA_160,sRequest,:ConsumerSecret + "&" + (NoSpace(:RequestTokenSecret) + NoSpace(:AccessTokenSecret)))

sRequestSigned is string = Replace(Crypt(sBinarySigned, "", cryptNone, encodeBASE64), CR, "")

RESULT sRequestSigned


//METHOD BUILDREQUEST
Procedure PRIVATE BuildRequest(LOCAL sMethod is string, LOCAL sRequest is string, pclParams is OAuthParams dynamic)

sToSign is string = Upper(sMethod) + "&" + URLCoder(sRequest) + "&" + pclParams:BuildRequest()

RESULT sToSign


//METHOD CREATETIMESTAMP
Procedure PRIVATE CreateTimestamp()

dtFecInicial is DateTime = "19700101000001000"

dtFechaActual is DateTime = DateTimeLocalToUTC(Today() + Now())

sStrDur is string = DateTimeDifference(dtFecInicial, dtFechaActual)
duDuration is Duration = StringToDuration(sStrDur,durationCenti)
Timestamp is string = duDuration..InMilliseconds
RESULT Timestamp[[1 TO 10]]


//METHOD PLACEREQUEST
//METHOD PlaceRequest
Procedure PRIVATE PlaceRequest(LOCAL sMethod is string, LOCAL sRequest is string, pclParams is OAuthParams dynamic, pclBodyParams is OAuthParams dynamic = Null)

response is STOAuthResponse dynamic = new STOAuthResponse()

nMethod is int
SWITCH Upper(sMethod)
CASE "GET":
nMethod = httpGet;
CASE "PUT":
nMethod = httpPut;
CASE "POST":
nMethod = httpPost;
CASE "DELETE":
nMethod = httpDelete;
OTHER CASE
ExceptionThrow(1,"Method not supported: " + sMethod + ", please choose GET,PUT,POST,DELETE")
END

bPudo is boolean = False

IF pclBodyParams <> Null THEN
pclBodyParams:ApplyTo(pclParams)
END

PostFormName is string = ""
IF nMethod = httpGet THEN
clEmptyParams is OAuthParams = ""

sSignature is string = :SignRequest(:BuildRequest(sMethod, sRequest, pclParams))
pclParams:AddEnc(::oauth_signature, sSignature)

sNewGETUrl is string = sRequest + "?" + pclParams:BuildForm()

bPudo = HTTPRequest(sNewGETUrl, "OAuth for WinDev")
ELSE
PostFormName = "FORM_OAUTH_" + Random(1, 99999999)

sSignature = :SignRequest(:BuildRequest(sMethod, sRequest, pclParams))
pclParams:AddEnc(::oauth_signature, sSignature)

HTTPCreateForm(PostFormName)

sHeaders is string = ""
IF pclParams:HasFile() THEN
pclBodyParams:RemoveFrom(pclParams)
sHeaders = "Authorization:" + pclParams:BuildHeader()
pclBodyParams:BuildPostForm(PostFormName)
ELSE
pclParams:BuildPostForm(PostFormName)
END

bPudo = HTTPSendForm(PostFormName, sRequest, nMethod, "OAuth for WinDev", sHeaders)
END

IF NOT bPudo THEN
response:ErrorCode = ErrorInfo(errCode)
response:ErrorMessage = ErrorInfo(errMessage)

ExceptionThrow(1,StringBuild("Error #%1: %2", response:ErrorCode, response:ErrorMessage))
ELSE
response:Headers = HTTPGetResult(httpHeader)
response:response = HTTPGetResult(httpResult)
END

RESULT response

END:

IF PostFormName <> "" THEN
HTTPCancelForm(PostFormName)
END


//METHOD CreateUniqueString
Procedure PRIVATE CreateUniqueString()

sUStr is string = :CreateTimestamp() + ",WinDev OAuth Framework,For Free Use" + :ConsumerKey

SignedUStr is string = Replace(Crypt(HashString(HA_HMAC_SHA_160,sUStr,"Not Necesary"),"",cryptNone,encodeBASE64),CR,"")

sHexStr is string = ""

FOR i = 1 _TO_ Length(SignedUStr)
nVasc is int = Asc(SignedUStr[[i]])
sHexStr += NumToString(nVasc, "00x")
END

RESULT sHexStr


//METHOD ReqRequestToken
// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] ReqRequestToken ()
//
// Parameters:
// None
// Return Value:
// boolean: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure ReqRequestToken()

:State = ::STATE_DEFAULT
:RequestToken = ""
:RequestTokenSecret = ""
:CallbackConfirmed = False
:RequestVerifier = ""
:AccessToken = ""
:AccessTokenSecret = ""

pclParams is OAuthParams dynamic = new OAuthParams()
IF :Callback <> "" THEN
pclParams:AddEnc(::oauth_callback, :Callback)
END
pclParams:AddEnc(::oauth_consumer_key, :ConsumerKey)
pclParams:Add(::oauth_nonce, :CreateUniqueString())
pclParams:Add(::oauth_signature_method, :SignatureMethod)
pclParams:Add(::oauth_timestamp, :CreateTimestamp())
pclParams:Add(::oauth_version, :Version)
pclParams:Add(::oauth_token, "")

IF :LastResponse <> Null THEN
Delete :LastResponse
END
:LastResponse = :PlaceRequest("POST", :RequestTokenURL, pclParams)
Delete pclParams

IF :LastResponse.ErrorCode = 0 THEN
aaValues is associative array of strings
:TokenizeParams(:LastResponse.response, aaValues)

:RequestToken = aaValues[::oauth_token]
:RequestTokenSecret = aaValues[::oauth_token_secret]
:CallbackConfirmed = aaValues[::oauth_callback_confirmed] ~= "true"

IF :RequestToken <> "" THEN
:State = ::STATE_HAVEREQUEST_TOKEN
END
ELSE
ExceptionThrow(1, StringBuild("Error #%1: %2", :LastResponse.ErrorCode, :LastResponse.ErrorMessage))
END

RESULT :LastResponse.ErrorCode = 0


// Summary: <specify the procedure action>
// Syntax:
// TokenizeParams (<sQuery> is string, <aaParams> is associative array)
//
// Parameters:
// sQuery (string): <specify the role of sQuery>
// aaParams (associative array): <specify the role of aaParams>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure TokenizeParams(LOCAL sQuery is string, aaParams is associative array of strings)

sParam is string
sName is string
sValue is string

FOR EACH STRING sParam OF sQuery SEPARATED by "&"
sName = ExtractString(sParam, 1, "=")
sValue = ExtractString(sParam, 2, "=")
aaParams[sName] = URLDecoder(sValue)
END


//METHOD GenAccessURL
// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] GenAccessURL ()
//
// Parameters:
// None
// Return Value:
// string: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure GenAccessURL()

IF :State < ::STATE_HAVEREQUEST_TOKEN THEN
ExceptionThrow(1,"You do not have a request token")
END

sQueryURL is string = StringBuild("%1?%2=%3", :AuthorizeURL, ::oauth_token, :RequestToken)

RESULT sQueryURL


// Summary: <specify the procedure action>
// Syntax:
// SetRequestVerifier (<sVerifier> is string)
//
// Parameters:
// sVerifier (string): <specify the role of sVerifier>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure SetRequestVerifier(LOCAL sVerifier is string)

IF :State < ::STATE_HAVEREQUEST_TOKEN THEN
ExceptionThrow(1,"You do not have a request token")
END

:RequestVerifier = sVerifier


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] ReqAccessToken ()
//
// Parameters:
// None
// Return Value:
// boolean: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure ReqAccessToken()

IF :State < ::STATE_HAVEREQUEST_TOKEN THEN
ExceptionThrow(1,"You do not have a request token")
END

IF :RequestVerifier = "" THEN
ExceptionThrow(1,"You do not have the PIN or the Verifier")
END

:AccessToken = ""
:AccessTokenSecret = ""
:UserID = ""
:ScreenName = ""

pclParams is OAuthParams dynamic = new OAuthParams()
pclParams:AddEnc(::oauth_consumer_key, :ConsumerKey)
pclParams:AddEnc(::oauth_nonce, :CreateUniqueString())
pclParams:Add(::oauth_signature_method, :SignatureMethod)
pclParams:Add(::oauth_timestamp, :CreateTimestamp())
pclParams:Add(::oauth_version, :Version)
pclParams:AddEnc(::oauth_token, :RequestToken)
pclParams:AddEnc(::oauth_verifier, :RequestVerifier)

IF :LastResponse <> Null THEN
Delete :LastResponse
END
:LastResponse = :PlaceRequest("POST", :AccessTokenURL, pclParams)
Delete pclParams

IF :LastResponse.ErrorCode = 0 THEN
aaValues is associative array of strings
:TokenizeParams(:LastResponse.response, aaValues)

:AccessToken = aaValues[::oauth_token]
:AccessTokenSecret = aaValues[::oauth_token_secret]
:UserID = aaValues[::user_id]
:ScreenName = aaValues[::screen_name]
:RequestToken = ""
:RequestTokenSecret = ""

IF :AccessToken <> "" THEN
:State = ::STATE_ACCESS_GRANTED
END
ELSE
ExceptionThrow(1, StringBuild("Error #%1: %2", :LastResponse.ErrorCode, :LastResponse.ErrorMessage))
END

RESULT :LastResponse.ErrorCode = 0


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] ReqProvider (<sMethod> is string, <sRequestURL> is string, <pclBodyParams> is OAuthParams dynamic)
//
// Parameters:
// sMethod (string): <specify the role of sMethod>
// sRequestURL (string): <specify the role of sRequestURL>
// pclBodyParams (OAuthParams dynamic): <specify the role of pclBodyParams>
// Return Value:
// boolean: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure ReqProvider(LOCAL sMethod is string, LOCAL sRequestURL is string, pclBodyParams is OAuthParams dynamic)

pclParams is OAuthParams dynamic = new OAuthParams()
IF :State >= ::STATE_ACCESS_GRANTED THEN
pclParams:AddEnc(::oauth_consumer_key, :ConsumerKey)
pclParams:Add(::oauth_nonce, :CreateUniqueString())
pclParams:Add(::oauth_signature_method, :SignatureMethod)
pclParams:Add(::oauth_timestamp, :CreateTimestamp())
pclParams:Add(::oauth_version, :Version)
pclParams:AddEnc(::oauth_token, :AccessToken)
END

IF :LastResponse <> Null THEN
Delete :LastResponse
END
:LastResponse = :PlaceRequest(sMethod, sRequestURL, pclParams, pclBodyParams)
Delete pclParams

IF :LastResponse.ErrorCode <> 0 THEN
ExceptionThrow(1, StringBuild("Error #%1: %2", :LastResponse.ErrorCode, :LastResponse.ErrorMessage))
END

RESULT :LastResponse.ErrorCode = 0


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] GetState ()
//
// Parameters:
// None
// Return Value:
// int: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure GetState()

RESULT :State


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] GetLastResponse ()
//
// Parameters:
// None
// Return Value:
// STOAuthResponse dynamic: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure GetLastResponse()

RESULT :LastResponse


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] GetLastResponseText ()
//
// Parameters:
// None
// Return Value:
// string: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure GetLastResponseText()

IF :LastResponse = Null THEN
ExceptionThrow(1,"There is no last response available")
END

RESULT :LastResponse:Response


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] GetUserID ()
//
// Parameters:
// None
// Return Value:
// string: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure GetUserID()

RESULT :UserID


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] GetScreenName ()
//
// Parameters:
// None
// Return Value:
// string: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure GetScreenName()

RESULT :ScreenName


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] GetAccessToken ()
//
// Parameters:
// None
// Return Value:
// string: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure GetAccessToken()

RESULT :AccessToken


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] GetAccessTokenSecret ()
//
// Parameters:
// None
// Return Value:
// string: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure GetAccessTokenSecret()

RESULT :AccessTokenSecret


// Summary: <specify the procedure action>
// Syntax:
// SetAccessTokens (<sToken> is string, <sSecret> is string)
//
// Parameters:
// sToken (string): <specify the role of sToken>
// sSecret (string): <specify the role of sSecret>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure SetAccessTokens(LOCAL sToken is string, LOCAL sSecret is string)

:AccessToken = sToken
:AccessTokenSecret = sSecret
:RequestToken = ""
:RequestTokenSecret = ""

IF :AccessToken <> "" _AND_ :AccessTokenSecret <> "" THEN
:State = ::STATE_ACCESS_GRANTED
ELSE
:State = ::STATE_DEFAULT
END


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] GetRequestToken ()
//
// Parameters:
// None
// Return Value:
// string: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure GetRequestToken()

RESULT :RequestToken

//--------------------------------------------------------------------------------------------------------//


Classe OAuthParams
//--------------------------------------------------------------------------------------------------------//
STOAuthParam is structure
Key is string
Value is string
IsFile is boolean
ContentBase64 is Buffer
END

OAuthParams is Class
PRIVATE
Params is array of 0 STOAuthParam
END


// Summary: <specify the procedure action>
// Syntax:
// Constructor ()
//
// Parameters:
// None
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure Constructor()


// Summary: <specify the procedure action>
// Syntax:
// Destructor ()
//
// Parameters:
// None
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure Destructor()


// Summary: <specify the procedure action>
// Syntax:
// Add (<sKey> is string, <sValue> is string)
//
// Parameters:
// sKey (string): <specify the role of sKey>
// sValue (string): <specify the role of sValue>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure Add(LOCAL sKey is string, LOCAL sValue is string)

nIdx is int = ArraySeek(:Params,asLinear,"Key",sKey)
IF nIdx < 1 THEN
stMyParam is STOAuthParam
stMyParam:Key = sKey
stMyParam:Value = sValue
ArrayAdd(:Params, stMyParam)
ELSE
:Params[nIdx]:Value = sValue
END


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] BuildRequest ()
//
// Parameters:
// None
// Return Value:
// Unspecified Type: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure BuildRequest()

ArraySort(:Params,asMember,"Key;Value")

sQuery is Buffer = ""
FOR i = 1 _TO_ :Params..Occurrence
IF sQuery <> "" THEN
sQuery += "&"
END
IF :Params[i]:IsFile THEN
sQuery += :Params[i]:Key + "=" + :Params[i]:ContentBase64
ELSE
sQuery += :Params[i]:Key + "=" + :Params[i]:Value
END
END

RESULT URLCoder(sQuery)


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] BuildHeader ()
//
// Parameters:
// None
// Return Value:
// string: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure BuildHeader()

IF :Params..Occurrence = 0 THEN
RESULT ""
END

ArraySort(:Params,asMember,"Key;Value")

sQuery is string = ""
FOR i = 1 _TO_ :Params..Occurrence
IF sQuery <> "" THEN
sQuery += ", "
END
sQuery += :Params[i]:Key + "=""" + :Params[i]:Value + """"
END

RESULT "OAuth " + sQuery


// Summary: <specify the procedure action>
// Syntax:
// AddEnc (<sKey> is string, <sValue> is string)
//
// Parameters:
// sKey (string): <specify the role of sKey>
// sValue (string): <specify the role of sValue>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure AddEnc(LOCAL sKey is string, LOCAL sValue is string)

:Add(sKey, URLCoder(sValue))


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] BuildForm ()
//
// Parameters:
// None
// Return Value:
// string: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure BuildForm()

ArraySort(:Params,asMember,"Key;Value")

sQuery is string = ""
FOR i = 1 _TO_ :Params..Occurrence
IF sQuery <> "" THEN
sQuery += "&"
END
sQuery += :Params[i]:Key + "=" + :Params[i]:Value
END

RESULT sQuery


// Summary: <specify the procedure action>
// Syntax:
// ApplyTo (<pclOtherParams> is OAuthParams dynamic)
//
// Parameters:
// pclOtherParams (OAuthParams dynamic): <specify the role of pclOtherParams>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure ApplyTo(pclOtherParams is OAuthParams dynamic)

FOR i = 1 _TO_ :Params..Occurrence
IF :Params[i]:IsFile THEN
pclOtherParams:AddFile(:Params[i]:Key, :Params[i]:Value)
ELSE
pclOtherParams:Add(:Params[i]:Key, :Params[i]:Value)
END
END


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] HasParams ()
//
// Parameters:
// None
// Return Value:
// boolean: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure HasParams()

RESULT :Params..Occurrence > 0


// Summary: <specify the procedure action>
// Syntax:
// RemoveFrom (<pclOtherAuth> is OAuthParams dynamic)
//
// Parameters:
// pclOtherAuth (OAuthParams dynamic): <specify the role of pclOtherAuth>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure RemoveFrom(pclOtherAuth is OAuthParams dynamic)

FOR i = 1 _TO_ :Params..Occurrence
pclOtherAuth:Remove(:Params[i]:Key)
END


// Summary: <specify the procedure action>
// Syntax:
// Remove (<sKey> is string)
//
// Parameters:
// sKey (string): <specify the role of sKey>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure Remove(LOCAL sKey is string)

nIdx is int = ArraySeek(:Params,asLinear,"Key",sKey)
IF nIdx > 0 THEN
ArrayDelete(:Params,nIdx)
END


// Summary: <specify the procedure action>
// Syntax:
// BuildPostForm (<FormName>)
//
// Parameters:
// FormName: <specify the role of FormName>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure BuildPostForm(LOCAL FormName)

ArraySort(:Params,asMember,"Key;Value")

FOR i = 1 _TO_ :Params..Occurrence
IF :Params[i]:IsFile THEN
HTTPAddFile(FormName, :Params[i]:Key, :Params[i]:Value)
ELSE
HTTPAddParameter(FormName, :Params[i]:Key, URLDecode(:Params[i]:Value))
END
END


// Summary: <specify the procedure action>
// Syntax:
// AddFile (<sKey> is string, <sPath> is string)
//
// Parameters:
// sKey (string): <specify the role of sKey>
// sPath (string): <specify the role of sPath>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure AddFile(LOCAL sKey is string, LOCAL sPath is string)

IF NOT fFileExist(sPath) THEN
ExceptionThrow(1,"File not found " + sPath)
END

sContent is Buffer = fLoadText(sPath)
//InBase64 is string = replace(crypt(scontent,"",cryptNone,encodeBASE64), cr, "")

nIdx is int = ArraySeek(:Params,asLinear,"Key",sKey)
IF nIdx < 1 THEN
stMyParam is STOAuthParam
stMyParam:Key = sKey
stMyParam:Value = sPath
stMyParam:IsFile = True
stMyParam:ContentBase64 = sContent
ArrayAdd(:Params, stMyParam)
ELSE
:Params[nIdx]:Value = sPath
:Params[nIdx]:IsFile = True
:Params[nIdx]:ContentBase64 = sContent
END


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] HasFile ()
//
// Parameters:
// None
// Return Value:
// boolean: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure HasFile()

FOR i = 1 _TO_ :Params..Occurrence
IF NOT :Params[i]:isfile THEN CONTINUE

RESULT True
END

RESULT False

//--------------------------------------------------------------------------------------------------------//

Classe Twitter
//--------------------------------------------------------------------------------------------------------//
Twitter is Class

PRIVATE
APIXMLName is string

APIKey is string
Auth is OAuth dynamic
Secure is boolean = True
Format is string = "json"
APIVersion is string = "1"

Resources is associative array of int

CONSTANT
TWITTER_REQUEST_TOKEN_URL = "https://api.twitter.com/oauth/request_token"
TWITTER_ACCESS_TOKEN_URL = "https://api.twitter.com/oauth/access_token"
TWITTER_AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize"
TWITTER_OAUTH_VERSION = "1.0"
TWITTER_OAUTH_SIGNATURE_METHOD = "HMAC-SHA1"
END

GLOBAL
TWITTER_COUNT is int = 0
END


// Summary: <specify the procedure action>
// Syntax:
// Constructor (<sAPIKey> is string, <pclAuth> is OAuth dynamic)
//
// Parameters:
// sAPIKey (string): <specify the role of sAPIKey>
// pclAuth (OAuth dynamic): <specify the role of pclAuth>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure Constructor(LOCAL sAPIKey is string, pclAuth is OAuth dynamic)

::TWITTER_COUNT++
:APIXMLName = "TWITXML" + ::TWITTER_COUNT
:APIKey = sAPIKey
:Auth = pclAuth
:Auth:Setup(::TWITTER_REQUEST_TOKEN_URL, ::TWITTER_ACCESS_TOKEN_URL, ::TWITTER_AUTHORIZE_URL, ::TWITTER_OAUTH_VERSION, ::TWITTER_OAUTH_SIGNATURE_METHOD)


// Summary: <specify the procedure action>
// Syntax:
// Destructor ()
//
// Parameters:
// None
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure Destructor()

XMLClose(:APIXMLName)


// Summary: <specify the procedure action>
// Syntax:
// LoadAPIFile (<sFileName> is string)
//
// Parameters:
// sFileName (string): <specify the role of sFileName>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure LoadAPIFile(LOCAL sFileName is string)

sApixml is string = fLoadText(sFileName)
:LoadAPIString(sApixml)


// Summary: <specify the procedure action>
// Syntax:
// LoadAPIString (<sAPIXML> is string)
//
// Parameters:
// sAPIXML (string): <specify the role of sAPIXML>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure LoadAPIString(LOCAL sAPIXML is string)

XMLClose(:APIXMLName)

XMLDocument(:APIXMLName, sAPIXML)

ArrayDeleteAll(:Resources)

nTotalRes is int
XMLExecuteXPath(:APIXMLName,"count(/resources/resource)")
nTotalRes = XMLResult(:APIXMLName)

FOR i = 1 _TO_ nTotalRes
sMethods is string = XMLRead(:APIXMLName,"/resources/resource[" + i + "]/@method","GET")
sName is string = XMLRead(:APIXMLName,"/resources/resource[" + i + "]/@name", "")

sMethod is string
FOR EACH STRING sMethod OF sMethods SEPARATED by ","
:Resources[Upper(sMethod) + "|" + sName] = i
END
END


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] IsSecure ()
//
// Parameters:
// None
// Return Value:
// boolean: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure IsSecure()

RESULT :Secure


// Summary: <specify the procedure action>
// Syntax:
// SetSecure (<bSecure> is boolean)
//
// Parameters:
// bSecure (boolean): <specify the role of bSecure>
// Return Value:
// None
//
// For instance:
// Indicate an example.
//
Procedure SetSecure(LOCAL bSecure is boolean)

:Secure = bSecure


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] REST (<Method> is string, <Resource> is string, <aaParams> is associative array [, <sFormat> is string])
//
// Parameters:
// Method (string): <specify the role of Method>
// Resource (string): <specify the role of Resource>
// aaParams (associative array): <specify the role of aaParams>
// sFormat (string): <specify the role of sFormat>
// Return Value:
// string: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure REST(LOCAL Method is string, LOCAL Resource is string, aaParams is associative array of string, LOCAL sFormat is string = :Format)

ResIdx is int = :Resources[Upper(Method) + "|" + Resource]

IF ResIdx < 1 THEN
ExceptionThrow(1,"Resource not available: " + Resource)
END

sProtocol is string = :IsSecure() ? "https" ELSE "http"

sURL is string = XMLRead(:APIXMLName,"/resources/resource[" + ResIdx + "]/url", "")
sFormats is string = XMLRead(:APIXMLName,"/resources/resource[" + ResIdx + "]/@formats", "")

IF StringCount(sFormats, sFormat) < 1 THEN
ExceptionThrow(1,"Format " + sFormat + " not supported by the resource: " + Resource)
END

nParamCount is int
XMLExecuteXPath(:APIXMLName,"count(/resources/resource[" + ResIdx + "]/param)")
nParamCount = XMLResult(:APIXMLName)

sBinaryParam is string
arrAvailParams is array of strings
arrReqParams is array of strings
sParamName is string
bRequired is boolean
bBinary is boolean
FOR i = 1 _TO_ nParamCount
sParamName = XMLRead(:APIXMLName,"/resources/resource[" + ResIdx + "]/param[" + i + "]/@name", "")
bRequired = XMLRead(:APIXMLName,"/resources/resource[" + ResIdx + "]/param[" + i + "]/@required", "false") _IN_ ("true", "t", "1")
bBinary = XMLRead(:APIXMLName,"/resources/resource[" + ResIdx + "]/param[" + i + "]/@binary", "false") _IN_ ("true", "t", "1")

IF bBinary THEN
sBinaryParam = sParamName
ArrayAdd(arrReqParams, sParamName)
ELSE IF bRequired THEN
ArrayAdd(arrReqParams, sParamName)
END

ArrayAdd(arrAvailParams, sParamName)
END

sNewURL is string = sURL
sNewURL = Replace(sNewURL, "{http}", sProtocol)
sNewURL = Replace(sNewURL, "{format}", sFormat)
sNewURL = Replace(sNewURL, "{version}", :APIVersion)

pclBodyParams is OAuthParams dynamic = new OAuthParams()

sParamValue is string
FOR EACH ELEMENT sParamValue, sParamName OF aaParams
nIdxParam is int = ArraySeek(arrAvailParams, asLinear, sParamName)
IF nIdxParam < 1 THEN
ExceptionThrow(1,"Parameter '" + sParamName + "' not available for the resource: " + Resource)
ELSE
ArrayDelete(arrAvailParams, nIdxParam)
END

nReqIdx is int = ArraySeek(arrReqParams, asLinear, sParamName)
IF nReqIdx >= 1 THEN
ArrayDelete(arrReqParams, nReqIdx)
END

IF StringCount(sNewURL, "{" + sParamName + "}") > 0 THEN
sNewURL = Replace(sNewURL, "{" + sParamName + "}", URLCoder(sParamValue))
ELSE IF sBinaryParam = sParamName THEN
pclBodyParams:AddFile(sParamName, sParamValue)
ELSE
pclBodyParams:AddEnc(sParamName, sParamValue)
END
END

IF arrReqParams..Occurrence > 0 THEN
sMissing is string = ArrayToString(arrReqParams, ", ")
ExceptionThrow(1,"Missing required parameters: " + sMissing + " for resource: " + Resource)
END

ArrayDeleteAll(arrReqParams)
ArrayDeleteAll(arrAvailParams)

:Auth:ReqProvider(Method, sNewURL, pclBodyParams)

RESULT :Auth:GetLastResponseText()


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] GetUserID ()
//
// Parameters:
// None
// Return Value:
// string: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure GetUserID()

RESULT :Auth:GetUserID()


// Summary: <specify the procedure action>
// Syntax:
// [ <Result> = ] GetScreenName ()
//
// Parameters:
// None
// Return Value:
// string: <specify the possible values as well as their interpretation>
//
// For instance:
// Indicate an example.
//
Procedure GetScreenName()

RESULT :Auth:GetScreenName()

//--------------------------------------------------------------------------------------------------------//

Código fonte do projeto:

http://repository.windev.com/resource.awp…;

Amostra Twitter Aplicação
Publicado por Hilario PEREZ CORONA

Bons estudos

OK

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 9949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/