As the title suggests, my goal here is to be able to send a tweet from a script.gs. The tweet would be posted to my feed, ideally without me having to visit the Twitter website.
I wrote two main functions to attempt this:
script.gs
//post tweet
function oAuth() {
var CONSUMER_KEY = "**********************";
var CONSUMER_SECRET = "*************************************************";
ScriptProperties.setProperty("TWITTER_CONSUMER_KEY", CONSUMER_KEY);
ScriptProperties.setProperty("TWITTER_CONSUMER_SECRET", CONSUMER_SECRET);
var oauthConfig = UrlFetchApp.addOAuthService("twitter");
oauthConfig.setAccessTokenUrl("https://api.twitter.com/oauth/access_token");
oauthConfig.setRequestTokenUrl("https://api.twitter.com/oauth/request_token");
oauthConfig.setAuthorizationUrl("https://api.twitter.com/oauth/authorize");
oauthConfig.setConsumerKey(ScriptProperties.getProperty("TWITTER_CONSUMER_KEY"));
oauthConfig.setConsumerSecret(ScriptProperties.getProperty("TWITTER_CONSUMER_SECRET"));
var options = {muteHttpExceptions: true,oAuthServiceName:'twitter',oAuthUseToken:'always'}
var url = "https://api.twitter.com/1.1/statuses/user_timeline.json";
var response = UrlFetchApp.fetch(url, options).getContentText();
Logger.log(response);
}
function postTweet() {
oAuth();
Logger.log('oAuth complete');
var status = "Tweet";
var Roptions = {
method: "post",
oAuthServiceName: "twitter",
oAuthUseToken: "always",
status: status
};
var url = "https://api.twitter.com/1.1/statuses/update.json";
Logger.log('begin post');
var request = UrlFetchApp.fetch(url, Roptions); //the trouble line. Execution stops.
Logger.log('post complete');
}
After about a day of relentless hacking, I was able to get the first function, oAuth() to work. That logs, well, my user data. However, for the life of me, I cannot figure out what is holding up request. I do get this error: Request failed for returned code 403. Truncated server response: {"errors":[{"message":"SSL is required","code":92}]}. Googling this didn't turn up much. I'm guessing that the issue is somewhere in Roptions. Any help would be appreciated, and I can try to provide further clarification if needed.
Eureka! Here's the solution. The irony is that I had had something like this before, but had dismissed it. Turns out https was my biggest problem. I'll feast on humble pie tonight.
script to send tweet
//post tweet
function oAuth() {
var CONSUMER_KEY = "*************************";
var CONSUMER_SECRET = "**************************************************";
ScriptProperties.setProperty("TWITTER_CONSUMER_KEY", CONSUMER_KEY);
ScriptProperties.setProperty("TWITTER_CONSUMER_SECRET", CONSUMER_SECRET);
var oauthConfig = UrlFetchApp.addOAuthService("twitter");
oauthConfig.setAccessTokenUrl("https://api.twitter.com/oauth/access_token");
oauthConfig.setRequestTokenUrl("https://api.twitter.com/oauth/request_token");
oauthConfig.setAuthorizationUrl("https://api.twitter.com/oauth/authenticate");
oauthConfig.setConsumerKey(ScriptProperties.getProperty("TWITTER_CONSUMER_KEY"));
oauthConfig.setConsumerSecret(ScriptProperties.getProperty("TWITTER_CONSUMER_SECRET"));
var options = {muteHttpExceptions: true,oAuthServiceName:'twitter',oAuthUseToken:'always'}
var url = "https://api.twitter.com/1.1/statuses/user_timeline.json";
var response = UrlFetchApp.fetch(url, options).getContentText();
Logger.log(response);
}
function postTweet() {
oAuth();
Logger.log('oAuth complete');
var status='Test tweet';
var options = {
"method": "post",
"oAuthServiceName": "twitter",
"oAuthUseToken": "always",
"payload":{"status":status}
};
var url = "https://api.twitter.com/1.1/statuses/update.json";
Logger.log('begin post');
var request = UrlFetchApp.fetch(url, options);
Logger.log('post complete');
}
When you register your Twitter app, you have to check the option Allow this application to be used to Sign in with Twitter. This prevents continual Authorize popups. Also, the tweet text CANNOT contain single quotes (').
#J148, oauthConfig depricated and you can't use it anymore;
Now for twitter you have to use OAuth1 for Apps Script. Migration docs:
https://developers.google.com/apps-script/migration/oauth-config?utm_campaign=oauth-appsscript-315&utm_source=gadbc&utm_medium=blog
Sample:
https://github.com/googlesamples/apps-script-oauth1/blob/master/samples/Twitter.gs
To make sample working you have to:
Add "OAuth1 for Apps Script library" to your script project
Declare some stub "Callback URL" in the twitter app's settings
Related
My objective is to use the upload attachment functionality of the Gmail API. The uploaded file is to be processed within my Gmail add-on. I found the following POST request in this link.
POST https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send?uploadType=media
Here is my try so far:
function testPOST() {
Logger.log('Testing of POST in Apps script');
// var url = ScriptApp.getService().getUrl();
var url = "https://www.googleapis.com/upload/gmail/v1/users/userId/messages/send"
Logger.log('URL:'+url);
var options =
{
"method" : "POST",
"uploadType" : "media"
};
// Trying to fetch the file
var result = UrlFetchApp.fetch(url, options);
Logger.log('Response code: ' + result.getResponseCode());
// maybe I need to use some function in 'Gmail.Users.*'
}
I am trying to figure out if twitterizer is still relevant. The library looks really old. And the current project i am working on uses it. I am using the following code...
private static OAuthTokens OAuthTokens()
{
var accessToken = "<insert>";
var accessTokenSecret = "<insert>";
var consumerKey = "<insert>";
var consumerSecret = "<insert>";
return new OAuthTokens
{
ConsumerKey = consumerKey,
ConsumerSecret = consumerSecret,
AccessToken = accessToken,
AccessTokenSecret = accessTokenSecret
};
}
if i do the following call
var responseFollowersIds = TwitterFriendship.FollowersIds(credentials, new UsersIdsOptions()
{
UseSSL = true,
APIBaseAddress = "http://api.twitter.com/1.1/",
ScreenName = screenName
});
I can see that i have followers and that the request being made looks like this
https://api.twitter.com/1.1/followers/ids.json?screen_name=screenname&cursor=-1
notice that i set the APIBaseAddress to the latest version, but if i try and get the followers i use the following
var responseFollowers = TwitterFriendship.Followers(credentials, new FollowersOptions
{
ScreenName = screenName,
UseSSL = true,
APIBaseAddress = "http://api.twitter.com/1.1/",
});
But then i get an error
{"errors":[{"message":"Sorry, that page does not exist","code":34}]}
upon further investigation i realized that TwitterFriendship.Followers request url is wrong and that is buried deep in the twitterizer code.
The request made is
https://api.twitter.com/1.1/statuses/followers.json?cursor=-1&screen_name=screenname
and should be
https://api.twitter.com/1.1/followers/list.json
according to the new twitter documentation.
Is there an easy way to fix it?
A little bit late, but just in case anyone faces this problem again. You can easily fix it by modifiying the code of Twitterizer at \Methods\User\FollowersCommand.cs, look for the constructor and change the URL of the method:
public FollowersCommand(OAuthTokens tokens, FollowersOptions options)
: base(HTTPVerb.GET, "followers/list.json", tokens, options)
I pulled this code from this question.
Applying the author's solution, I am always given this error:
I get my key and secret from my created twitter app here:
I have the app configured to write...
What am I doing wrong?
//post tweet
function oAuth() {
var CONSUMER_KEY = "xxxx";
var CONSUMER_SECRET = "xxxxx";
ScriptProperties.setProperty("TWITTER_CONSUMER_KEY", CONSUMER_KEY);
ScriptProperties.setProperty("TWITTER_CONSUMER_SECRET", CONSUMER_SECRET);
var oauthConfig = UrlFetchApp.addOAuthService("twitter");
oauthConfig.setAccessTokenUrl("https://api.twitter.com/oauth/access_token");
oauthConfig.setRequestTokenUrl("https://api.twitter.com/oauth/request_token");
oauthConfig.setAuthorizationUrl("https://api.twitter.com/oauth/authenticate");
oauthConfig.setConsumerKey(ScriptProperties.getProperty("TWITTER_CONSUMER_KEY"));
oauthConfig.setConsumerSecret(ScriptProperties.getProperty("TWITTER_CONSUMER_SECRET"));
var options = {muteHttpExceptions: true,oAuthServiceName:'twitter',oAuthUseToken:'always'}
var url = "https://api.twitter.com/1.1/statuses/user_timeline.json";
var response = UrlFetchApp.fetch(url, options).getContentText();
Logger.log(response);
}
function postTweet() {
oAuth();
Logger.log('oAuth complete');
var status='Operational!';
var options = {
"method": "post",
"oAuthServiceName": "twitter",
"oAuthUseToken": "always",
"payload":{"status":status}
};
var url = "https://api.twitter.com/1.1/statuses/update.json";
Logger.log('begin post');
var request = UrlFetchApp.fetch(url, options);
Logger.log('post complete');
}
I was getting this error also, until I realized you need to specify a 'CallBack URL' in Twitter:
Specifying that as either 'https://script.google.com' or 'https://script.google.com/macros' is allowing me to Authorize. I've tested this and it's currently letting me post with the code that you've listed.
One note however if you try and post the same 'status' text twice, it will throw you the following error:
This isn't an issue as you simply change the value of the variable 'Status', but it threw me the first time.
I'm trying to pull the revision history from a document that I own. When I debug it, I receive a 401 Error requiring login. However, I'm trying to use the anonymous ConsumerKey/ConsumerSecret to pass the login and when I debug it, urlFetch comes back as undefined. Here's the code I have so far:
//Get revison history
//fileId is the ID of the resource from Google Docs
function getRevisionHistory(fileId){
//Scope
var scope = 'https://www.googleapis.com/auth/drive';
//Get Google oAuth Arguments
var fetchArgs = googleOAuth_('docs', scope);
//Set the fetch method
fetchArgs.method = 'LIST';
//Feed URL
var url = 'https://www.googleapis.com/drive/v2/files/' + fileId + '/revisionsv=3&alt=json';
var urlFetch = UrlFetchApp.fetch(url);
//Get the json of revision history entry
var jsonFeed = Utilities.jsonParse(urlFetch.getContentText()).feed.entry;
//return the revison history feed
return jsonFeed
}
//Google oAuth
//Used by getRevisionHistory
function googleOAuth_(name, scope) {
var oAuthConfig = UrlFetchApp.addOAuthService(name);
oAuthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
oAuthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope="+scope);
oAuthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
oAuthConfig.setConsumerKey("anonymous");
oAuthConfig.setConsumerSecret("anonymous");
return {oAuthServiceName:name, oAuthUseToken:"always"};
}
function trackChanges(jsonFeed){
var doc = DocumentApp.getActiveDocument();
var docName = doc.getName();
var docId = doc.getId();
getRevisionHistory(docId)
var jsonString = Utilities.jsonStringify(jsonFeed);
var changes = DocumentApp.create("Track Changes for " + docName);
var text = changes.getBody().editAsText();
text.appendText(jsonString);
}
Any help would be greatly appreciated.
Try adding an API Key (&key=mykey) to the UrlFetch call to the Drive API. You can enable Drive API and get an API key at http://developer.google.com/console.
Read more for help here - https://developers.google.com/console/help/#generatingdevkeys
Hello guys I need help in auto login to youtube.com to upload videos "browser-based" (and later get them data to show in a site by api). So basicly I downloaded extension from here http://framework.zend.com/downloads/latest Zend Gdata. And make it work.
It works fine (demos/.../YouTubeVideoApp). But how can i do auto login to youtube without confirmation page ("grant access" \ "deny access")? Currently I use developer key to work with youtube api.
The message of confirmation is
An anonymous application is requesting access to your Google Account for the product(s) listed below.
YouTube
If you grant access, you can revoke access at any time under 'My Account'. The anonymous application will not have access to your password or any other personal information from your Google Account. Learn more
This website has not registered with Google to establish a secure connection for authorization requests. We recommend that you continue the process only if you trust the following destination:
http://somedomain/operations.php
In general I need create connection to youtube (by api) and upload there (using my own account) video without any popups and confirmation pages.
i think all you need is to get a access token and set it to a session value "$_SESSION['sessionToken']". Combination of javascript and PHP will need to do this. previously i always have to grant access or deny it while using Picasa web API but after changes that i described below, grant or access page is no longer needed.
I have not integrated youtube with zend Gdata but have integrated Picasa web Albums using it
make a login using javascript popup and get a token for a needed scope. below is a javascript code. change your scope to youtube data as in this scope for picasa is used.. click function "picasa" on your button onclick.
var OAUTHURL = 'https://accounts.google.com/o/oauth2/auth?';
var VALIDURL = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=';
var SCOPE = 'https://picasaweb.google.com/data';
var CLIENTID = YOUR_CLIENT_ID;
var REDIRECT = 'http://localhost/YOUR_REDIRECT_URL'
var LOGOUT = 'http://accounts.google.com/Logout';
var TYPE = 'token';
var _url = OAUTHURL + 'scope=' + SCOPE + '&client_id=' + CLIENTID + '&redirect_uri=' + REDIRECT + '&response_type=' + TYPE;
var acToken;
var tokenType;
var expiresIn;
var user;
var loggedIn = false;
function picasa() {
var win = window.open(_url, "windowname1", 'width=800, height=600');
var pollTimer = window.setInterval(function() {
console.log(win);
console.log(win.document);
console.log(win.document.URL);
if (win.document.URL.indexOf(REDIRECT) != -1) {
window.clearInterval(pollTimer);
var url = win.document.URL;
acToken = gup(url, 'access_token');
tokenType = gup(url, 'token_type');
expiresIn = gup(url, 'expires_in');
win.close();
validateToken(acToken);
}
}, 500);
}
function validateToken(token) {
$.ajax({
url: VALIDURL + token,
data: null,
success: function(responseText){
//alert(responseText.toSource());
getPicasaAlbums(token);
loggedIn = true;
},
dataType: "jsonp"
});
}
function getPicasaAlbums(token) {
$.ajax({
url: site_url+"ajaxs/getAlbums/picasa/"+token,
data: null,
success: function(response) {
alert("success");
}
});
}
//credits: http://www.netlobo.com/url_query_string_javascript.html
function gup(url, name) {
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\#&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( url );
if( results == null )
return "";
else
return results[1];
}
Here i am making a ajax call in function "getPicasaAlbums" and setting token to a $_session there and after it i am able to get a album listing using zend queries. here is a some code of php file that i am calling using ajax in function "getPicasaAlbums".
function getAlbums($imported_from = '',$token = '') {
//echo $imported_from; //picasa
//echo $token;
$_SESSION['sessionToken'] = $token;// set sessionToken
$client = getAuthSubHttpClient();
$user = "default";
$photos = new Zend_Gdata_Photos($client);
$query = new Zend_Gdata_Photos_UserQuery();
$query->setUser($user);
$userFeed = $photos->getUserFeed(null, $query);
echo "<pre>";print_r($userFeed);echo "</pre>";exit;
}
i think this will help you a little in your task. relpace above "getAlbums" function's code with your youtube zend data code to retrieve data.
good example & referene of a login popup is here
http://www.gethugames.in/blog/2012/04/authentication-and-authorization-for-google-apis-in-javascript-popup-window-tutorial.html