Handle multiple gmail accounts - javascript

I am using Google Calendar JavaScript API.It works fine for single account.Problem is when user is logged-in into two of my gmail accounts, It asks user every time to select which account user want to use.
I want API to remember my last selection at least for the session or most preferably till user disconnect himself.
Here is my JS file.
var clientId = $("#CalendarClientId").val();
var scopes = 'https://www.googleapis.com/auth/calendar';
var objEventList = [];
var calendarIdAtt;
function InitilizeCalendarAPI() {
// Step 2: Reference the API key
window.setTimeout(checkAuth, 5);
}
function CheckGoogleCalAuth() {
gapi.auth.authorize({ client_id: clientId, scope: scopes }, HandleAuthCallBack);
}
function checkAuth() {
gapi.auth.authorize({ client_id: clientId, scope: scopes }, HandelCalAuthResult);
}
function CheckAuthentication() {
gapi.auth.checkSessionState({ client_id: clientId }, CheckAuthCallback);
}
function CheckAuthCallback(loginDataCallback) {
if (loginDataCallback == false) {
checkAuth();
$("#googleAuthorize-Button").hide();
}
}
function HandelCalAuthResult(authResult) {
if (authResult && !authResult.error) {
/*authorizeButton.style.visibility = 'hidden';*/
$("#googleAuthorize-Button").hide();
if ($("#googleConnected").length > 0) {
$("#googleConnected").show();
}
/*bind listing of google calendar name in addevent page*/
if ($("#divGoogleCalendarNameList").length > 0) {
GetListOfCalendarNameFromGoogle();
}
} else {
$("#googleAuthorize-Button").show();
/*authorizeButton.style.visibility = '';*/
if ($("#googleConnected").length > 0) {
$("#googleConnected").hide();
}
}
if ($('#googleAuthorized-Button').length > 0) {
$("#googleAuthorize-Button").hide();
$('#googleAuthorized-Button').show();
$('#calenderSettingIcon').attr('data-original-title', 'Connected To Google');
}
}
function CheckAutheForEventList() {
gapi.auth.checkSessionState({ client_id: clientId }, CheckAuthCallbackListEvent);
}
function CheckAuthCallbackListEvent(loginDataCallback)
{
gapi.auth.authorize({ client_id: clientId, scope: scopes }, LoadEventListinAPI);
}
function checkAuthEventList() {
ConfirmConnectionToGoogleCalendar(function (isConnect) {
if (isConnect) {
gapi.auth.authorize({ client_id: clientId, scope: scopes }, LoadEventListinAPI);
}
});
}
function LoadEventListinAPI() {
gapi.client.load('calendar', 'v3', GetAllCalendar);
}
function GetAllCalendar() {
gapi.client.load('calendar', 'v3', GetCalendarAndTheirEvents);
}
function GetCalendarAndTheirEvents() {
objEventList = [];
try {
var objDate = GetMinAndMaxDate();
var finalMinDate = (objDate.MinDate).toISOString();;
var finalMaxDate = (objDate.MaxDate).toISOString();;
var request = gapi.client.calendar.calendarList.list();
var tempCount = 0;
request.execute(function (resp) {
var calLength = resp.items.length;
$.each(resp.items, function (index, item) {
if (item.accessRole == "owner") {
try {
calendarIdAtt = item.id;
var request = gapi.client.calendar.events.list({
'calendarId': item.id,
'showDeleted': false,
'singleEvents': true,
'orderBy': 'startTime',
'maxResults': 100,
'timeMin': finalMinDate,
'timeMax': finalMaxDate
});
request.execute(function (resp) {
tempCount = tempCount + 1;
var events = resp.items;
if (events.length > 0) {
objEventList.push(events);
}
if (tempCount == calLength) {
//Binding Kendo Scheduler with Google Calenda Events
var eventsList = BindEventToCalendar();
LoadEventsScheduler(eventsList);
}
});
}
catch (error) {
tempCount = tempCount + 1;
if (tempCount == calLength) {
BindEventToCalendar();
}
}
}
else {
tempCount = tempCount + 1;
if (tempCount == calLength) {
BindEventToCalendar();
}
}
});
});
return objEventList;
}
catch (exception) {
BindEventToCalendar();
return null;
}
}
//Function will display google calendar events in the Kendo Scheduler
function LoadEventsScheduler(eventsList) {
//This will retrun all the google calendar events to the server side for the scheduler
var request = {
EventsList: eventsList, CalendarAccount: calendarIdAtt
};
$.ajax({
type: "POST",
data: JSON.stringify(request),
url: $_SetEventScheduler,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
var data;
if (msg.hasOwnProperty("d")) {
data = msg.d;
}
else
data = msg;
if (data.success) {
$("#scheduler").data("kendoScheduler").dataSource.read();
}
else {
}
}
});
}
I noticed that API show me logged in but calendar is not stored in case of multiple accounts,so it asks me again to select the account.
Summary: I want to save the complete scenario (may be calendar_id or any unique identifier) which can tell API which account and which calendar should be picked up.
If you need more details, please let me know.

