Fetching GAds account with zero impression in the last fresh hour, return false negative results - google-ads-api

I've tried to write an ads-script that returns all the child accounts which had zero impression in the latest available hour (3 hours ago)
However the script returns false negative results.
Meaning there was an account with zero impressions, but the script flagged it as non-zero.
What am I missing?
function main() {
Logger.log("now.getHours(); = "+new Date().getHours());
var past = new Date(new Date().getTime() - HOURS_BACK * 3600 * 1000);
var pastHour = past.getHours();
var pastDateStr = getDateStringInTimeZone(past, 'yyyy-MM-dd');
query = "SELECT customer.id, metrics.impressions, segments.hour FROM customer WHERE metrics.impressions = 0 AND segments.hour = " + pastHour + " AND segments.date = '" + pastDateStr + "'";
Logger.log("query " + query);
updateAccountsInParallel();
}
function updateAccountsInParallel() {
// You can use this approach when you have a large amount of processing
// to do in each of your client accounts.
// Select the accounts to be processed. You can process up to 50 accounts.
var accountSelector = AdsManagerApp.accounts();
// Process the account in parallel. The callback method is optional.
accountSelector.executeInParallel('processAccount', 'allFinished', query);
}
/**
* Process one account at a time. This method is called by the executeInParallel
* method call in updateAccountsInParallel function for every account that
* it processes.
*/
function processAccount(query) {
// executeInParallel will automatically switch context to the account being
// processed, so all calls to AdsApp will apply to the selected account.
var customerId = AdsApp.currentAccount();
if (excludedAccountIds.includes(customerId)) return null;
var currentZeroImpressionRows = AdsApp.report(query, { apiVersion: 'v10' });
var rows = currentZeroImpressionRows.rows();
var accounts = [];
while (rows.hasNext()) {
var row = rows.next();
Logger.log(JSON.stringify(row));
accounts = accounts.push(row["customer.id"] + " " + row["customer.descriptive_name"]);
}
// Optional: return a string value. If you have a more complex JavaScript
// object to return from this method, use JSON.stringify(value). This value
// will be passed on to the callback method, if specified, in the
// executeInParallel method call.
return accounts.length > 0 ? account.getCustomerId() + " " + account.getName() : null;
}
/**
* Post-process the results from processAccount. This method will be called
* once all the accounts have been processed by the executeInParallel method
* call.
*
* #param {Array.<ExecutionResult>} results An array of ExecutionResult objects,
* one for each account that was processed by the executeInParallel method.
*/
function allFinished(results) {
var todayZeroCostAccounts = [];
for (var i = 0; i < results.length; i++) {
// Get the ExecutionResult for an account.
var result = results[i];
//Logger.log('Customer ID: %s; status = %s.', result.getCustomerId(),
// result.getStatus());
// Check the execution status. This can be one of ERROR, OK, or TIMEOUT.
if (result.getStatus() == 'ERROR') {
Logger.log("-- Failed with error: '%s'.", result.getError());
} else if (result.getStatus() == 'OK') {
// This is the value you returned from processAccount method. If you
// used JSON.stringify(value) in processAccount, you can use
// JSON.parse(text) to reconstruct the JavaScript object.
var retval = result.getReturnValue();
if (retval != null) {
Logger.log('%s had 0 impressions in that hour.', result.getCustomerId());
todayZeroCostAccounts.push(retval);
}
else
{
Logger.log('%s had positive impressions in that hour.', result.getCustomerId());
}
} else {
// Handle timeouts here.
}
}
}

Related

hyperledger composer #returns not working

