Integrating G Analytics to a Node.js API - javascript

I am currently stuck with this project : integrating GA to my REST API so I can retrieve metrics and dimensions.
I must highlight that I am running the API on localhost, it may explain why it does not work...?
I tried to integrate GA following different ways :
1. Using universal-analytics (https://github.com/peaksandpies/universal-analytics/blob/master/AcceptableParams.md)
const ua = require('universal-analytics');
require('dotenv').config({path: '../.env'});
// to retrieve the number of connexions to the homepage
server.route({
method: 'GET',
path: '/homepage',
handler: function (request, reply) {
...
const visitor = ua(process.env.UA_ID);
visitor.pageview('/bookmarks', 'http://localhost:4000', 'Homepage', (err) => {
if (err) {
throw err;
}
});
return reply.view('index');
}
});
// I have pretty much the same thing at the end of a POST endpoint handler
// to retrieve the number of new data posted
handler: function (request, reply) {
...
const user = ua(process.env.UA_ID, userId(request.auth.credentials.username));
user.event('Bookmarks', 'new_bkm_created', payload.title, (err) => {
if (err) {
throw err;
}
});
}
2. Creating a trackEvent function (https://cloud.google.com/appengine/docs/flexible/nodejs/integrating-with-analytics)
in google.js
const got = require('got');
module.exports = function trackEvent (propertyId, category, action, options) {
const data = {
v: '1', // API version
tid: propertyId, // Tracking / Property ID.
t: 'event', // Event hit type.
ec: category, // Event category.
ea: action // Event action.
};
if (options) {
if (options.label) {
data.el = options.label; // Event label.
}
if (options.value) {
data.ev = options.value; // Event value.
}
}
return got.post('http://www.google-analytics.com/collect', {
body: data,
form: true
});
};
in app.js
require('dotenv').config({path: '../.env'});
const trackEvent = require('./google');
const postHandler = (request, reply) => {
...
trackEvent(process.env.UA_ID, 'Thing', 'new_thing_created').then(() => {
return reply(bookmark).code(201);
}
}
3. Pasting the website tracking code from Admin --> Property ---> Tracking Info (https://developers.google.com/analytics/devguides/collection/analyticsjs/)
<script>
(function(i,s,o,g,r,a,m)i['GoogleAnalyticsObject']=ri[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;.parentNode.insertBefore(a,m)})(window,document,'script','https://www.google-analytics.com, 'analytics.js','ga');
ga('create', 'UA-XXX-whatev', 'auto');
ga('send', 'pageview');
</script>
I also tried the async version proposed on the link on the third title. The thing is, I do not like this way of doingm I do not understand how to launch events and page views from handlers with ga created in the front end...
Anyway, none of them works... I have no error, but nothing appears in G Analytics.
Just so you know, I used example.com in the default URL as it does not work with a localhost url.
Do you have any lead to help me with this?
Thank you so much in advance!
-- smgr

Turned out one of the three methods worked: the first one with universal-analytics. One needs to be patient to see the first tracked events. I warmly recommend this module though, very developer-friendly ;)

Related

cypress cy.route not behaving consistently

I am trying to stub out a route using cypress 5.2. I have a simple function to do that:
function mockAlertsResponses(){
cy.route({
method: "GET",
url: "/api/polling/alerts/statistics*",
response: {
total: 2,
...
}
});
}
In one set of tests, this works just fine:
describe("admin and read only permissions", () => {
it ("all action bar items are enabled with admin permissions", () => {
cy.login("user", "password");
mockAlertsResponses();
// Click alert to enable all buttons
cy.get("#1-checkbox").click()
cy.get("#mark-alert-button").should("be.enabled");
cy.get("#delete-alert-button").should("be.enabled");
});
// ... a few more similar tests
});
However, in another set of tests, I use the same function:
it("Logs in and out", () => {
cy.login("username", "password");
mockAlertsResponses()
cy.get("#vine-appbar").should("be.visible");
cy.get("#info-button").click();
cy.get("#info-menu-logout").click();
cy.get("#login-button");
cy.get("#vine-appbar").should("not.be.visible");
});
In this second set of tests, the routes are not stubbing properly, leading to errors and test failures. Here, you can see the route is not stubbed, but rather throws a 500 error:
I'm not sure what could be interfering here. I'm a bit new to cypress and I'm not even sure where to begin debugging this. Might the cy.server calls be interfering? Please let me know what more information we'd need to figure out why one set of stubs works and another doesn't.
If you're wondering, the login function has a call to cy.server and has its own cy.route as well:
Cypress.Commands.add("login", (username, password, admin = true) => {
const response = admin ? <jwt1> : <jwt2>
cy.server();
cy.route({
method: "POST",
url: "/api/login",
response
});
cy.visit("/logout");
cy.visit("/");
cy.wait(100);
cy.get("#login-error").should("not.be.visible");
cy.get("#login-username").type(username);
cy.get("#login-password").type(password);
cy.get("#login-button").click();
});

Jaspersoft visualise.js report export failing to produce file

I hope there is few among you who have experience with Jaspersoft Reports and their new visualise.js api
I have a problem with visualise.js not producing report export file. What happens is:
I am able to succsefully load the report through the visualise.js API, it loads and displays on my web page
Export controls load up successfully too, so I have dropdown with export file formats and a button to export the file.
When I click the export button though, the whole page reloads as if the export button was really a submit button and nothing happens.
Occasionally, the export will work and it will produce file. Though there is no pattern to when it will produce the file and when it will fail.
Below is the code I am using for this (I am using plain text auth for testing purposes):
visualize({
auth: {
name: "mylogin",
password: "mypass",
organization: "organization_1"
}
}, function (v) {
var $select = buildControl("Export to: ", v.report.exportFormats),
$button = $("#button"),
report = v.report({
resource: "/FPSReports/journal",
container: "#export",
params: {
"journal_ref": [ "<?php echo $reference; ?>" ],
},
success: function () {
button.removeAttribute("disabled");
},
error : function (error) {
console.log(error);
}
});
$button.click(function () {
console.log($select.val());
report.export({
// export options here
outputFormat: $select.val(),
// exports all pages if not specified
// pages: "1-2"
}, function (link) {
var url = link.href ? link.href : link;
window.location.href = url;
}, function (error) {
console.log(error);
});
});
function buildControl(name, options){
function buildOptions(options) {
var template = "<option>{value}</option>";
return options.reduce(function (memo, option) {
return memo + template.replace("{value}", option);
}, "")
}
var template = "<label>{label}</label><select>{options}</select><br />",
content = template.replace("{label}", name)
.replace("{options}", buildOptions(options));
var $control = $(content);
$control.insertBefore($("#button"));
//return select
return $($control[1]);
}
});
HTML:
<div class="grid">
<div class="grid-8"></div>
<div class="grid-8 center">Export</div>
<div class="grid-8"></div>
</div>
<div class="grid">
<div class="grid-24" id="export"></div>
</div>
The only parameter comes from URI segment (I am using codeigniter framework):
$reference = $this->uri->segment(3, 0);
I have found an answer that seems to work, and has resolved the issue. Posting it here in case anyone else has this specific problem like I did.
In brief:
After spending hours looking at console debug output I have realised that each time I tried to send a request for export a new session would be opened. Without logging out of the previous one. And apparently that is a no-no. I do not know JS very well but from what I understood there was session id mismatch in request. Please feel free to correct me here :)
The solution to this problem (or for example if you are having authentication issues with visualize.js) is very simple. Set the authentication in global config:
visualize.config({
auth: {
name: "superuser",
password: "superuser"
}
});
No matter if you are using tokens or plain text or whatever else auth is available through the api.
Then do your stuff wherever else on your website:
visualize(function (v) {
v("#container1").report({
resource: "/public/Samples/Reports/06g.ProfitDetailReport",
error: function (err) {
alert(err.message);
}
});
});
visualize(function (v) {
v("#container2").report({
resource: "/public/Samples/Reports/State_Performance",
error: function (err) {
alert(err.message);
}
});
});
Everything should work for you as it did for me. This works in version 5.6 and 6.1 of visualize.js.
Further reading and links from my research:
Token based authentication to Jasper reports failing when used with visualize.js
Visualize.js authentication error after second login
http://community.jaspersoft.com/questions/842695/visualizejs-authentication-error
http://community.jaspersoft.com/questions/845886/authentication-error-refresh-credentials-visualizejs
Code example (5.6):
http://jsfiddle.net/TIBCO_JS_Community/sozzq0sL/embedded/
Api samples (6.1):
http://community.jaspersoft.com/wiki/visualizejs-api-samples-v61
Api samples (5.6):
http://community.jaspersoft.com/wiki/visualizejs-api-notes-and-samples-v56
Really hope this will help someone new to Jaspersoft & visualize.js like me.

Meteor Iron Router, Pub Sub causing weird behavior

I am trying to make sing post page a route where it does a several things using iron:router
Uses the template postPage
Subscribes to publication of singlePost, userStatus (shows status and info of Author of single post page'), comments .
Grabs Comments documents that has field of postId : this.params._id
Increments Comments List by Session.get('commentLimit')
Here is the code I currently have.
Router.js
Router.route('/posts/:_id', {
name: 'postPage',
subscriptions: function() {
return [
Meteor.subscribe('singlePost', this.params._id),
Meteor.subscribe('userStatus'),
Meteor.subscribe('comments', {
limit: Number(Session.get('commentLimit'))
})
];
},
data: function() {
return Posts.findOne({_id:this.params._id});
},
});
Publications.js
Meteor.publish('singlePost', function(id) {
check(id, String);
return Posts.find(id);
});
Meteor.publish('comments', function(options) {
check(options, {
limit: Number
});
return Comments.find({}, options);
});
Template.postPage.onCreated
Template.onCreated( function () {
Session.set('commentLimit', 4);
});
Template.postPage.helpers
Template.postPage.helpers({
comments: function () {
var commentCursor = Number(Session.get('commentLimit'));
return Comments.find({postId: this._id}, {limit: commentCursor});
},
});
Template.postPage.events
Template.postPage.events({
'click a.load-more-comments': function (event) {
event.preventDefault();
Session.set('commentLimit', Number(Session.get('commentLimit')) + 4)
}
});
Everything works fine, but I found one thing to be inconsistent.
Here is the problem I am having...
User goes into single post page and adds comment (everything works fine).
User goes into a different single post page and adds comment (everything works fine).
Here is where the problem begins
The user at any time, goes into another route that is not the single post page.
User goes back into single post page
The comments are not showing.
New comments will be added into DB but still wont show
This problem only goes away when meteor reset or manual deletion of all comments in MongoDB is performed.
Is there a better way that I can code my routing and related code to stop this weird behavior from happening?
Or even if there is a better practice.
Your publish is publishing comments without any postId filter.
Your helper, filters by postId. Maybe the 4 comments that get published are the ones that do not belong to the current post that is open?
Could you try updating, your subscription to
Meteor.subscribe('comments', {
postId: this.params._id
}, {
limit: Number(Session.get('commentLimit'))
})
and your publication to
Meteor.publish('comments', function(filter, options) {
check(filter, {
postId: String
});
check(options, {
limit: Number
});
return Comments.find(filter, options);
});
so that only the same posts' comments are published?
I have figured it out. I have updated the following codes.
So far it is not showing weird behavior...
Publications.js
Meteor.publish('comments', function(postId, limit) {
check(postId, String);
check(limit, Number);
return Comments.find({postId:postId}, {limit:limit});
});
Router.js
Router.route('/posts/:_id', {
name: 'postPage',
subscriptions: function () {
return [
Meteor.subscribe('singlePost', this.params._id),
Meteor.subscribe('userStatus'),
Meteor.subscribe('comments', this.params._id, Number(Session.get('commentLimit')))
];
},
data: function() {
return Posts.findOne({_id:this.params._id});
},
});

angular push adds operator that that results in MongoError

I am implementing the tutorial on the mean stack https://www.youtube.com/watch?v=AEE7DY2AYvI
I am adding a delete feature to remove items from the database on a button click
My client side controller has the following 2 functions to add to db and remove
$scope.createMeetup = function() {
var meetup = new Meetup();
meetup.name = $scope.meetupName;
meetup.$save(function (result) {
$scope.meetups.push(result);
$scope.meetupName = '';
});
}
$scope.deleteMeetup = function() {
item = $scope.meetups[0];
console.log("deleting meetup: " + item["name"]);
Meetup.delete(item);
scope.meetups.shift();
}
My server side has the following code
module.exports.create = function (req, res) {
var meetup = new Meetup(req.body);
meetup.save(function (err, result) {
res.json(result);
});
}
module.exports.remove = function(req, res) {
console.log("GOING TO REMOVE!!!");
console.log(req.query);
item = req.query;
Meetup.remove(item, function (err, results) {
console.log("done");
console.log(err);
console.log(results);
});
}
When I run my code and if I delete an already loaded item in the list, it is removed from Mongodb just fine. But if I add an item to the list and I do not refresh the page, it results in an error at my server that appears as
GOING TO REMOVE!!!
{ '$resolved': 'true',
__v: '0',
_id: '54ec04e70398fab504085178',
name: 'j' }
done
{ [MongoError: unknown top level operator: $resolved]
name: 'MongoError',
code: 2,
err: 'unknown top level operator: $resolved' }
null
I if I refresh the page, the it gets deleted fine. But if I added the entry, angular seems to be adding a new variable $resolved. Why is that happening?
Also another question, What is the proper way to call delete? I call it now but I am not able to put a callback. I want a callback which returns and then I shift the list of items. I tried adding a callback but the code never reaches it.
ie I tried the following
/*
Meetup.delete(item, function () {
console.log("In callback!!");
console.log(returnValue);
console.log(responseHeaders);
$scope.meetups.splice(item);
});
*/
/*Meetup.delete(item,
function (returnValue, responseHeaders) {
console.log("In callback!!");
console.log(returnValue);
console.log(responseHeaders);
$scope.meetups.splice(item);
},
function (httpResponse){
// error handling here
console.log("Need to handle errors");
});
*/
I am very new to node and am confused. Any help is very, very appreciated
Looks like it possible to call item.delete instead of Meetup.delete(item). You can call same methods on model instance. It prevent sending angular properties to server.
But better to make a rest API with delete method
DELETE /meetups/:id
and send just a _id
Meetup.remove({id: item._id});

PhoneGap/Cordova with client-side routing?

I've inherited a Cordova/PhoneGap app running Cordova 3.4. My first task was to implement a Client-Side Routing framework to make it easier to navigate between pages. I chose Flatiron Director as my client-side router, but when I went to implement it I started to get weird functionality out of the app.
My first router setup:
var routing = {
testHandler: function(){
console.log('Route ran');
},
routes: function(){
return {
"/testhandler": testHandler
}
}
};
console.log('Routes added');
The routes are added (at least based on the console output). When I attempt to hit the /testhandler hash, I receive a "Failed to load resource: file:///testhandler" error when I set window.location.hash to "/testhandler". I noticed the "Route ran" statement was never printed.
My next attempt was just using the hashchange event with jQuery.
$(window).on('hashchange', function(){ console.log('Ran'); });
On this attempt, regardless of what I change the hash to, I see the 'Ran' output, but I still receive the "Failed to load resource: " error.
Is this a problem with PhoneGap/Cordova? Or our implementation? Is it just not possible to use client-side routing with Cordova? What am I doing wrong?
I know that this doesn't answer your question directly but you may consider making your own provisional router. This may help you to debug your app and to figure out what's the problem.
Something like this for example:
var router = (function (routes) {
var onRouteChange = function () {
// removes hash from the route
var route = location.hash.slice(1);
if (route in routes) {
routes[route]();
} else {
console.log('Route not defined');
}
};
window.addEventListener('hashchange', onRouteChange, false);
return {
addRoute: function (hashRoute, callback) {
routes[hashRoute] = callback;
},
removeRoute: function (hashRoute) {
delete routes[hashRoute];
}
};
})({
route1: function () {
console.log('Route 1');
document.getElementById('view').innerHTML = '<div><h1>Route 1</h1><p>Para 1</p><p>Para 2</p></div>';
},
route2: function () {
console.log('Route 2');
document.getElementById('view').innerHTML = '<div><h1>Route 1</h1><p>Para 1</p><p>Para 2</p></div>';
}
});

Categories