I simply used the auth2 implementation and it is working perfect.
Basically current session state function do not work properly in old API. That's why it was asking every time for selecting the account and calendar.

Related

Tabulator not working with remote pagination and ajaxURLGenerator

I have an issue with tabulator (4.9.1) and the pagination, when I try to configure it with remote pagination and ajaxUrlGenerator function, it never pass into the generator function, after investigating the code I've noticed that the code of tabulator do the following :
Tabulator.prototype._loadInitialData = function () {
var self = this;
if (self.options.pagination && self.modExists("page")) {
self.modules.page.reset(true, true);
if (self.options.pagination == "local") {
if (self.options.data.length) {
self.rowManager.setData(self.options.data, false, true);
} else {
if ((self.options.ajaxURL || self.options.ajaxURLGenerator) && self.modExists("ajax")) {
self.modules.ajax.loadData(false, true).then(function () {}).catch(function () {
if (self.options.paginationInitialPage) {
self.modules.page.setPage(self.options.paginationInitialPage);
}
});
return;
} else {
self.rowManager.setData(self.options.data, false, true);
}
}
if (self.options.paginationInitialPage) {
self.modules.page.setPage(self.options.paginationInitialPage);
}
} else {
if (self.options.ajaxURL) {
self.modules.page.setPage(self.options.paginationInitialPage).then(function () {}).catch(function () {});
} else {
self.rowManager.setData([], false, true);
}
}
} else {
if (self.options.data.length) {
self.rowManager.setData(self.options.data);
} else {
if ((self.options.ajaxURL || self.options.ajaxURLGenerator) && self.modExists("ajax")) {
self.modules.ajax.loadData(false, true).then(function () {}).catch(function () {});
} else {
self.rowManager.setData(self.options.data, false, true);
}
}
}
};
using the ajaxURLGenerator with the 'local' configuration makes it work correctly in remote.
But then it doesn't do the progressive pagination and doesn't pass the parameters correctly in the ajaxURLGenerator function, probably due to the parsing mecanism that is not called in 'local' mode for the data :
Page.prototype.trigger = function () {
var _this81 = this;
var left;
return new Promise(function (resolve, reject) {
switch (_this81.mode) {
case "local":
left = _this81.table.rowManager.scrollLeft;
_this81.table.rowManager.refreshActiveData("page");
_this81.table.rowManager.scrollHorizontal(left);
_this81.table.options.pageLoaded.call(_this81.table, _this81.getPage());
resolve();
break;
case "remote":
case "progressive_load":
case "progressive_scroll":
_this81.table.modules.ajax.blockActiveRequest();
_this81._getRemotePage().then(function () {
resolve();
}).catch(function () {
reject();
});
break;
default:
console.warn("Pagination Error - no such pagination mode:", _this81.mode);
reject();
}
});
};
At the end it is loading, but all the data when the server return just a json list, but it fail when receiving the object expected for the remote pagination.
Does anyone had the same issue with remote pagination and ajaxURLGenerator? Anyone has an idea how to solve it, without modifying the library?
Thanks in advance

3rd party Authentication Issues in Google Appscript

