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
gclOAuth:SetRequestVerifier(EDT_Verification)
WHEN EXCEPTION IN
IF gclOAuth:ReqAccessToken() = False THEN
Error("Ocurrió un error: " + gclOAuth:GetLastResponseText())
RETURN
END
DO
Error(ExceptionInfo())
RETURN
END
sAccessToken is string = gclOAuth:GetAccessToken()
sAccessTokenSecret is string = gclOAuth:GetAccessTokenSecret()
IF sAccessToken <> "" _AND_ sAccessTokenSecret <> "" THEN
gbTwitterAutorizado = True
END
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
gclOAuth is OAuth ("AAAA", "BBBB")
gclTwitt is Twitter("AAAA", gclOAuth)
gbTwitterAutorizado is boolean = False
InicializarTwitter()
INFORME NESSE CODIGO O SEU USUARIO E SENHA DO TWITTER
Procedure InicializarTwitter()
gclTwitt:LoadAPIFile("twitter.xml")
sAccessToken is string = INIRead("twitter", "Token", "", ".\twitter.ini")
sAccessTokenSecret is string = INIRead("twitter", "Secret", "", ".\twitter.ini")
IF sAccessToken <> "" _AND_ sAccessTokenSecret <> "" THEN
gclOAuth:SetAccessTokens(sAccessToken, sAccessTokenSecret)
gbTwitterAutorizado = True
ELSE
WHEN EXCEPTION IN
IF gclOAuth:ReqRequestToken() = False THEN
Error("Ocurrió un error: " + gclOAuth:GetLastResponseText())
RETURN
END
sURLAutorizacion is string = gclOAuth:GenAccessURL()
Open(WIN_Twitter_Verificacion, sURLAutorizacion)
DO
Error(ExceptionInfo())
RETURN
END
END
ENVIAR MENSAGEM
Procedure PostearMensaje(LOCAL sMensaje is string)
IF gbTwitterAutorizado = False THEN
Error("This application is not authorized, please restart...")
RETURN
END
WHEN EXCEPTION IN
aaParams is associative array of strings
aaParams["status"] = NoSpace(sMensaje)
sJSon is string = gclTwitt:REST("POST", "statuses/update", aaParams)
ValidaRespuesta(sJSon)
DO
ExceptionThrow(1, ExceptionInfo())
END
Procedure ValidaRespuesta(LOCAL sRespuesta is string)
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
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.")
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()
IF gbTwitterAutorizado = False THEN
Error("This application is not authorized by Twitter, please restart...")
RETURN
END
WHEN EXCEPTION IN
aaParams is associative array of strings
aaParams["count"] = 30
sJSon is string = gclTwitt:REST("GET", "statuses/home_timeline", aaParams)
ValidaRespuesta(sJSon)
clJSON is JSON(sJSon)
TableDeleteAll(TABLE_Table1)
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
//--------------------------------------------------------------------------------------------------------//
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
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
Procedure Destructor()
:Release()
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 = ""
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)
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)
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
//--------------------------------------------------------------------------------------------------------//
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
ConsumerKey is string
ConsumerSecret is string
RequestToken is string
RequestTokenSecret is string
CallbackConfirmed is boolean
RequestVerifier is string
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
Procedure Constructor(LOCAL sCunsomerKey is string, LOCAL sCunsomerSecret is string, LOCAL sCallback is string = "")
:ConsumerKey = sCunsomerKey
:ConsumerSecret = sCunsomerSecret
:Callback = sCallback
Procedure Destructor()
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
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
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
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]]
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
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
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
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
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
Procedure SetRequestVerifier(LOCAL sVerifier is string)
IF :State < ::STATE_HAVEREQUEST_TOKEN THEN
ExceptionThrow(1,"You do not have a request token")
END
:RequestVerifier = sVerifier
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
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
Procedure GetState()
RESULT :State
Procedure GetLastResponse()
RESULT :LastResponse
Procedure GetLastResponseText()
IF :LastResponse = Null THEN
ExceptionThrow(1,"There is no last response available")
END
RESULT :LastResponse:Response
Procedure GetUserID()
RESULT :UserID
Procedure GetScreenName()
RESULT :ScreenName
Procedure GetAccessToken()
RESULT :AccessToken
Procedure GetAccessTokenSecret()
RESULT :AccessTokenSecret
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
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
Procedure Constructor()
Procedure Destructor()
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
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)
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
Procedure AddEnc(LOCAL sKey is string, LOCAL sValue is string)
:Add(sKey, URLCoder(sValue))
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
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
Procedure HasParams()
RESULT :Params..Occurrence > 0
Procedure RemoveFrom(pclOtherAuth is OAuthParams dynamic)
FOR i = 1 _TO_ :Params..Occurrence
pclOtherAuth:Remove(:Params[i]:Key)
END
Procedure Remove(LOCAL sKey is string)
nIdx is int = ArraySeek(:Params,asLinear,"Key",sKey)
IF nIdx > 0 THEN
ArrayDelete(:Params,nIdx)
END
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
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)
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
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
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)
Procedure Destructor()
XMLClose(:APIXMLName)
Procedure LoadAPIFile(LOCAL sFileName is string)
sApixml is string = fLoadText(sFileName)
:LoadAPIString(sApixml)
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
Procedure IsSecure()
RESULT :Secure
Procedure SetSecure(LOCAL bSecure is boolean)
:Secure = bSecure
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()
Procedure GetUserID()
RESULT :Auth:GetUserID()
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/