In Hyperledger Composer, v 19.12, I am trying to use the #returns decorator to return an asset. When I call the function through the REST API though I get a succesful transaction (200 return code) but do not get the Account object in the Response Body. Here is the transaction as defined in the data model file, the associated transaction function, and the Response Body from the REST API call. The Account object is defined in the same model file.
I expect to get an Account JSON object back. What am I doing wrong?
Transaction model
/*
Read only transaction to load account
*/
#commit(false)
#returns(Account)
transaction LoadAccountTx {
o String accountId
}
Transaction function
/**
* function to load account
* #param {org.scsvault.history.LoadAccountTx} loadAccountTx
* #returns {org.scsvault.history.Account} The resulting array of accounts
* #transaction
*/
async function loadAccount(loadAccount)
{
var i = 2;
var factory = getFactory();
var NS = 'org.scsvault.history';
var account = factory.newResource(NS, 'Account', 'ACCOUNT_1');
account.accountType = 'CREDITCARD';
account.balance = 100;
account.openingbalance = 1000;
account.opendate = new Date(2017, i, i);
if (i % 2) {
account.approvalStatus = 'REQUEST_PENDING';
}
else {
account.approvalStatus = 'CREATE';
}
account.status = 'PENDING_APPROVAL';
account.creditlimit = i * 1000;
account.term_months = i;
account.encryptedDescription = account.accountType + ' from Chase';
account.apr = i;
return account;
}
Response Body:
{
"$class": "org.scsvault.history.LoadAccountTx",
"accountId": "ACCOUNT_1",
"transactionId": "09c9eb722fe3adda41fe0a4d1060ab4efff4c2ca9ad817a763dae81374123b4c"
}
EDIT:
To test further, I changed the code above to be a simple string return value and do not receive the test string back throught the REST API.
#returns(String)
transaction LoadAccountTx {
o String accountId
}
/**
* function to load account
* #param {org.scsvault.history.LoadAccountTx} loadAccountTx
* #returns {string} (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string)
* #transaction
*/
async function loadAccount(loadAccount)
{
return "This is a test string";
}
just adding to what #nicolapaoli wrote: this is fixed in Hyperledger Composer release v0.19.13 FYI - you do get the return value.
I had very similar issue. I've just opened an issue with general example on GitHub here with ref to this question and to the message on Rocketchat as well. Hope this will be fixed soon.

Incrementing Value of incoming value in Azure Table Insert

I am an iOS developer & currently working with Azure mobile services SDK in iOS.
In my case, I am providing each user as a uniqueid say 'myid' in Table say 'todomytable'. In todomytable.js file I am performing check for myid value. If coming value of 'myid' from device is less than stored value in table then I am increasing incoming value greater than earlier stored value in table by One. Below is my logic in todomytable.js
table.insert(function (context) {
context.item.userId = context.user.id;
//....
var intIncomingID = context.item.myid; //ID coming from mobile device
//Call back to get max value of 'myid' from Table
var myFunction = function( callback) {
var query = {
sql: 'select MAX(myid) from TodoItem'
};
context.data.execute(query).then(function (results) {
var objectTest = eval(JSON.stringify(results));
var tempObject = objectTest[0];
var previuosIntID = tempObject["MAX(myid)"];
callback(previuosIntID);
});
};
myFunction(function(returnValue) {
console.log("returnValue is : "+returnValue);
if (intIncomingID<=returnValue)
{
console.log('IF');
context.item.userId = context.user.id;
returnValue = returnValue+1;
context.item.myid = returnValue;
console.log("UPDATED value is : "+context.item.myid);
}
else{
context.item.myid = intIncomingID;
console.log("ITEM value is :"+intIncomingID);
}
return context.execute();
});
});
But issue is that table is not getting update & in mobile log I am getting network request time out error as below
{Error Domain=NSURLErrorDomain Code=-1001 "The request timed out."}
Can anyone suggest how to resolve this issue? I have to store 'myid' in incremented order in table. I am new to Node.js, so sorry If I am making any foolish mistake.
It is likely that there is an exception occurring at some point that causes a promise to reject. Given that there is no promise exception handler defined, the exception ends up being "swallowed". Try the following:
var table = module.exports = require('azure-mobile-apps').table()
table.insert(function (context) {
context.item.userId = context.user.id;
var intIncomingID = context.item.myid; //ID coming from mobile device
var query = { sql: 'select MAX(myid) from TodoItem' };
return context.data.execute(query)
.then(function (results) {
var tempObject = results[0];
var previousIntID = tempObject["MAX(myid)"];
console.log("previous ID is : " + previousIntID);
if (intIncomingID <= previousIntID) {
context.item.myid = previousIntID + 1;
console.log("UPDATED value is : " + context.item.myid);
} else {
context.item.myid = intIncomingID;
console.log("ITEM value is :" + intIncomingID);
}
return context.execute();
});
});
Some points to note:
context.data.execute returns a promise - we are returning this from the insert function so that the Mobile Apps runtime handles any rejected promises
context.execute also returns a promise; we are returning this so that the promises are "chained" properly
Hope this helps!