I am using an internal service to Authenticate my Gsuite add-on. The Issue is we cannot find any request made from the Add-on to internal servers on Prod (or Dev environments). These are public facing authentication endpoints.
Currently this Addon only runs in Gmail. Unsure If there are any bandwidth limits we might be reaching but Google support said they couldn't help.
We followed the docs Google provides for 3rd Part Oauth.
auth File:
function accessProtectedResource(url, method_opt, headers_opt, body) {
var service = getOAuthService();
var maybeAuthorized = service.hasAccess();
if (maybeAuthorized) {
// A token is present, but it may be expired or invalid. Make a
// request and check the response code to be sure.
// Make the UrlFetch request and return the result.
var accessToken = service.getAccessToken();
var method = method_opt || 'get';
var headers = headers_opt || {};
headers['Authorization'] = Utilities.formatString('Bearer %s', accessToken);
var resp = UrlFetchApp.fetch(url, {
'headers': headers,
'method' : method,
'contentType': 'application/json',
'muteHttpExceptions': true, // Prevents thrown HTTP exceptions.
'payload': JSON.stringify(body)
});
var code = resp.getResponseCode();
if (code >= 200 && code < 300) {
return resp.getContentText('utf-8'); // Success
} else if (code >= 400 && code <= 403) {
// Not fully authorized for this action.
maybeAuthorized = false;
} else {
// Handle other response codes by logging them and throwing an exception.
Logger.log('Server error (%s): %s', code.toString(),
resp.getContentText('utf-8'));
throw ('Backend server error: ' + code);
}
}
if (!maybeAuthorized) {
// Invoke the authorization flow using the default authorization
// prompt card.
CardService.newAuthorizationException()
.setAuthorizationUrl(service.getAuthorizationUrl())
.setCustomUiCallback('createCompanyeAuthorizationUi')
.setResourceDisplayName('Company')
.throwException();
}
}
function getOAuthService() {
// added Console.log for debug
var service = OAuth2.createService('COMPANY_AUTH')
var servicewithurl = service.setAuthorizationBaseUrl(urlBase + '/oauth2/authenticate/');
var setauthBase = servicewithurl.setAuthorizationBaseUrl(urlBase + '/oauth2/authenticate/');
console.log('setauthBase ', setauthBase);
var setToken = setauthBase.setTokenUrl(urlBase + '/oauth/token/');
console.log('setToken ',setToken);
var setCallback = setToken.setCallbackFunction('authCallback');
console.log('setCallback ', setCallback);
setCallback.setClientId('2222TW9LzuT4AgAMN')
.setClientSecret('WZN5tyDKfMYoDLNnC')
.setPropertyStore(PropertiesService.getUserProperties());
.setCache(CacheService.getUserCache())
console.log('setCallback2 ', setCallback);
return setCallback;
}
function authCallback(callbackRequest) {
var authorized = getOAuthService().handleCallback(callbackRequest);
if (authorized) {
return HtmlService.createHtmlOutput(
'Success! <script>setTimeout(function() { top.window.close() }, 1);</script>');
} else {
return HtmlService.createHtmlOutput('Denied');
}
}
function createCompanyAuthorizationUi() {
var service = getOAuthService();
var authUrl = service.getAuthorizationUrl();
var authAction = CardService.newAuthorizationAction().setAuthorizationUrl(authUrl);
var CompanyLogo = CardService.newImage().setAltText("Company Logo").setImageUrl("image_url_replaced");
var headerText = 'Create actions in Company from your email.';
var mainImage = CardService.newImage().setAltText("Company Mail").setImageUrl("image_url_replaced");
var loginButton = CardService.newImage().setAltText("Login").setImageUrl("image_url_replaced").setAuthorizationAction(authAction);
var signupLink = CardService.newOpenLink()
.setUrl(urlBase + "/join")
.setOpenAs(CardService.OpenAs.FULL_SIZE)
.setOnClose(CardService.OnClose.NOTHING);
var signupButton = CardService.newImage().setAltText("Sign up").setImageUrl("image_url_replaced").setOpenLink(signupLink);
var featureOne = CardService.newKeyValue()
.setIconUrl("image_url_replaced")
.setContent("Company is the best way to plan, execute, and monitor all of your teams's projects in one place.")
.setMultiline(true);
var featureTwo = CardService.newKeyValue()
.setIconUrl("image_url_replaced")
.setContent("Content here")
.setMultiline(true);
var card = CardService.newCardBuilder()
.addSection(CardService.newCardSection()
.addWidget(CardService.newTextParagraph())
.addWidget(CompanyLogo)
.addWidget(CardService.newTextParagraph().setText(headerText))
.addWidget(mainImage)
.addWidget(signupButton)
.addWidget(loginButton)
.addWidget(featureOne)
.addWidget(featureTwo)
).build();
return [card];
}
function resetOAuth() {
getOAuthService().reset();
}
function getCompanyResourceUrls() {
accessProtectedResource(urlBase + '/api/v1/books/');
}
function makeRequest(url, params) {
var oauthService = getOAuthService();
var response = UrlFetchApp.fetch(url, {
headers: {
Authorization: 'Bearer ' + oauthService.getAccessToken()
},
body: params
});
return response;
}
function getUserId() {
var cache = CacheService.getUserCache();
var userId = cache.get('userId');
if(userId) {
return userId;
}
var response = accessProtectedResource(urlBase + '/oauth/getIdentity');
var data = JSON.parse(response);
var userId = data.data.id;
cache.put('userId', userId);
return userId;
}
appsscript.json
{
"timeZone": "America/New_York",
"dependencies": {
"libraries": [{
"userSymbol": "OAuth2",
"libraryId": "",
"version": "37",
"developmentMode": true
}]
},
"webapp": {
"access": "ANYONE",
"executeAs": "USER_ACCESSING"
},
"oauthScopes": ["https://www.googleapis.com/auth/gmail.addons.execute", "https://www.googleapis.com/auth/gmail.addons.current.message.readonly", "https://www.googleapis.com/auth/script.external_request"],
"urlFetchWhitelist": ["https://company.com/", "https://company.com/oauth/token/", "https://company.com/api/v1/books/", "https://companycom/oauth/revoke"],
"runtimeVersion": "V8",
"gmail": {
"name": "Name",
"logoUrl": "https://logourl.com",
"contextualTriggers": [{
"unconditional": {
},
"onTriggerFunction": "buildAddOn"
}],
"universalActions": [{
"text": "Logout",
"runFunction": "logout"
}],
"primaryColor": "#ffffff",
"secondaryColor": "#ffffff",
"authorizationCheckFunction": "getCompanyResourceUrls",
"openLinkUrlPrefixes": ["https://company.com/"]
}
}
You made mistake:
.setCustomUiCallback('createCompanyeAuthorizationUi')
but you have
createCompanyAuthorizationUi
I am not sure, but it can help you.

Login Google javascript

I´m using google login javascript.
I want import js after click button. The problem: Only show popup login google the second time I click the button
My Code:
function clickButton(){
$.getScript( "https://apis.google.com/js/client:plusone.js?onload=onLoadGoogleLogin");
}
function onLoadGoogleLogin()
{
var initializedGoogleCallback = false;
gapi.client.setApiKey('AIzaSyBhV6vP_D_I7ldL1YIU7LJUGtSxJ55ievw');
var myParams = {
'callback': function googleLoginCallback(result) {
debugger;
if (!initializedGoogleCallback) {
if (result) {
if (result['error'] == undefined) {
initializedGoogleCallback = true;
gapi.auth.setToken(result);
gapi.client.load('oauth2', 'v2', function () {
var request = gapi.client.oauth2.userinfo.get();
request.execute(googleLoginDataUserCallback);
});
}
} else {
alert('Empty authResult');
}
}
},
'clientid': 'xxxxx-4kragpsm6jolann6d9t74crpkthch0iq.apps.googleusercontent.com',
'cookiepolicy': 'single_host_origin',
'requestvisibleactions': 'http://schemas.google.com/AddActivity',
'scope': 'https://www.googleapis.com/auth/plus.login'
}

ExtJs minify Gets ignored

We have a CMS so I don't have access to the header of the HTML page which gets rendered for our extjs implementation. So I had to make a workaround which is like this:
Ext.local = {};
var lang = {
initLang: function (revisionNr) {
var local = localStorage.getItem('localLang')
if (!local) {
AjaxHandlerByClass('ajax/lang/webuser/init', {}, this.loadLangRemote);
} else {
local = JSON.parse(local);
if (local.revisionNr == config.revisionNr && local.lang == config.lang) {
console.log('loading local lang variables');
if (local.date < new Date().getTime() - (24 * 60 * 60 * 1000) * 2) {//2 day caching time before retry
delete window.localStorage.localLangBackup;
}
this.loadLangLocal(local);
} else {
delete window.localStorage.localLang;
AjaxHandlerByClass('ajax/lang/webuser/init', {}, this.loadLangRemote);
}
}
},
loadLangRemote: function (data) {
data.revisionNr = config.revisionNr;
data.lang = config.lang;
data.date = new Date().getTime();
lang.loadLangLocal(data);
localStorage.setItem('localLang', JSON.stringify(data));
},
loadLangLocal: function (data) {
var jsElm = document.createElement("script");
jsElm.type = "application/javascript";
jsElm.src = 'js/freetext-deploy.min.js?rev={/literal}{$revisionNr}{literal}';
document.getElementsByTagName('head')[0].appendChild(jsElm);
Ext.Date.defaultFormat = 'd-m-Y';
if (!debug) {
Ext.Loader.config.disableCaching = true;
}
Ext.application({
name: 'freetextOrder',
appFolder: 'modules/extjs/freetextOrder/app',
controllers: [
'Main'
],
launch: function () {
var freetextOrder = Ext.create('Ext.container.Container', {
renderTo: Ext.get('freetextOrderDiv'),
layout: 'fit',
id: 'catalogAdministrationDiv_ext',
height: 800,
cls: 'x-dig-override',
items: [Ext.create('freetextOrder.view.base.MainView', {})],
layout:'fit'
});
}
});
Ext.local = data;
}
};
lang.initLang();
The problem I'm having is that the minified version gets ignored completely. I see it load on the http request but extjs ignores them.... even though I can see the objects are being created after include (via console log)
Anyone any idea how I can achieve this?
as i see none found the answer so i post my own here wich i came up with.
Since i could for the love of god not load the damn thing i refactored the loader and exported it into a Js. file. wich i reqired and called later on in code.
exported lang.js file:
Ext.define('Lang', {
singleton: true,
ApplicationConf: null,
Launch: function (launchConfig) {
this.ApplicationConf = launchConfig;
var local = localStorage.getItem('localLang');
var me = this;
this.loadLangRemote = function (data) {
debugger;
data.revisionNr = config.revisionNr;
data.lang = config.lang;
data.date = new Date().getTime();
me.loadLangLocal(data);
localStorage.setItem('localLang', JSON.stringify(data));
};
this.loadLangLocal = function (data) {
Ext.local = data;
Ext.lang = function (langId) {
if (Ext.local[langId]) {
return Ext.local[langId];
}
delete window.localStorage.localLang;
localStorage.setItem('localLangBackup', true);
return langId;
}
Ext.application(me.ApplicationConf);
};
if (!local) {
Ext.Ajax.request({
url: 'ajax/lang/webuser/init',
params: {
sid: sid,
},
success: function (data) {
debugger;
me.loadLangRemote(Ext.JSON.decode(data.responseText));
}
})
} else {
local = JSON.parse(local);
if (local.revisionNr == config.revisionNr && local.lang == config.lang) {
console.log('loading local lang variables');
if (local.date < new Date().getTime() - (24 * 60 * 60 * 1000) * 2) {//2 day caching time before retry
delete window.localStorage.localLangBackup;
}
debugger;
me.loadLangLocal(local);
} else {
delete window.localStorage.localLang;
Ext.Ajax.request({
url: 'ajax/lang/webuser/init',
params: {
sid: sid,
},
success: function (data) {
me.loadLangRemote(Ext.JSON.decode(data.responseText));
}
})
}
}
},
})
And IMPORTANT was to add the
Ext.onReady(function () {
Lang.Launch({
name: 'catalogAdministration',
appFold....
To the call of the Launch function in code, bacause it would have been not defined at run time. i added the file to the minified file first and call the Lang.Launch instead Ext.Application.
Hope somone has use of my solution :)

jQuery plugin callback function and parameter settings issue

I have developed below plug-in
(function($) {
$.fn.addressSearch = function(settings) {
settings = jQuery.extend({
searchClass: "quickSearch",
checkElement: "href",
dataElement: "data",
countryListClass: "countryList",
countryCode: "11455",
errorMsg: "You can only search for address in the UK.",
houseNumberClass: "TextboxHouseNumber",
postcodeClass: "postcode",
addressLine1Class: "addSearchLine1",
addressLine2Class: "addSearchLine2",
addressLine3Class: "addSearchLine3",
addressTownCityClass: "addTownCity",
ajaxUrl: "/WebService/addressLook",
submitType: "POST",
dataType: "xml",
parameters: "",
addressProcessURL: "",
callbackFunctionSingleAddress: selectAddress, //Callback 1
callbackFunctionMultipleAddress: quickBoxSearch, //Callback 2
useExternalProcessPage: false,
validateCountry: true
}, settings);
var jQueryMatchedObj = this;
function _initialize() {
_startModal(this, jQueryMatchedObj);
return false;
}
function _startModal(objClicked, jQueryMatchedObj) {
$j(objClicked).addClass(settings.searchClass);
var countryList = "." + settings.countryListClass + "";
if (settings.validateCountry) {
if ($j(countryList) && $j(countryList).val() != settings.countryCode) {
alert(settings.errorMsg);
return false;
}
}
if (settings.parameters) {
$j.ajax({
url: settings.ajaxUrl,
type: settings.submitType,
dataType: settings.dataType,
data: settings.parameters,
success: function(res) {
var addresses = eval(res.getElementsByTagName('string')[0].firstChild.data);
if (addresses.length == 0)
alert('Your address could not be found, please enter it manually');
else if (addresses.length == 1) {
//Callback 1 and parameters set here
settings.callbackFunctionSingleAddress(
addresses[0].addressLine1,
addresses[0].addressLine2,
addresses[0].addressLine3,
addresses[0].town,
settings.TextboxHouseNumber,
settings.postcodeClass,
settings.addressTownCityClass,
settings.addressLine1Class,
settings.addressLine2Class,
settings.addressLine3Class
);
} else if (addresses.length > 1) {
//Callback 2 and parameters set here
settings.callbackFunctionMultipleAddress(
settings.callbackFunctionSingleAddress,
addresses,
settings.useExternalProcessPage,
settings.TextboxHouseNumber,
settings.postcodeClass,
settings.addressTownCityClass,
settings.addressLine1Class,
settings.addressLine2Class,
settings.addressLine3Class
);
}
}
});
}
return false;
}
return this.unbind('click').click(_initialize);
}
})(jQuery);
Above works fine without any problem. I call this with code below
$('#mydiv').click(function() {
$(this).addressSearch(/* ... */);
});
However now I want to extend this even further with the passing both callback functions and parameters in the settings for the plugging so the plugging will be more robust.
how do I do this, basically I want to pass
settings.callbackFunctionSingleAddress(
addresses[0].addressLine1,
addresses[0].addressLine2,
addresses[0].addressLine3,
addresses[0].town,
settings.TextboxHouseNumber,
settings.postcodeClass,
settings.addressTownCityClass,
settings.addressLine1Class,
settings.addressLine2Class,
settings.addressLine3Class
);
AND
settings.callbackFunctionMultipleAddress(
settings.callbackFunctionSingleAddress,
addresses,
settings.useExternalProcessPage,
settings.TextboxHouseNumber,
settings.postcodeClass,
settings.addressTownCityClass,
settings.addressLine1Class,
settings.addressLine2Class,
settings.addressLine3Class
);
as parameters on the click event of a div. So it would look like,
$('#mydiv').click(function() {
$(this).addressSearch({
callbackFunctionSingleAddress: callbackFuntion(param1, param2)
});
});
Above is the idea. Is this possible? Please help
If I'm reading this right, all you need to do is wrap the callbackFunction in a function block:
$('#mydiv').click(function() {
$(this).addressSearch({
callbackFunctionSingleAddress: function() { callbackFuntion(param1, param2); }
});
});

Categories

Resources