Google docs spreadsheet script error OAuthConfig when fetching data from Fitbit

I have got following script in Google docs spreadsheet which is fetching data from Fitbit. Script worked fine so far but recently on 6th July Google stopped using OAuthConfig so script is not working since:-(
I am not programmer, I am just advanced user. So I would like to kindly ask some programmer to help tune script below in order to make it work again.
// Key of ScriptProperty for Firtbit consumer key.
var CONSUMER_KEY_PROPERTY_NAME = "fitbitConsumerKey";
// Key of ScriptProperty for Fitbit consumer secret.
var CONSUMER_SECRET_PROPERTY_NAME = "fitbitConsumerSecret";
// Default loggable resources (from Fitbit API docs).
var LOGGABLES = ["activities/log/steps", "activities/log/distance",
"activities/log/activeScore", "activities/log/activityCalories",
"activities/log/calories", "foods/log/caloriesIn",
"activities/log/minutesSedentary",
"activities/log/minutesLightlyActive",
"activities/log/minutesFairlyActive",
"activities/log/minutesVeryActive", "sleep/timeInBed",
"sleep/minutesAsleep", "sleep/minutesAwake", "sleep/awakeningsCount",
"body/weight", "body/bmi", "body/fat",];
// function authorize() makes a call to the Fitbit API to fetch the user profile
function authorize() {
var oAuthConfig = UrlFetchApp.addOAuthService("fitbit");
oAuthConfig.setAccessTokenUrl("https://api.fitbit.com/oauth/access_token");
oAuthConfig.setRequestTokenUrl("https://api.fitbit.com/oauth/request_token");
oAuthConfig.setAuthorizationUrl("https://api.fitbit.com/oauth/authorize");
oAuthConfig.setConsumerKey(getConsumerKey());
oAuthConfig.setConsumerSecret(getConsumerSecret());
var options = {
"oAuthServiceName": "fitbit",
"oAuthUseToken": "always",
};
// get the profile to force authentication
Logger.log("Function authorize() is attempting a fetch...");
try {
var result = UrlFetchApp.fetch("https://api.fitbit.com/1/user/-/profile.json", options);
var o = Utilities.jsonParse(result.getContentText());
return o.user;
}
catch (exception) {
Logger.log(exception);
Browser.msgBox("Error attempting authorization");
return null;
}
}
// function setup accepts and stores the Consumer Key, Consumer Secret, firstDate, and list of Data Elements
function setup() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication().setTitle("Setup Fitbit Download");
app.setStyleAttribute("padding", "10px");
var consumerKeyLabel = app.createLabel("Fitbit OAuth Consumer Key:*");
var consumerKey = app.createTextBox();
consumerKey.setName("consumerKey");
consumerKey.setWidth("100%");
consumerKey.setText(getConsumerKey());
var consumerSecretLabel = app.createLabel("Fitbit OAuth Consumer Secret:*");
var consumerSecret = app.createTextBox();
consumerSecret.setName("consumerSecret");
consumerSecret.setWidth("100%");
consumerSecret.setText(getConsumerSecret());
var firstDate = app.createTextBox().setId("firstDate").setName("firstDate");
firstDate.setName("firstDate");
firstDate.setWidth("100%");
firstDate.setText(getFirstDate());
// add listbox to select data elements
var loggables = app.createListBox(true).setId("loggables").setName(
"loggables");
loggables.setVisibleItemCount(4);
// add all possible elements (in array LOGGABLES)
var logIndex = 0;
for (var resource in LOGGABLES) {
loggables.addItem(LOGGABLES[resource]);
// check if this resource is in the getLoggables list
if (getLoggables().indexOf(LOGGABLES[resource]) > -1) {
// if so, pre-select it
loggables.setItemSelected(logIndex, true);
}
logIndex++;
}
// create the save handler and button
var saveHandler = app.createServerClickHandler("saveSetup");
var saveButton = app.createButton("Save Setup", saveHandler);
// put the controls in a grid
var listPanel = app.createGrid(6, 3);
listPanel.setWidget(1, 0, consumerKeyLabel);
listPanel.setWidget(1, 1, consumerKey);
listPanel.setWidget(2, 0, consumerSecretLabel);
listPanel.setWidget(2, 1, consumerSecret);
listPanel.setWidget(3, 0, app.createLabel(" * (obtain these at dev.fitbit.com)"));
listPanel.setWidget(4, 0, app.createLabel("Start Date for download (yyyy-mm-dd)"));
listPanel.setWidget(4, 1, firstDate);
listPanel.setWidget(5, 0, app.createLabel("Data Elements to download:"));
listPanel.setWidget(5, 1, loggables);
// Ensure that all controls in the grid are handled
saveHandler.addCallbackElement(listPanel);
// Build a FlowPanel, adding the grid and the save button
var dialogPanel = app.createFlowPanel();
dialogPanel.add(listPanel);
dialogPanel.add(saveButton);
app.add(dialogPanel);
doc.show(app);
}
// function sync() is called to download all desired data from Fitbit API to the spreadsheet
function sync() {
// if the user has never performed setup, do it now
if (!isConfigured()) {
setup();
return;
}
var user = authorize();
// Spatny kod, oprava nize - var doc = SpreadsheetApp.getActiveSpreadsheet();
var doc = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Pavel');
doc.setFrozenRows(1);
var options = {
"oAuthServiceName": "fitbit",
"oAuthUseToken": "always",
"method": "GET"
};
// prepare and format today's date, and a list of desired data elements
var dateString = formatToday();
var activities = getLoggables();
// for each data element, fetch a list beginning from the firstDate, ending with today
for (var activity in activities) {
var currentActivity = activities[activity];
try {
var result = UrlFetchApp.fetch("https://api.fitbit.com/1/user/-/"
+ currentActivity + "/date/" + getFirstDate() + "/"
+ dateString + ".json", options);
} catch (exception) {
Logger.log(exception);
Browser.msgBox("Error downloading " + currentActivity);
}
var o = Utilities.jsonParse(result.getContentText());
// set title
var titleCell = doc.getRange("a1");
titleCell.setValue("date");
var cell = doc.getRange('a2');
// fill the spreadsheet with the data
var index = 0;
for (var i in o) {
// set title for this column
var title = i.substring(i.lastIndexOf('-') + 1);
titleCell.offset(0, 1 + activity * 1.0).setValue(title);
var row = o[i];
for (var j in row) {
var val = row[j];
cell.offset(index, 0).setValue(val["dateTime"]);
// set the date index
cell.offset(index, 1 + activity * 1.0).setValue(val["value"]);
// set the value index index
index++;
}
}
}
}
function isConfigured() {
return getConsumerKey() != "" && getConsumerSecret() != "";
}
function setConsumerKey(key) {
ScriptProperties.setProperty(CONSUMER_KEY_PROPERTY_NAME, key);
}
function getConsumerKey() {
var key = ScriptProperties.getProperty(CONSUMER_KEY_PROPERTY_NAME);
if (key == null) {
key = "";
}
return key;
}
function setLoggables(loggable) {
ScriptProperties.setProperty("loggables", loggable);
}
function getLoggables() {
var loggable = ScriptProperties.getProperty("loggables");
if (loggable == null) {
loggable = LOGGABLES;
} else {
loggable = loggable.split(',');
}
return loggable;
}
function setFirstDate(firstDate) {
ScriptProperties.setProperty("firstDate", firstDate);
}
function getFirstDate() {
var firstDate = ScriptProperties.getProperty("firstDate");
if (firstDate == null) {
firstDate = "2012-01-01";
}
return firstDate;
}
function formatToday() {
var todayDate = new Date;
return todayDate.getFullYear()
+ '-'
+ ("00" + (todayDate.getMonth() + 1)).slice(-2)
+ '-'
+ ("00" + todayDate.getDate()).slice(-2);
}
function setConsumerSecret(secret) {
ScriptProperties.setProperty(CONSUMER_SECRET_PROPERTY_NAME, secret);
}
function getConsumerSecret() {
var secret = ScriptProperties.getProperty(CONSUMER_SECRET_PROPERTY_NAME);
if (secret == null) {
secret = "";
}
return secret;
}
// function saveSetup saves the setup params from the UI
function saveSetup(e) {
setConsumerKey(e.parameter.consumerKey);
setConsumerSecret(e.parameter.consumerSecret);
setLoggables(e.parameter.loggables);
setFirstDate(e.parameter.firstDate);
var app = UiApp.getActiveApplication();
app.close();
return app;
}
// function onOpen is called when the spreadsheet is opened; adds the Fitbit menu
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [{
name: "Sync",
functionName: "sync"
}, {
name: "Setup",
functionName: "setup"
}, {
name: "Authorize",
functionName: "authorize"
}];
ss.addMenu("Fitbit", menuEntries);
}
// function onInstall is called when the script is installed (obsolete?)
function onInstall() {
onOpen();
}
Problem solved with updated code at https://github.com/loghound/Fitbit-for-Google-App-Script

firefox addon, how to modify(change) the url before the request is sent (even made) by the browser?

I want to remove some parameters in a url, currently my code:
require("sdk/tabs").on("ready", removeList);
function removeList(tab) {
var index = tab.url.indexOf("&list=");
if (tab.url.indexOf("youtube.com") > -1 && index > -1) {
console.log(tab.url);
var temp = tab.url.slice(0, index);
console.log(temp);
tab.url = "";
tab.url = temp;
}
}
But it will send two urls(requests) to the server, the original one (I can see the response without the video being played) and the truncated one(as expected).
Your two options are http-on-modify-request and http-on-opening-request. The first is fine, but the second fires earlier and you lose a lot of a ability. The first method the url is fine because server never sees it.
const { Ci, Cu, Cc, Cr } = require('chrome'); //const {interfaces: Ci, utils: Cu, classes: Cc, results: Cr } = Components;
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/devtools/Console.jsm');
var observers = {
'http-on-examine-response': {
observe: function (aSubject, aTopic, aData) {
console.info('http-on-modify-request: aSubject = ' + aSubject + ' | aTopic = ' + aTopic + ' | aData = ' + aData);
var httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
var requestUrl = httpChannel.URI.spec
var index = requestUrl.indexOf('&list=');
if (requestUrl.indexOf('youtube.com') > -1 && index > -1) {
console.log(requestUrl);
var temp = requestUrl.slice(0, index);
httpChannel.redirectTo(Services.io.newURI(temp, null, null));
}
},
reg: function () {
Services.obs.addObserver(observers['http-on-modify-request'], 'http-on-modify-request', false);
},
unreg: function () {
Services.obs.removeObserver(observers['http-on-modify-request'], 'http-on-modify-request');
}
}
};
or instead of the redirectTo line you can do httpChannel.cancel(Cr.NS_BINDING_ABORTED); than get that loadConext and change the url.
To start observing
To start start obseving all requests do this (for example on startup of your addon)
for (var o in observers) {
observers[o].reg();
}
To stop observing
Its important to stop observring (make sure to run this at least on shutdown of addon, you dont want to leave the observer registered for memory reasons)
for (var o in observers) {
observers[o].unreg();
}

Refresh tweets frequently in my site homepage without reaching to the rate limit

I am working on the site which needs real time tweets to be displayed to users. I have used Tweet Sharp library to fetch tweets.
My site needs tweets to be refreshed frequently, but sometimes I get {"The remote server returned an error: (429) Too Many Requests."} error.
As my site needs real time information, I have to fetch tweets frequently. How can I achieve this? How to get newest tweets without hitting to the Rate Limits?
TwitterService service=new TwitterService(AppSetting.objTwitterClientInfo.ConsumerKey, AppSetting.objTwitterClientInfo.ConsumerSecret, AppSetting.objTwitterModerateInfo.ModerateAccessToken, AppSetting.objTwitterModerateInfo.ModerateAccessTokenSecret);
var options = new ListTweetsOnHomeTimelineOptions();
options.ExcludeReplies = false;
options.Count = intTotalRec;
var lstTwitterStatus = service.ListTweetsOnHomeTimeline(options);
You can use the streaming api like this:-
public void Can_stream_from_user_stream() {
const int maxStreamEvents = 5;
var block = new AutoResetEvent(false);
var count = 0;
service.StreamUser((streamEvent, response) =>
{
if (streamEvent is TwitterUserStreamEnd)
{
block.Set();
}
if (response.StatusCode == 0)
{
if (streamEvent is TwitterUserStreamFriends)
{
var friends = (TwitterUserStreamFriends)streamEvent;
Assert.IsNotNull(friends);
Assert.IsNotNull(friends.RawSource);
Assert.IsTrue(friends.Ids.Any());
}
if (streamEvent is TwitterUserStreamEvent)
{
var #event = (TwitterUserStreamEvent)streamEvent;
Assert.IsNotNull(#event);
Assert.IsNotNull(#event.TargetObject);
Assert.IsNotNull(#event.RawSource);
Console.Write(#event.Event + "\n" + #event.Source + "\n" + #event.Target);
}
if (streamEvent is TwitterUserStreamStatus)
{
var tweet = ((TwitterUserStreamStatus)streamEvent).Status;
Assert.IsNotNull(tweet);
Assert.IsNotNull(tweet.Id);
Assert.IsNotNull(tweet.User);
Assert.IsNotNull(tweet.RawSource);
Assert.IsNotNull(tweet.User.ScreenName);
Console.WriteLine(tweet.User.ScreenName + "\n" + tweet.Text);
}
if (streamEvent is TwitterUserStreamDirectMessage)
{
var dm = ((TwitterUserStreamDirectMessage)streamEvent).DirectMessage;
Assert.IsNotNull(dm);
Assert.IsNotNull(dm.Id);
Assert.IsNotNull(dm.Sender);
Assert.IsNotNull(dm.Recipient);
Assert.IsNotNull(dm.RawSource);
Console.WriteLine(dm.SenderScreenName + "\n" + dm.RecipientScreenName + "\n" + dm.Text);
}
if (streamEvent is TwitterUserStreamDeleteStatus)
{
var deleted = (TwitterUserStreamDeleteStatus)streamEvent;
Assert.IsNotNull(deleted);
Assert.IsTrue(deleted.StatusId > 0);
Assert.IsTrue(deleted.UserId > 0);
}
if (streamEvent is TwitterUserStreamDeleteDirectMessage)
{
var deleted = (TwitterUserStreamDeleteDirectMessage)streamEvent;
Assert.IsNotNull(deleted);
Assert.IsTrue(deleted.DirectMessageId > 0);
Assert.IsTrue(deleted.UserId > 0);
}
count++;
if (count == maxStreamEvents)
{
block.Set();
}
}
else
{
Assert.Ignore("Stream responsed with status code: {0}", response.StatusCode);
}
});
block.WaitOne();
service.CancelStreaming();
}

Resources