From 2a809a00a01d2fd25f107aca2f7c66c3a0d4bbf2 Mon Sep 17 00:00:00 2001 From: Kapil Date: Tue, 28 May 2019 13:24:15 +0530 Subject: [PATCH 01/41] Login branch initial commit --- Commands/GCCommands.ts | 24 ++++++++++++++++++++++++ Commands/GSGetter.ts | 0 GoogleCalendar.ts | 24 ++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 Commands/GCCommands.ts create mode 100644 Commands/GSGetter.ts diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts new file mode 100644 index 0000000..440cc15 --- /dev/null +++ b/Commands/GCCommands.ts @@ -0,0 +1,24 @@ +import { IHttp, IModify, IPersistence, IRead } from '@rocket.chat/apps-engine/definition/accessors'; +import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; +import { GoogleCalendarApp } from '../GoogleCalendar'; + +export class GiphyCommand implements ISlashCommand { + + public command = 'calendar'; + public i18nParamsExample = 'Calendar_login'; + public i18nDescription = 'Calendar_Command_Description'; + public providesPreview = false; + + constructor(private readonly app: GoogleCalendarApp) { } + + public executor(context: SlashCommandContext, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise { + // if there are no args or args[0] === 'random' + // then get a single one + + // otherwise, fetch the results and get a random one + // as the max amount returned will be ten + throw new Error('Method not implemented.'); + } + + +} \ No newline at end of file diff --git a/Commands/GSGetter.ts b/Commands/GSGetter.ts new file mode 100644 index 0000000..e69de29 diff --git a/GoogleCalendar.ts b/GoogleCalendar.ts index 7c50b90..bf14c77 100644 --- a/GoogleCalendar.ts +++ b/GoogleCalendar.ts @@ -1,4 +1,6 @@ import { + IConfigurationExtend, + IEnvironmentRead, IAppAccessors, ILogger, } from '@rocket.chat/apps-engine/definition/accessors'; @@ -13,6 +15,28 @@ export class GoogleCalendarApp extends App { super(info, logger, accessors); } + protected async extendConfiguration(configuration: IConfigurationExtend, environmentRead: IEnvironmentRead): Promise { + await configuration.settings.provideSetting({ + id: 'calendar_apikey', + type: SettingType.STRING, + packageValue: '', + required: true, + public: false, + i18nLabel: 'Customize_GoogleCalendar_APIKey', + i18nDescription: 'Customize_GoogleCalendar_APIKey_Description', + }); + await configuration.settings.provideSetting({ + id: 'calendar_clientid', + type: SettingType.STRING, + packageValue: 'en', + required: true, + public: false, + i18nLabel: 'Customize_Calendar_ClientID', + i18nDescription: 'Customize_Calendar_ClientID', + }); + await configuration.slashCommands.provideSlashCommand(new GCCommand(this)); + + } } \ No newline at end of file From 2c27edfcc3f0346532d5b663a19b6971c40f8593 Mon Sep 17 00:00:00 2001 From: Kapil Date: Tue, 28 May 2019 15:18:10 +0530 Subject: [PATCH 02/41] Basic Message Printing --- Commands/GCCommands.ts | 28 ++++++++++++++++++++++++---- Commands/GSGetter.ts | 0 GoogleCalendar.ts | 3 ++- 3 files changed, 26 insertions(+), 5 deletions(-) delete mode 100644 Commands/GSGetter.ts diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts index 440cc15..2b9893d 100644 --- a/Commands/GCCommands.ts +++ b/Commands/GCCommands.ts @@ -2,7 +2,7 @@ import { IHttp, IModify, IPersistence, IRead } from '@rocket.chat/apps-engine/de import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; import { GoogleCalendarApp } from '../GoogleCalendar'; -export class GiphyCommand implements ISlashCommand { +export class GCCommand implements ISlashCommand { public command = 'calendar'; public i18nParamsExample = 'Calendar_login'; @@ -11,14 +11,34 @@ export class GiphyCommand implements ISlashCommand { constructor(private readonly app: GoogleCalendarApp) { } - public executor(context: SlashCommandContext, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise { + public async executor(context: SlashCommandContext, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise { // if there are no args or args[0] === 'random' // then get a single one // otherwise, fetch the results and get a random one // as the max amount returned will be ten - throw new Error('Method not implemented.'); - } + // throw new Error('Method not implemented.'); + + + + + const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); + try{ + + const parame = context.getArguments().join(' '); + if(parame=='auth') + msg.setText('This basic part is working with auth'); + if(parame=='logout') + msg.setText('This basic part is working with logout') + await modify.getCreator().finish(msg); + }catch (e) { + this.app.getLogger().error('Failed getting a gif', e); + msg.setText('An error occurred when trying to send the gif :disappointed_relieved:'); + + modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); + } + + } } \ No newline at end of file diff --git a/Commands/GSGetter.ts b/Commands/GSGetter.ts deleted file mode 100644 index e69de29..0000000 diff --git a/GoogleCalendar.ts b/GoogleCalendar.ts index bf14c77..7bbda30 100644 --- a/GoogleCalendar.ts +++ b/GoogleCalendar.ts @@ -7,6 +7,7 @@ import { import { App } from '@rocket.chat/apps-engine/definition/App'; import { IAppInfo } from '@rocket.chat/apps-engine/definition/metadata'; import { SettingType } from '@rocket.chat/apps-engine/definition/settings'; +import { GCCommand } from './Commands/GCCommands'; export class GoogleCalendarApp extends App { @@ -29,7 +30,7 @@ export class GoogleCalendarApp extends App { await configuration.settings.provideSetting({ id: 'calendar_clientid', type: SettingType.STRING, - packageValue: 'en', + packageValue: '', required: true, public: false, i18nLabel: 'Customize_Calendar_ClientID', From 140654e7c3f0aa0fa5d9abb4b86730fceb5ed62f Mon Sep 17 00:00:00 2001 From: Kapil Date: Wed, 29 May 2019 21:12:12 +0530 Subject: [PATCH 03/41] Login/Logout Api Call --- Commands/GCCommands.ts | 13 +++++----- GoogleCalendar.ts | 21 +++++++++++++++- helpers/GCResult.ts | 23 ++++++++++++++++++ helpers/GSGetter.ts | 54 ++++++++++++++++++++++++++++++++++++++++++ library.js | 12 ++++++++++ 5 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 helpers/GCResult.ts create mode 100644 helpers/GSGetter.ts create mode 100644 library.js diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts index 2b9893d..5163b8a 100644 --- a/Commands/GCCommands.ts +++ b/Commands/GCCommands.ts @@ -1,6 +1,8 @@ import { IHttp, IModify, IPersistence, IRead } from '@rocket.chat/apps-engine/definition/accessors'; import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; import { GoogleCalendarApp } from '../GoogleCalendar'; +import { GCResults } from '../helpers/GCResult'; + export class GCCommand implements ISlashCommand { @@ -19,18 +21,15 @@ export class GCCommand implements ISlashCommand { // as the max amount returned will be ten // throw new Error('Method not implemented.'); - - + + const cont= context.getArguments; const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); try{ - const parame = context.getArguments().join(' '); - if(parame=='auth') - msg.setText('This basic part is working with auth'); - if(parame=='logout') - msg.setText('This basic part is working with logout') + const loginstatus = await this.app.getGCGetter().login(cont,this.app.getLogger(), http); + await modify.getCreator().finish(msg); }catch (e) { this.app.getLogger().error('Failed getting a gif', e); diff --git a/GoogleCalendar.ts b/GoogleCalendar.ts index 7bbda30..0e13197 100644 --- a/GoogleCalendar.ts +++ b/GoogleCalendar.ts @@ -8,13 +8,22 @@ import { App } from '@rocket.chat/apps-engine/definition/App'; import { IAppInfo } from '@rocket.chat/apps-engine/definition/metadata'; import { SettingType } from '@rocket.chat/apps-engine/definition/settings'; import { GCCommand } from './Commands/GCCommands'; +import { GCGetter } from './helpers/GSGetter'; + export class GoogleCalendarApp extends App { + private gcGetter: GCGetter; + constructor(info: IAppInfo, logger: ILogger, accessors: IAppAccessors) { super(info, logger, accessors); - + this.gcGetter = new GCGetter(); + + } + + public getGCGetter(): GCGetter { + return this.gcGetter; } protected async extendConfiguration(configuration: IConfigurationExtend, environmentRead: IEnvironmentRead): Promise { await configuration.settings.provideSetting({ @@ -37,6 +46,16 @@ export class GoogleCalendarApp extends App { i18nDescription: 'Customize_Calendar_ClientID', }); + await configuration.settings.provideSetting({ + id: 'calendar_secret_key', + type: SettingType.STRING, + packageValue: '', + required: true, + public: false, + i18nLabel: 'Customize_Calendar_SecretKey', + i18nDescription: 'Customize_Calendar_SecretKey', + }); + await configuration.slashCommands.provideSlashCommand(new GCCommand(this)); } diff --git a/helpers/GCResult.ts b/helpers/GCResult.ts new file mode 100644 index 0000000..dd4af7b --- /dev/null +++ b/helpers/GCResult.ts @@ -0,0 +1,23 @@ +import { ISlashCommandPreviewItem, SlashCommandPreviewItemType } from '@rocket.chat/apps-engine/definition/slashcommands'; +import { HttpStatusCode, IHttp, ILogger, IRead } from '@rocket.chat/apps-engine/definition/accessors'; + +export class GCResults { + public atoken: string; + + constructor(data?: any) { + + if (data) { + this.atoken = data.access_token as string; + } + } + + public result(): Promise { + if (!this.atoken) { + throw new Error('Invalid result'); + } + else + return this.atoken; + + } + +} \ No newline at end of file diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts new file mode 100644 index 0000000..7e693f2 --- /dev/null +++ b/helpers/GSGetter.ts @@ -0,0 +1,54 @@ +import { HttpStatusCode, IHttp, ILogger, IRead } from '@rocket.chat/apps-engine/definition/accessors'; +import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; +import { GCResults } from '../helpers/GCResult'; + +export class GCGetter { + private readonly Client_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; + private readonly api_key = 'AIzaSyAY1YAPK1lIcx1bgsLOgsRfNfAluVQhuq4'; + private readonly DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"]; + private readonly SCOPES = "https://www.googleapis.com/auth/calendar.readonly"; + private readonly urli = 'https://accounts.google.com/o/oauth2/v2/auth?'; + private readonly secret = '-lYglmNGqFNNazKoQX1m-EC9'; + + public async login(phase: string, logger: ILogger, http: IHttp): Promise { + + let signedin: boolean = false; + + const parame = phase; + + if (parame == 'auth') { + //step1,2,3 + + const response = await http.get(`${this.urli}client_id='${this.Client_id}'&redirect_uri=http://localhost:3000/general&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&response_type=code`); + + //step4 + if (response.statusCode !== HttpStatusCode.OK || !response.data) { + logger.debug('Did not get a valid response', response); + throw new Error('Unable to retrieve gifs.'); + } + + //response = https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7 + //need to create regex such that res=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7 + const res = new RegExp['']; + + const newresponse = await http.get(`https://www.googleapis.com/oauth2/v4/token/code='${this.res}'&client_id='${this.Client_id}'&client_secret='${this.secret}'&redirect_uri=http://localhost:3000/general&grant_type=authorization_code`); + + + const acesstoken = new GCResults(newresponse); + + if (accesstoken) { + signedin = true; + } + + + } + + if (parame == 'logout') { + const resnew = await http.get(`https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=http://localhost:3000`); + } + + return signedin; + + } + +} \ No newline at end of file diff --git a/library.js b/library.js new file mode 100644 index 0000000..3f02805 --- /dev/null +++ b/library.js @@ -0,0 +1,12 @@ +var gapi=window.gapi=window.gapi||{};gapi._bs=new Date().getTime();(function(){var g=function(){this.g=""};g.prototype.toString=function(){return"SafeScript{"+this.g+"}"};g.prototype.a=function(a){this.g=a};(new g).a("");var h=function(){this.j=""};h.prototype.toString=function(){return"SafeStyle{"+this.j+"}"};h.prototype.a=function(a){this.j=a};(new h).a("");var m=function(){this.i=""};m.prototype.toString=function(){return"SafeStyleSheet{"+this.i+"}"};m.prototype.a=function(a){this.i=a};(new m).a("");var n=function(){this.f=""};n.prototype.toString=function(){return"SafeHtml{"+this.f+"}"};n.prototype.a=function(a){this.f=a};(new n).a("");(new n).a("");(new n).a("
");/* + gapi.loader.OBJECT_CREATE_TEST_OVERRIDE &&*/ +var q=window,v=document,aa=q.location,ba=function(){},ca=/\[native code\]/,x=function(a,b,c){return a[b]=a[b]||c},da=function(a){a=a.sort();for(var b=[],c=void 0,d=0;df}f&&c.push(e)}return c},Z=function(){var a=E.nonce;return void 0!==a?a&&a===String(a)&&a.match(X)?a:E.nonce=null:v.querySelector?(a=v.querySelector("script[nonce]"))?(a=a.nonce||a.getAttribute("nonce")||"",a&&a===String(a)&&a.match(X)?E.nonce=a:E.nonce=null):null:null},ua=function(a){if("loading"!=v.readyState)ta(a); +else{var b=Z(),c="";null!==b&&(c=' nonce="'+b+'"');v.write("<"+W+' src="'+encodeURI(a)+'"'+c+">")}},ta=function(a){var b=v.createElement(W);b.setAttribute("src",a);a=Z();null!==a&&b.setAttribute("nonce",a);b.async="true";(a=v.getElementsByTagName(W)[0])?a.parentNode.insertBefore(b,a):(v.head||v.body||v.documentElement).appendChild(b)},va=function(a,b){var c=b&&b._c;if(c)for(var d=0;d Date: Thu, 30 May 2019 19:24:37 +0530 Subject: [PATCH 04/41] Resolved minor errors --- Commands/GCCommands.ts | 11 +++++------ helpers/GCResult.ts | 2 +- helpers/GSGetter.ts | 26 +++++++++++++++++--------- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts index 5163b8a..7db34f6 100644 --- a/Commands/GCCommands.ts +++ b/Commands/GCCommands.ts @@ -1,7 +1,7 @@ import { IHttp, IModify, IPersistence, IRead } from '@rocket.chat/apps-engine/definition/accessors'; import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; import { GoogleCalendarApp } from '../GoogleCalendar'; -import { GCResults } from '../helpers/GCResult'; +import { GCGetter } from '../helpers/GSGetter'; export class GCCommand implements ISlashCommand { @@ -22,22 +22,21 @@ export class GCCommand implements ISlashCommand { // throw new Error('Method not implemented.'); - const cont= context.getArguments; + const cont= context.getArguments().join(' '); const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); try{ const loginstatus = await this.app.getGCGetter().login(cont,this.app.getLogger(), http); - + msg.setText('Successfully executed'); await modify.getCreator().finish(msg); }catch (e) { - this.app.getLogger().error('Failed getting a gif', e); - msg.setText('An error occurred when trying to send the gif :disappointed_relieved:'); + this.app.getLogger().error('Failed getting a response', e); + msg.setText('An error occurred when trying to send the request:disappointed_relieved:'); modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); } - } } \ No newline at end of file diff --git a/helpers/GCResult.ts b/helpers/GCResult.ts index dd4af7b..3cf9841 100644 --- a/helpers/GCResult.ts +++ b/helpers/GCResult.ts @@ -11,7 +11,7 @@ export class GCResults { } } - public result(): Promise { + public result(): string { if (!this.atoken) { throw new Error('Invalid result'); } diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index 7e693f2..cdcd5af 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -1,6 +1,8 @@ -import { HttpStatusCode, IHttp, ILogger, IRead } from '@rocket.chat/apps-engine/definition/accessors'; +import { HttpStatusCode, IHttp, ILogger, IRead, IHttpResponse } from '@rocket.chat/apps-engine/definition/accessors'; import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; import { GCResults } from '../helpers/GCResult'; +import { GoogleCalendarApp } from '../GoogleCalendar'; +import { SettingType } from '@rocket.chat/apps-engine/definition/settings'; export class GCGetter { private readonly Client_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; @@ -9,34 +11,40 @@ export class GCGetter { private readonly SCOPES = "https://www.googleapis.com/auth/calendar.readonly"; private readonly urli = 'https://accounts.google.com/o/oauth2/v2/auth?'; private readonly secret = '-lYglmNGqFNNazKoQX1m-EC9'; + private res; + private readonly app: GoogleCalendarApp; public async login(phase: string, logger: ILogger, http: IHttp): Promise { let signedin: boolean = false; - + const parame = phase; if (parame == 'auth') { //step1,2,3 - const response = await http.get(`${this.urli}client_id='${this.Client_id}'&redirect_uri=http://localhost:3000/general&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&response_type=code`); + const response = await http.get(`${this.urli}client_id='${this.Client_id}'&redirect_uri=http://localhost:3000&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&response_type=code`); + // this.app.('The auth code we got is: ${this.response}'); //step4 if (response.statusCode !== HttpStatusCode.OK || !response.data) { logger.debug('Did not get a valid response', response); - throw new Error('Unable to retrieve gifs.'); + throw new Error('Unable to retrieve response with auth code.'); } //response = https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7 //need to create regex such that res=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7 - const res = new RegExp['']; - - const newresponse = await http.get(`https://www.googleapis.com/oauth2/v4/token/code='${this.res}'&client_id='${this.Client_id}'&client_secret='${this.secret}'&redirect_uri=http://localhost:3000/general&grant_type=authorization_code`); + const newr = response.url.split('code=',2); + const arry = newr[1]; + const cd = arry.split('&',2); + this.res=cd[0]; + logger.debug('The auth code we got is: ${this.res}'); + const newresponse = await http.post(`https://www.googleapis.com/oauth2/v4/token/code='${this.res}'&client_id='${this.Client_id}'&client_secret='${this.secret}'&redirect_uri=http://localhost:3000/general&grant_type=authorization_code`); - const acesstoken = new GCResults(newresponse); + const acesstoken = new GCResults(newresponse.data); - if (accesstoken) { + if (acesstoken) { signedin = true; } From 3f7f3e4f4f762ba9eb03ead2b3ffd1a9e0c2b310 Mon Sep 17 00:00:00 2001 From: Kapil Date: Thu, 30 May 2019 19:59:02 +0530 Subject: [PATCH 05/41] Improved url --- helpers/GSGetter.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index cdcd5af..cffb13e 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -23,23 +23,25 @@ export class GCGetter { if (parame == 'auth') { //step1,2,3 - const response = await http.get(`${this.urli}client_id='${this.Client_id}'&redirect_uri=http://localhost:3000&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&response_type=code`); + const response = await http.get(`${this.urli}client_id=${this.Client_id}&redirect_uri=http://localhost:3000/home&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&response_type=code`); // this.app.('The auth code we got is: ${this.response}'); //step4 - if (response.statusCode !== HttpStatusCode.OK || !response.data) { - logger.debug('Did not get a valid response', response); - throw new Error('Unable to retrieve response with auth code.'); - } - + logger.debug('response from first request is:',response); + //response = https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7 //need to create regex such that res=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7 const newr = response.url.split('code=',2); const arry = newr[1]; const cd = arry.split('&',2); this.res=cd[0]; - logger.debug('The auth code we got is: ${this.res}'); - const newresponse = await http.post(`https://www.googleapis.com/oauth2/v4/token/code='${this.res}'&client_id='${this.Client_id}'&client_secret='${this.secret}'&redirect_uri=http://localhost:3000/general&grant_type=authorization_code`); + // logger.debug('The auth code we got is: ${this.res}'); + const newresponse = await http.post(`https://www.googleapis.com/oauth2/v4/token/code=${this.res}&client_id=${this.Client_id}&client_secret=${this.secret}&redirect_uri=http://localhost:3000/general&grant_type=authorization_code`); + + if (newresponse.statusCode !== HttpStatusCode.OK || !newresponse.data) { + logger.debug('Did not get a valid response', newresponse); + throw new Error('Unable to retrieve response with auth code.'); + } const acesstoken = new GCResults(newresponse.data); From 43f6f855c7e99bda12b4a4c7c3a2cc80f7d8ad7d Mon Sep 17 00:00:00 2001 From: Kapil Date: Thu, 30 May 2019 21:11:37 +0530 Subject: [PATCH 06/41] Changed response_type --- helpers/GSGetter.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index cffb13e..e4c9865 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -35,7 +35,8 @@ export class GCGetter { const arry = newr[1]; const cd = arry.split('&',2); this.res=cd[0]; - // logger.debug('The auth code we got is: ${this.res}'); + + logger.debug('The auth code we got is:',this.res); const newresponse = await http.post(`https://www.googleapis.com/oauth2/v4/token/code=${this.res}&client_id=${this.Client_id}&client_secret=${this.secret}&redirect_uri=http://localhost:3000/general&grant_type=authorization_code`); if (newresponse.statusCode !== HttpStatusCode.OK || !newresponse.data) { From 2aaecca78caebe7b968cfa5e6d109ca02dd8fc13 Mon Sep 17 00:00:00 2001 From: Kapil Date: Fri, 31 May 2019 02:28:14 +0530 Subject: [PATCH 07/41] Added the auth link as the message --- Commands/GCCommands.ts | 4 ++-- helpers/GSGetter.ts | 25 ++++++++++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts index 7db34f6..5b4c306 100644 --- a/Commands/GCCommands.ts +++ b/Commands/GCCommands.ts @@ -28,8 +28,8 @@ export class GCCommand implements ISlashCommand { try{ - const loginstatus = await this.app.getGCGetter().login(cont,this.app.getLogger(), http); - msg.setText('Successfully executed'); + const loginstatus = await this.app.getGCGetter().login(cont,this.app.getLogger(), http,modify,context); + // msg.setText('Successfully executed'); await modify.getCreator().finish(msg); }catch (e) { this.app.getLogger().error('Failed getting a response', e); diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index e4c9865..1749c13 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -1,4 +1,4 @@ -import { HttpStatusCode, IHttp, ILogger, IRead, IHttpResponse } from '@rocket.chat/apps-engine/definition/accessors'; +import { HttpStatusCode, IHttp, ILogger, IRead, IHttpResponse, IModify } from '@rocket.chat/apps-engine/definition/accessors'; import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; import { GCResults } from '../helpers/GCResult'; import { GoogleCalendarApp } from '../GoogleCalendar'; @@ -14,7 +14,7 @@ export class GCGetter { private res; private readonly app: GoogleCalendarApp; - public async login(phase: string, logger: ILogger, http: IHttp): Promise { + public async login(phase: string, logger: ILogger, http: IHttp, modify:IModify, context:SlashCommandContext): Promise { let signedin: boolean = false; @@ -23,15 +23,30 @@ export class GCGetter { if (parame == 'auth') { //step1,2,3 - const response = await http.get(`${this.urli}client_id=${this.Client_id}&redirect_uri=http://localhost:3000/home&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&response_type=code`); + const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); + const response = (`${this.urli}client_id=${this.Client_id}&redirect_uri=http://localhost:3000/home&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&response_type=code`); + + try{ + + //const loginstatus = await this.app.getGCGetter().login(cont,this.app.getLogger(), http,modify,context); + msg.setText('Please click the link below and authenticate!'); + msg.setText(response); + await modify.getCreator().finish(msg); + }catch (e) { + this.app.getLogger().error('Failed sending login url', e); + msg.setText('An error occurred when trying to send the request:disappointed_relieved:'); + + modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); + } + // this.app.('The auth code we got is: ${this.response}'); //step4 logger.debug('response from first request is:',response); - + //response = https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7 //need to create regex such that res=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7 - const newr = response.url.split('code=',2); + const newr = response.split('code=',2); const arry = newr[1]; const cd = arry.split('&',2); this.res=cd[0]; From 86cf4712f409e1f3d2a769f047dc819c86566c3f Mon Sep 17 00:00:00 2001 From: Kapil Date: Tue, 4 Jun 2019 18:49:25 +0530 Subject: [PATCH 08/41] Webhook Endpoint --- Commands/GCCommands.ts | 24 +++++++---------------- GoogleCalendar.ts | 18 +++++++++++++++++- helpers/GSGetter.ts | 42 ++++++++++------------------------------- helpers/Webhook.ts | 43 ++++++++++++++++++++++++++++++++++++++++++ library.js | 12 ------------ 5 files changed, 77 insertions(+), 62 deletions(-) create mode 100644 helpers/Webhook.ts delete mode 100644 library.js diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts index 5b4c306..7cd40c3 100644 --- a/Commands/GCCommands.ts +++ b/Commands/GCCommands.ts @@ -2,6 +2,8 @@ import { IHttp, IModify, IPersistence, IRead } from '@rocket.chat/apps-engine/de import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; import { GoogleCalendarApp } from '../GoogleCalendar'; import { GCGetter } from '../helpers/GSGetter'; +import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from '@rocket.chat/apps-engine/definition/api'; + export class GCCommand implements ISlashCommand { @@ -14,29 +16,17 @@ export class GCCommand implements ISlashCommand { constructor(private readonly app: GoogleCalendarApp) { } public async executor(context: SlashCommandContext, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise { - // if there are no args or args[0] === 'random' - // then get a single one - - // otherwise, fetch the results and get a random one - // as the max amount returned will be ten - // throw new Error('Method not implemented.'); - - + const cont= context.getArguments().join(' '); const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - try{ + // try{ const loginstatus = await this.app.getGCGetter().login(cont,this.app.getLogger(), http,modify,context); - // msg.setText('Successfully executed'); - await modify.getCreator().finish(msg); - }catch (e) { - this.app.getLogger().error('Failed getting a response', e); - msg.setText('An error occurred when trying to send the request:disappointed_relieved:'); + // msg.setText('Successfully executed') - modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); - } - } + //} + } } \ No newline at end of file diff --git a/GoogleCalendar.ts b/GoogleCalendar.ts index 0e13197..a002e61 100644 --- a/GoogleCalendar.ts +++ b/GoogleCalendar.ts @@ -1,30 +1,41 @@ import { + IAppAccessors, IConfigurationExtend, IEnvironmentRead, - IAppAccessors, ILogger, } from '@rocket.chat/apps-engine/definition/accessors'; +import { ApiSecurity, ApiVisibility } from '@rocket.chat/apps-engine/definition/api'; import { App } from '@rocket.chat/apps-engine/definition/App'; import { IAppInfo } from '@rocket.chat/apps-engine/definition/metadata'; import { SettingType } from '@rocket.chat/apps-engine/definition/settings'; import { GCCommand } from './Commands/GCCommands'; import { GCGetter } from './helpers/GSGetter'; +import { WebhookEndpoint } from './helpers/Webhook'; export class GoogleCalendarApp extends App { private gcGetter: GCGetter; + private webhook : WebhookEndpoint; constructor(info: IAppInfo, logger: ILogger, accessors: IAppAccessors) { super(info, logger, accessors); this.gcGetter = new GCGetter(); + this.webhook= new WebhookEndpoint(this); + + } + public getwebhook(): WebhookEndpoint { + return this.webhook; } public getGCGetter(): GCGetter { return this.gcGetter; } + + + protected async extendConfiguration(configuration: IConfigurationExtend, environmentRead: IEnvironmentRead): Promise { await configuration.settings.provideSetting({ id: 'calendar_apikey', @@ -55,6 +66,11 @@ export class GoogleCalendarApp extends App { i18nLabel: 'Customize_Calendar_SecretKey', i18nDescription: 'Customize_Calendar_SecretKey', }); + configuration.api.provideApi({ + visibility: ApiVisibility.PRIVATE, + security: ApiSecurity.UNSECURE, + endpoints: [new WebhookEndpoint(this)], + }); await configuration.slashCommands.provideSlashCommand(new GCCommand(this)); diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index 1749c13..dc99091 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -2,7 +2,10 @@ import { HttpStatusCode, IHttp, ILogger, IRead, IHttpResponse, IModify } from '@ import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; import { GCResults } from '../helpers/GCResult'; import { GoogleCalendarApp } from '../GoogleCalendar'; +import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from '@rocket.chat/apps-engine/definition/api'; import { SettingType } from '@rocket.chat/apps-engine/definition/settings'; +import { WebhookEndpoint } from '../helpers/Webhook'; +import { request } from 'http'; export class GCGetter { private readonly Client_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; @@ -14,7 +17,8 @@ export class GCGetter { private res; private readonly app: GoogleCalendarApp; - public async login(phase: string, logger: ILogger, http: IHttp, modify:IModify, context:SlashCommandContext): Promise { + + public async login(phase: string, logger: ILogger, http: IHttp, modify:IModify, context:SlashCommandContext, req:IApiRequest, end:IApiEndpointInfo): Promise { let signedin: boolean = false; @@ -22,40 +26,14 @@ export class GCGetter { if (parame == 'auth') { //step1,2,3 + const auth_code = await this.app.getwebhook().stepone(req,end,this.app.getLogger(), http,modify,context); - const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - const response = (`${this.urli}client_id=${this.Client_id}&redirect_uri=http://localhost:3000/home&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&response_type=code`); - - try{ - - //const loginstatus = await this.app.getGCGetter().login(cont,this.app.getLogger(), http,modify,context); - msg.setText('Please click the link below and authenticate!'); - msg.setText(response); - await modify.getCreator().finish(msg); - }catch (e) { - this.app.getLogger().error('Failed sending login url', e); - msg.setText('An error occurred when trying to send the request:disappointed_relieved:'); - - modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); - } - - // this.app.('The auth code we got is: ${this.response}'); - - //step4 - logger.debug('response from first request is:',response); - - //response = https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7 - //need to create regex such that res=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7 - const newr = response.split('code=',2); - const arry = newr[1]; - const cd = arry.split('&',2); - this.res=cd[0]; - - logger.debug('The auth code we got is:',this.res); - const newresponse = await http.post(`https://www.googleapis.com/oauth2/v4/token/code=${this.res}&client_id=${this.Client_id}&client_secret=${this.secret}&redirect_uri=http://localhost:3000/general&grant_type=authorization_code`); + + + const newresponse = await http.post(`https://www.googleapis.com/oauth2/v4/token/code=${auth_code}&client_id=${this.Client_id}&client_secret=${this.secret}&redirect_uri=http://localhost:3000/general&grant_type=authorization_code`); if (newresponse.statusCode !== HttpStatusCode.OK || !newresponse.data) { - logger.debug('Did not get a valid response', newresponse); + logger.debug('Did not get a valid response', newresponse); throw new Error('Unable to retrieve response with auth code.'); } diff --git a/helpers/Webhook.ts b/helpers/Webhook.ts new file mode 100644 index 0000000..1826bae --- /dev/null +++ b/helpers/Webhook.ts @@ -0,0 +1,43 @@ + +import { IHttp,ILogger, IModify, IPersistence, IRead } from '@rocket.chat/apps-engine/definition/accessors'; +import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from '@rocket.chat/apps-engine/definition/api'; +//import { AppPersistence } from '../lib/persistence'; +import { GCGetter } from './GSGetter'; +import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; +import { request } from 'http'; + + +export class WebhookEndpoint extends ApiEndpoint { + public path = 'webhook'; + private readonly Client_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; + private readonly urli = 'https://accounts.google.com/o/oauth2/v2/auth?'; + + + public async stepone(request:IApiRequest,endpoint:IApiEndpointInfo,logger: ILogger, http: IHttp, modify:IModify, context:SlashCommandContext): Promise { + + + let token=true; + const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); + const response = (`${this.urli}client_id=${this.Client_id}&redirect_uri=http://localhost:3000/api/apps/public/3c3ed60d-774b-4d1c-a547-6fc42a5a87c6/webhook&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&response_type=code`); + + try{ + msg.setText(response); + await modify.getCreator().finish(msg); + }catch (e) { + this.app.getLogger().error('Failed sending login url', e); + msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); + + modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); + } + logger.debug('response from first request is:',request.params); + + const auth_code= request.params.code; + + + //const auth_token= request.code; + + return auth_code; + + } + +} \ No newline at end of file diff --git a/library.js b/library.js deleted file mode 100644 index 3f02805..0000000 --- a/library.js +++ /dev/null @@ -1,12 +0,0 @@ -var gapi=window.gapi=window.gapi||{};gapi._bs=new Date().getTime();(function(){var g=function(){this.g=""};g.prototype.toString=function(){return"SafeScript{"+this.g+"}"};g.prototype.a=function(a){this.g=a};(new g).a("");var h=function(){this.j=""};h.prototype.toString=function(){return"SafeStyle{"+this.j+"}"};h.prototype.a=function(a){this.j=a};(new h).a("");var m=function(){this.i=""};m.prototype.toString=function(){return"SafeStyleSheet{"+this.i+"}"};m.prototype.a=function(a){this.i=a};(new m).a("");var n=function(){this.f=""};n.prototype.toString=function(){return"SafeHtml{"+this.f+"}"};n.prototype.a=function(a){this.f=a};(new n).a("");(new n).a("");(new n).a("
");/* - gapi.loader.OBJECT_CREATE_TEST_OVERRIDE &&*/ -var q=window,v=document,aa=q.location,ba=function(){},ca=/\[native code\]/,x=function(a,b,c){return a[b]=a[b]||c},da=function(a){a=a.sort();for(var b=[],c=void 0,d=0;df}f&&c.push(e)}return c},Z=function(){var a=E.nonce;return void 0!==a?a&&a===String(a)&&a.match(X)?a:E.nonce=null:v.querySelector?(a=v.querySelector("script[nonce]"))?(a=a.nonce||a.getAttribute("nonce")||"",a&&a===String(a)&&a.match(X)?E.nonce=a:E.nonce=null):null:null},ua=function(a){if("loading"!=v.readyState)ta(a); -else{var b=Z(),c="";null!==b&&(c=' nonce="'+b+'"');v.write("<"+W+' src="'+encodeURI(a)+'"'+c+">")}},ta=function(a){var b=v.createElement(W);b.setAttribute("src",a);a=Z();null!==a&&b.setAttribute("nonce",a);b.async="true";(a=v.getElementsByTagName(W)[0])?a.parentNode.insertBefore(b,a):(v.head||v.body||v.documentElement).appendChild(b)},va=function(a,b){var c=b&&b._c;if(c)for(var d=0;d Date: Wed, 5 Jun 2019 18:21:06 +0530 Subject: [PATCH 09/41] Changed workflow --- Commands/GCCommands.ts | 11 +++++++---- GoogleCalendar.ts | 25 ++++++++++++------------- app.json | 3 ++- helpers/GSGetter.ts | 32 ++++++++++++++------------------ helpers/Webhook.ts | 35 +++++++++++++++-------------------- 5 files changed, 50 insertions(+), 56 deletions(-) diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts index 7cd40c3..b82b2da 100644 --- a/Commands/GCCommands.ts +++ b/Commands/GCCommands.ts @@ -21,12 +21,15 @@ export class GCCommand implements ISlashCommand { const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - // try{ + try{ const loginstatus = await this.app.getGCGetter().login(cont,this.app.getLogger(), http,modify,context); - // msg.setText('Successfully executed') - - //} + msg.setText('Slashcommand executed'); + await modify.getCreator().finish(msg); + }catch (e) { + this.app.getLogger().error('Failed sending login url', e); + //msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); + } } } \ No newline at end of file diff --git a/GoogleCalendar.ts b/GoogleCalendar.ts index a002e61..ad0c074 100644 --- a/GoogleCalendar.ts +++ b/GoogleCalendar.ts @@ -17,19 +17,14 @@ import { WebhookEndpoint } from './helpers/Webhook'; export class GoogleCalendarApp extends App { private gcGetter: GCGetter; - private webhook : WebhookEndpoint; + // private webhook : WebhookEndpoint; constructor(info: IAppInfo, logger: ILogger, accessors: IAppAccessors) { super(info, logger, accessors); this.gcGetter = new GCGetter(); - this.webhook= new WebhookEndpoint(this); + //this.webhook= new WebhookEndpoint(this); } - - public getwebhook(): WebhookEndpoint { - return this.webhook; - } - public getGCGetter(): GCGetter { return this.gcGetter; } @@ -37,6 +32,15 @@ export class GoogleCalendarApp extends App { protected async extendConfiguration(configuration: IConfigurationExtend, environmentRead: IEnvironmentRead): Promise { + + await configuration.api.provideApi({ + visibility: ApiVisibility.PRIVATE, + security: ApiSecurity.UNSECURE, + endpoints: [new WebhookEndpoint(this)], + + }); + + await configuration.settings.provideSetting({ id: 'calendar_apikey', type: SettingType.STRING, @@ -66,12 +70,7 @@ export class GoogleCalendarApp extends App { i18nLabel: 'Customize_Calendar_SecretKey', i18nDescription: 'Customize_Calendar_SecretKey', }); - configuration.api.provideApi({ - visibility: ApiVisibility.PRIVATE, - security: ApiSecurity.UNSECURE, - endpoints: [new WebhookEndpoint(this)], - }); - + await configuration.slashCommands.provideSlashCommand(new GCCommand(this)); } diff --git a/app.json b/app.json index 4b328fe..4a001a2 100644 --- a/app.json +++ b/app.json @@ -11,5 +11,6 @@ "name": "Google Calendar", "nameSlug": "google-calendar", "classFile": "GoogleCalendar.ts", - "description": "Use app to manage your calendar events" + "description": "Use app to manage your calendar events", + } \ No newline at end of file diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index dc99091..c5cfbb8 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -18,7 +18,7 @@ export class GCGetter { private readonly app: GoogleCalendarApp; - public async login(phase: string, logger: ILogger, http: IHttp, modify:IModify, context:SlashCommandContext, req:IApiRequest, end:IApiEndpointInfo): Promise { + public async login(phase: string, logger: ILogger, http: IHttp, modify:IModify, context:SlashCommandContext): Promise { let signedin: boolean = false; @@ -26,23 +26,19 @@ export class GCGetter { if (parame == 'auth') { //step1,2,3 - const auth_code = await this.app.getwebhook().stepone(req,end,this.app.getLogger(), http,modify,context); - - - - const newresponse = await http.post(`https://www.googleapis.com/oauth2/v4/token/code=${auth_code}&client_id=${this.Client_id}&client_secret=${this.secret}&redirect_uri=http://localhost:3000/general&grant_type=authorization_code`); - - if (newresponse.statusCode !== HttpStatusCode.OK || !newresponse.data) { - logger.debug('Did not get a valid response', newresponse); - throw new Error('Unable to retrieve response with auth code.'); - } - - - const acesstoken = new GCResults(newresponse.data); - - if (acesstoken) { - signedin = true; - } + // const auth_code = await this.app.getwebhook().stepone(req,end,this.app.getLogger(), http,modify,context); + const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); + const response = (`${this.urli}client_id=${this.Client_id}&redirect_uri=http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&response_type=code`); + + try{ + msg.setText(response); + await modify.getCreator().finish(msg); + }catch (e) { + this.app.getLogger().error('Failed sending login url', e); + msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); + + modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); + } } diff --git a/helpers/Webhook.ts b/helpers/Webhook.ts index 1826bae..6796070 100644 --- a/helpers/Webhook.ts +++ b/helpers/Webhook.ts @@ -1,43 +1,38 @@ -import { IHttp,ILogger, IModify, IPersistence, IRead } from '@rocket.chat/apps-engine/definition/accessors'; +import { HttpStatusCode,IHttp,ILogger, IModify, IPersistence, IRead } from '@rocket.chat/apps-engine/definition/accessors'; import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from '@rocket.chat/apps-engine/definition/api'; //import { AppPersistence } from '../lib/persistence'; import { GCGetter } from './GSGetter'; import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; import { request } from 'http'; +import { GCResults } from '../helpers/GCResult'; export class WebhookEndpoint extends ApiEndpoint { public path = 'webhook'; private readonly Client_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; private readonly urli = 'https://accounts.google.com/o/oauth2/v2/auth?'; + private readonly secret = '-lYglmNGqFNNazKoQX1m-EC9'; - public async stepone(request:IApiRequest,endpoint:IApiEndpointInfo,logger: ILogger, http: IHttp, modify:IModify, context:SlashCommandContext): Promise { - - - let token=true; - const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - const response = (`${this.urli}client_id=${this.Client_id}&redirect_uri=http://localhost:3000/api/apps/public/3c3ed60d-774b-4d1c-a547-6fc42a5a87c6/webhook&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&response_type=code`); - - try{ - msg.setText(response); - await modify.getCreator().finish(msg); - }catch (e) { - this.app.getLogger().error('Failed sending login url', e); - msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); - - modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); - } + public async stepone(request:IApiRequest, endpoint:IApiEndpointInfo,logger: ILogger, http: IHttp, modify:IModify, context:SlashCommandContext): Promise { + logger.debug('response from first request is:',request.params); const auth_code= request.params.code; + const newresponse = await http.post(`https://www.googleapis.com/oauth2/v4/token/code=${auth_code}&client_id=${this.Client_id}&client_secret=${this.secret}&redirect_uri=http://localhost:3000/general&grant_type=authorization_code`); + + if (newresponse.statusCode !== HttpStatusCode.OK || !newresponse.data) { + logger.debug('Did not get a valid response', newresponse); + throw new Error('Unable to retrieve response with auth code.'); + } - //const auth_token= request.code; - - return auth_code; + const acesstoken = new GCResults(newresponse.data); + logger.debug('Auth token received is: ',auth_code); + return this.success(); + //return auth_cod } } \ No newline at end of file From 29a9bf13d23a7c2a210b7076b96ce4d958dd2fff Mon Sep 17 00:00:00 2001 From: Kapil Date: Wed, 5 Jun 2019 18:24:44 +0530 Subject: [PATCH 10/41] Corrected typo --- app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.json b/app.json index 4a001a2..8367bf9 100644 --- a/app.json +++ b/app.json @@ -11,6 +11,6 @@ "name": "Google Calendar", "nameSlug": "google-calendar", "classFile": "GoogleCalendar.ts", - "description": "Use app to manage your calendar events", + "description": "Use app to manage your calendar events" } \ No newline at end of file From e824d9236ae45fad3b373a62d2ec9d6d9b360e34 Mon Sep 17 00:00:00 2001 From: Kapil Date: Wed, 5 Jun 2019 19:18:21 +0530 Subject: [PATCH 11/41] Add token id to app persistence --- GoogleCalendar.ts | 2 +- helpers/GSGetter.ts | 1 - helpers/Webhook.ts | 5 +++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/GoogleCalendar.ts b/GoogleCalendar.ts index ad0c074..591c938 100644 --- a/GoogleCalendar.ts +++ b/GoogleCalendar.ts @@ -34,7 +34,7 @@ export class GoogleCalendarApp extends App { protected async extendConfiguration(configuration: IConfigurationExtend, environmentRead: IEnvironmentRead): Promise { await configuration.api.provideApi({ - visibility: ApiVisibility.PRIVATE, + visibility: ApiVisibility.PUBLIC, security: ApiSecurity.UNSECURE, endpoints: [new WebhookEndpoint(this)], diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index c5cfbb8..c0d4da7 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -40,7 +40,6 @@ export class GCGetter { modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); } - } if (parame == 'logout') { diff --git a/helpers/Webhook.ts b/helpers/Webhook.ts index 6796070..c869106 100644 --- a/helpers/Webhook.ts +++ b/helpers/Webhook.ts @@ -13,9 +13,9 @@ export class WebhookEndpoint extends ApiEndpoint { private readonly Client_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; private readonly urli = 'https://accounts.google.com/o/oauth2/v2/auth?'; private readonly secret = '-lYglmNGqFNNazKoQX1m-EC9'; + public tokenid; - - public async stepone(request:IApiRequest, endpoint:IApiEndpointInfo,logger: ILogger, http: IHttp, modify:IModify, context:SlashCommandContext): Promise { + public async stepone(request:IApiRequest, persist:IPersistence,logger: ILogger, http: IHttp, modify:IModify, context:SlashCommandContext): Promise { logger.debug('response from first request is:',request.params); @@ -30,6 +30,7 @@ export class WebhookEndpoint extends ApiEndpoint { const acesstoken = new GCResults(newresponse.data); logger.debug('Auth token received is: ',auth_code); + this.tokenid= persist.create(acesstoken); return this.success(); //return auth_cod From f49b6b59d7400ea7ae711462e4124c0297766771 Mon Sep 17 00:00:00 2001 From: Kapil Date: Wed, 5 Jun 2019 23:17:27 +0530 Subject: [PATCH 12/41] Updated files --- Commands/GCCommands.ts | 44 +++++++++++++++++++++--------------------- GoogleCalendar.ts | 10 +++++----- helpers/GSGetter.ts | 36 +++++++++++++++++----------------- helpers/Webhook.ts | 37 +++++++++++++++++------------------ 4 files changed, 63 insertions(+), 64 deletions(-) diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts index b82b2da..3a1d0f7 100644 --- a/Commands/GCCommands.ts +++ b/Commands/GCCommands.ts @@ -8,28 +8,28 @@ import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from '@rocke export class GCCommand implements ISlashCommand { - public command = 'calendar'; - public i18nParamsExample = 'Calendar_login'; - public i18nDescription = 'Calendar_Command_Description'; - public providesPreview = false; - - constructor(private readonly app: GoogleCalendarApp) { } - - public async executor(context: SlashCommandContext, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise { - - const cont= context.getArguments().join(' '); - - const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - - try{ - - const loginstatus = await this.app.getGCGetter().login(cont,this.app.getLogger(), http,modify,context); - msg.setText('Slashcommand executed'); - await modify.getCreator().finish(msg); - }catch (e) { - this.app.getLogger().error('Failed sending login url', e); - //msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); - } + public command = 'calendar'; + public i18nParamsExample = 'Calendar_login'; + public i18nDescription = 'Calendar_Command_Description'; + public providesPreview = false; + constructor(private readonly app: GoogleCalendarApp) { } + + public async executor(context: SlashCommandContext, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise { + + const cont = context.getArguments().join(' '); + + const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); + + try { + + const loginstatus = await this.app.getGCGetter().login(cont, this.app.getLogger(), http, modify, context); + msg.setText('Slashcommand executed'); + await modify.getCreator().finish(msg); + } catch (e) { + this.app.getLogger().error('Failed sending login url', e); + //msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); } + + } } \ No newline at end of file diff --git a/GoogleCalendar.ts b/GoogleCalendar.ts index 591c938..e2f85bf 100644 --- a/GoogleCalendar.ts +++ b/GoogleCalendar.ts @@ -17,7 +17,7 @@ import { WebhookEndpoint } from './helpers/Webhook'; export class GoogleCalendarApp extends App { private gcGetter: GCGetter; - // private webhook : WebhookEndpoint; + // private webhook : WebhookEndpoint; constructor(info: IAppInfo, logger: ILogger, accessors: IAppAccessors) { super(info, logger, accessors); @@ -29,10 +29,10 @@ export class GoogleCalendarApp extends App { return this.gcGetter; } - + protected async extendConfiguration(configuration: IConfigurationExtend, environmentRead: IEnvironmentRead): Promise { - + await configuration.api.provideApi({ visibility: ApiVisibility.PUBLIC, security: ApiSecurity.UNSECURE, @@ -40,7 +40,7 @@ export class GoogleCalendarApp extends App { }); - + await configuration.settings.provideSetting({ id: 'calendar_apikey', type: SettingType.STRING, @@ -70,7 +70,7 @@ export class GoogleCalendarApp extends App { i18nLabel: 'Customize_Calendar_SecretKey', i18nDescription: 'Customize_Calendar_SecretKey', }); - + await configuration.slashCommands.provideSlashCommand(new GCCommand(this)); } diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index c0d4da7..5445c1f 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -5,7 +5,7 @@ import { GoogleCalendarApp } from '../GoogleCalendar'; import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from '@rocket.chat/apps-engine/definition/api'; import { SettingType } from '@rocket.chat/apps-engine/definition/settings'; import { WebhookEndpoint } from '../helpers/Webhook'; -import { request } from 'http'; + export class GCGetter { private readonly Client_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; @@ -14,32 +14,32 @@ export class GCGetter { private readonly SCOPES = "https://www.googleapis.com/auth/calendar.readonly"; private readonly urli = 'https://accounts.google.com/o/oauth2/v2/auth?'; private readonly secret = '-lYglmNGqFNNazKoQX1m-EC9'; - private res; + private res; private readonly app: GoogleCalendarApp; - public async login(phase: string, logger: ILogger, http: IHttp, modify:IModify, context:SlashCommandContext): Promise { + public async login(phase: string, logger: ILogger, http: IHttp, modify: IModify, context: SlashCommandContext): Promise { let signedin: boolean = false; - + const parame = phase; if (parame == 'auth') { //step1,2,3 - // const auth_code = await this.app.getwebhook().stepone(req,end,this.app.getLogger(), http,modify,context); - const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - const response = (`${this.urli}client_id=${this.Client_id}&redirect_uri=http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&response_type=code`); - - try{ - msg.setText(response); - await modify.getCreator().finish(msg); - }catch (e) { - this.app.getLogger().error('Failed sending login url', e); - msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); - - modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); - } - + // const auth_code = await this.app.getwebhook().stepone(req,end,this.app.getLogger(), http,modify,context); + const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); + const response = (`${this.urli}client_id=${this.Client_id}&redirect_uri=http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&response_type=code`); + + try { + msg.setText(response); + await modify.getCreator().finish(msg); + } catch (e) { + this.app.getLogger().error('Failed sending login url', e); + msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); + + modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); + } + return signedin = true; } if (parame == 'logout') { diff --git a/helpers/Webhook.ts b/helpers/Webhook.ts index c869106..f38b154 100644 --- a/helpers/Webhook.ts +++ b/helpers/Webhook.ts @@ -1,10 +1,9 @@ -import { HttpStatusCode,IHttp,ILogger, IModify, IPersistence, IRead } from '@rocket.chat/apps-engine/definition/accessors'; +import { HttpStatusCode, IHttp, ILogger, IModify, IPersistence, IRead } from '@rocket.chat/apps-engine/definition/accessors'; import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from '@rocket.chat/apps-engine/definition/api'; //import { AppPersistence } from '../lib/persistence'; import { GCGetter } from './GSGetter'; import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; -import { request } from 'http'; import { GCResults } from '../helpers/GCResult'; @@ -13,27 +12,27 @@ export class WebhookEndpoint extends ApiEndpoint { private readonly Client_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; private readonly urli = 'https://accounts.google.com/o/oauth2/v2/auth?'; private readonly secret = '-lYglmNGqFNNazKoQX1m-EC9'; - public tokenid; + public tokenid; - public async stepone(request:IApiRequest, persist:IPersistence,logger: ILogger, http: IHttp, modify:IModify, context:SlashCommandContext): Promise { - - logger.debug('response from first request is:',request.params); + public async stepone(request: IApiRequest, persist: IPersistence, logger: ILogger, http: IHttp, modify: IModify, context: SlashCommandContext): Promise { - const auth_code= request.params.code; - const newresponse = await http.post(`https://www.googleapis.com/oauth2/v4/token/code=${auth_code}&client_id=${this.Client_id}&client_secret=${this.secret}&redirect_uri=http://localhost:3000/general&grant_type=authorization_code`); - - if (newresponse.statusCode !== HttpStatusCode.OK || !newresponse.data) { - logger.debug('Did not get a valid response', newresponse); - throw new Error('Unable to retrieve response with auth code.'); - } + logger.debug('response from first request is:', request.params); + const auth_code = request.params.code; + const newresponse = await http.post(`https://www.googleapis.com/oauth2/v4/token/code=${auth_code}&client_id=${this.Client_id}&client_secret=${this.secret}&redirect_uri=http://localhost:3000/general&grant_type=authorization_code`); - const acesstoken = new GCResults(newresponse.data); - logger.debug('Auth token received is: ',auth_code); - this.tokenid= persist.create(acesstoken); - return this.success(); + if (newresponse.statusCode !== HttpStatusCode.OK || !newresponse.data) { + logger.debug('Did not get a valid response', newresponse); + throw new Error('Unable to retrieve response with auth code.'); + } - //return auth_cod - } + + const acesstoken = new GCResults(newresponse.data); + logger.debug('Auth token received is: ', auth_code); + this.tokenid = persist.create(acesstoken); + return this.success(); + + //return auth_cod + } } \ No newline at end of file From c1e3a6f97bfeb9c7e8c21bf424bcb42dc4612b71 Mon Sep 17 00:00:00 2001 From: Kapil Date: Wed, 5 Jun 2019 23:54:35 +0530 Subject: [PATCH 13/41] Changed Webhook method --- helpers/Webhook.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/Webhook.ts b/helpers/Webhook.ts index f38b154..5f06770 100644 --- a/helpers/Webhook.ts +++ b/helpers/Webhook.ts @@ -14,7 +14,7 @@ export class WebhookEndpoint extends ApiEndpoint { private readonly secret = '-lYglmNGqFNNazKoQX1m-EC9'; public tokenid; - public async stepone(request: IApiRequest, persist: IPersistence, logger: ILogger, http: IHttp, modify: IModify, context: SlashCommandContext): Promise { + public async post(request: IApiRequest, persist: IPersistence, logger: ILogger, http: IHttp, modify: IModify, context: SlashCommandContext): Promise { logger.debug('response from first request is:', request.params); From 120332208d6cce69bc8648bad82ea9696a7e7fc7 Mon Sep 17 00:00:00 2001 From: Kapil Date: Thu, 6 Jun 2019 03:31:43 +0530 Subject: [PATCH 14/41] Updated api call --- helpers/Webhook.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/helpers/Webhook.ts b/helpers/Webhook.ts index 5f06770..4361534 100644 --- a/helpers/Webhook.ts +++ b/helpers/Webhook.ts @@ -14,21 +14,22 @@ export class WebhookEndpoint extends ApiEndpoint { private readonly secret = '-lYglmNGqFNNazKoQX1m-EC9'; public tokenid; - public async post(request: IApiRequest, persist: IPersistence, logger: ILogger, http: IHttp, modify: IModify, context: SlashCommandContext): Promise { + public async get(request: IApiRequest,endpoint:IApiEndpointInfo, read:IRead, modify: IModify, http: IHttp,persist: IPersistence): Promise { - logger.debug('response from first request is:', request.params); + //logger.debug('response from first request is:', request.params);` - const auth_code = request.params.code; - const newresponse = await http.post(`https://www.googleapis.com/oauth2/v4/token/code=${auth_code}&client_id=${this.Client_id}&client_secret=${this.secret}&redirect_uri=http://localhost:3000/general&grant_type=authorization_code`); + const auth_code = request.query.code; + const url='https://www.googleapis.com/oauth2/v4/token'; + const newresponse = await http.post(url, { params: {'code':`${auth_code}`,'client_id':`${this.Client_id}`,'client_secret':`${this.secret}`,'redirect_uri':'http://localhost:3000/general','grant_type':'authorization_code',}}); if (newresponse.statusCode !== HttpStatusCode.OK || !newresponse.data) { - logger.debug('Did not get a valid response', newresponse); - throw new Error('Unable to retrieve response with auth code.'); + console.log('Did not get a valid response', newresponse); + throw new Error('Unable to retrieve response with auth code.'); } const acesstoken = new GCResults(newresponse.data); - logger.debug('Auth token received is: ', auth_code); + // logger.debug('Auth token received is: ', auth_code); this.tokenid = persist.create(acesstoken); return this.success(); From 981ddf0bb09d61e39b23e8da913b52bb612f798b Mon Sep 17 00:00:00 2001 From: Kapil Date: Thu, 6 Jun 2019 17:05:30 +0530 Subject: [PATCH 15/41] Access token received --- helpers/GSGetter.ts | 2 +- helpers/Webhook.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index 5445c1f..856fb4d 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -28,7 +28,7 @@ export class GCGetter { //step1,2,3 // const auth_code = await this.app.getwebhook().stepone(req,end,this.app.getLogger(), http,modify,context); const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - const response = (`${this.urli}client_id=${this.Client_id}&redirect_uri=http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&response_type=code`); + const response = (`${this.urli}client_id=${this.Client_id}&redirect_uri=http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&access_type=offline&response_type=code`); try { msg.setText(response); diff --git a/helpers/Webhook.ts b/helpers/Webhook.ts index 4361534..0da442d 100644 --- a/helpers/Webhook.ts +++ b/helpers/Webhook.ts @@ -10,7 +10,7 @@ import { GCResults } from '../helpers/GCResult'; export class WebhookEndpoint extends ApiEndpoint { public path = 'webhook'; private readonly Client_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; - private readonly urli = 'https://accounts.google.com/o/oauth2/v2/auth?'; + private readonly urli = 'http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook'; private readonly secret = '-lYglmNGqFNNazKoQX1m-EC9'; public tokenid; @@ -20,14 +20,14 @@ export class WebhookEndpoint extends ApiEndpoint { const auth_code = request.query.code; const url='https://www.googleapis.com/oauth2/v4/token'; - const newresponse = await http.post(url, { params: {'code':`${auth_code}`,'client_id':`${this.Client_id}`,'client_secret':`${this.secret}`,'redirect_uri':'http://localhost:3000/general','grant_type':'authorization_code',}}); + const newresponse = await http.post(url, { data: {'code':`${auth_code}`,'client_id':`${this.Client_id}`,'client_secret':`${this.secret}`,'redirect_uri':`${this.urli}`,'grant_type':'authorization_code',}}); if (newresponse.statusCode !== HttpStatusCode.OK || !newresponse.data) { console.log('Did not get a valid response', newresponse); throw new Error('Unable to retrieve response with auth code.'); } - + console.log('his is the response from post api',newresponse); const acesstoken = new GCResults(newresponse.data); // logger.debug('Auth token received is: ', auth_code); this.tokenid = persist.create(acesstoken); From 9a4a15630fc8401c41bee88df66baef15d35708f Mon Sep 17 00:00:00 2001 From: Kapil Date: Sat, 8 Jun 2019 00:04:11 +0530 Subject: [PATCH 16/41] Included user credentials, success login message --- Commands/GCCommands.ts | 2 +- helpers/GCResult.ts | 5 ++--- helpers/GSGetter.ts | 16 ++++++++++------ helpers/Webhook.ts | 31 ++++++++++++++++++++----------- i18n/en.json | 10 ++++++++++ 5 files changed, 43 insertions(+), 21 deletions(-) create mode 100644 i18n/en.json diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts index 3a1d0f7..e580435 100644 --- a/Commands/GCCommands.ts +++ b/Commands/GCCommands.ts @@ -23,7 +23,7 @@ export class GCCommand implements ISlashCommand { try { - const loginstatus = await this.app.getGCGetter().login(cont, this.app.getLogger(), http, modify, context); + const loginstatus = await this.app.getGCGetter().login(cont, this.app.getLogger(), read, http, modify, context); msg.setText('Slashcommand executed'); await modify.getCreator().finish(msg); } catch (e) { diff --git a/helpers/GCResult.ts b/helpers/GCResult.ts index 3cf9841..c1d882d 100644 --- a/helpers/GCResult.ts +++ b/helpers/GCResult.ts @@ -1,5 +1,6 @@ import { ISlashCommandPreviewItem, SlashCommandPreviewItemType } from '@rocket.chat/apps-engine/definition/slashcommands'; import { HttpStatusCode, IHttp, ILogger, IRead } from '@rocket.chat/apps-engine/definition/accessors'; +import { IApiRequest } from '@rocket.chat/apps-engine/definition/api'; export class GCResults { public atoken: string; @@ -15,9 +16,7 @@ export class GCResults { if (!this.atoken) { throw new Error('Invalid result'); } - else - return this.atoken; - + return this.atoken; } } \ No newline at end of file diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index 856fb4d..4b75839 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -8,17 +8,21 @@ import { WebhookEndpoint } from '../helpers/Webhook'; export class GCGetter { - private readonly Client_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; - private readonly api_key = 'AIzaSyAY1YAPK1lIcx1bgsLOgsRfNfAluVQhuq4'; - private readonly DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"]; + private readonly dClient_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; + private readonly dapi_key = 'AIzaSyAY1YAPK1lIcx1bgsLOgsRfNfAluVQhuq4'; private readonly SCOPES = "https://www.googleapis.com/auth/calendar.readonly"; private readonly urli = 'https://accounts.google.com/o/oauth2/v2/auth?'; - private readonly secret = '-lYglmNGqFNNazKoQX1m-EC9'; + private readonly dsecret = '-lYglmNGqFNNazKoQX1m-EC9'; private res; private readonly app: GoogleCalendarApp; - public async login(phase: string, logger: ILogger, http: IHttp, modify: IModify, context: SlashCommandContext): Promise { + + public async login(phase: string, logger: ILogger, read: IRead, http: IHttp, modify: IModify, context: SlashCommandContext): Promise { + + const Client_id = await read.getEnvironmentReader().getSettings().getValueById('calendar_clientid') || this.dClient_id; + const api_key = await read.getEnvironmentReader().getSettings().getValueById('calendar_apikey') || this.dapi_key; + const secret = await read.getEnvironmentReader().getSettings().getValueById('calendar_secret_key') || this.dsecret; let signedin: boolean = false; @@ -28,7 +32,7 @@ export class GCGetter { //step1,2,3 // const auth_code = await this.app.getwebhook().stepone(req,end,this.app.getLogger(), http,modify,context); const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - const response = (`${this.urli}client_id=${this.Client_id}&redirect_uri=http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&access_type=offline&response_type=code`); + const response = (`${this.urli}client_id=${Client_id}&redirect_uri=http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&access_type=offline&response_type=code`); try { msg.setText(response); diff --git a/helpers/Webhook.ts b/helpers/Webhook.ts index 0da442d..71fdd5e 100644 --- a/helpers/Webhook.ts +++ b/helpers/Webhook.ts @@ -9,30 +9,39 @@ import { GCResults } from '../helpers/GCResult'; export class WebhookEndpoint extends ApiEndpoint { public path = 'webhook'; - private readonly Client_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; + private readonly dClient_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; + private readonly dapi_key = 'AIzaSyAY1YAPK1lIcx1bgsLOgsRfNfAluVQhuq4'; private readonly urli = 'http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook'; - private readonly secret = '-lYglmNGqFNNazKoQX1m-EC9'; + private readonly dsecret = '-lYglmNGqFNNazKoQX1m-EC9'; public tokenid; - public async get(request: IApiRequest,endpoint:IApiEndpointInfo, read:IRead, modify: IModify, http: IHttp,persist: IPersistence): Promise { + public async get(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persist: IPersistence, resp: IApiResponse): Promise { + + const Client_id = await read.getEnvironmentReader().getSettings().getValueById('calendar_clientid') || this.dClient_id; + const secret = await read.getEnvironmentReader().getSettings().getValueById('calendar_secret_key') || this.dsecret; + const api_key = await read.getEnvironmentReader().getSettings().getValueById('calendar_apikey') || this.dapi_key; //logger.debug('response from first request is:', request.params);` const auth_code = request.query.code; - const url='https://www.googleapis.com/oauth2/v4/token'; - const newresponse = await http.post(url, { data: {'code':`${auth_code}`,'client_id':`${this.Client_id}`,'client_secret':`${this.secret}`,'redirect_uri':`${this.urli}`,'grant_type':'authorization_code',}}); + const url = 'https://www.googleapis.com/oauth2/v4/token'; + const newresponse = await http.post(url, { data: { 'code': `${auth_code}`, 'client_id': `${Client_id}`, 'client_secret': `${secret}`, 'redirect_uri': `${this.urli}`, 'grant_type': 'authorization_code', } }); if (newresponse.statusCode !== HttpStatusCode.OK || !newresponse.data) { - console.log('Did not get a valid response', newresponse); - throw new Error('Unable to retrieve response with auth code.'); + console.log('Did not get a valid response', newresponse); + throw new Error('Unable to retrieve response with auth code.'); } - console.log('his is the response from post api',newresponse); + console.log('This is the response from post api', newresponse); const acesstoken = new GCResults(newresponse.data); - // logger.debug('Auth token received is: ', auth_code); - this.tokenid = persist.create(acesstoken); - return this.success(); + // logger.debug('Auth token received is: ', auth_code); + this.tokenid = persist.create(acesstoken); + if (acesstoken) { + return this.success('Sign-in successful! Please close this window/tab and continue using!'); + } + else + throw new Error('Sign-in not successful'); //return auth_cod } diff --git a/i18n/en.json b/i18n/en.json new file mode 100644 index 0000000..984d3d0 --- /dev/null +++ b/i18n/en.json @@ -0,0 +1,10 @@ +{ + "calendar_apikey": "Your Google Calendar API key", + "Customize_GoogleCalendar_APIKey_Description": "Insert your Calendar API key from API Console", + "calendar_clientid": "Your Client ID", + "Customize_Calendar_ClientID": "Insert your Client ID from API Console", + "calendar_secret_key": "Your Secret Key", + "Customize_Calendar_SecretKey": "Insert your Secret Key from API Console", + "Calendar_Command_Description": "/calendar [subcommand]", + "Calendar_login": "/calendar {action}" +} \ No newline at end of file From 5b1caf8e33756ae404675d4feb7930cacf2134b8 Mon Sep 17 00:00:00 2001 From: Kapil Date: Mon, 10 Jun 2019 21:34:43 +0530 Subject: [PATCH 17/41] Added access token in app persistence and updated Readme --- Commands/GCCommands.ts | 5 ++++- README.md | 10 +++++++++- helpers/GSGetter.ts | 14 ++++++++++++-- helpers/Webhook.ts | 21 ++++++++++++++++----- helpers/persistence.ts | 35 +++++++++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 helpers/persistence.ts diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts index e580435..8d391e8 100644 --- a/Commands/GCCommands.ts +++ b/Commands/GCCommands.ts @@ -3,6 +3,8 @@ import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCom import { GoogleCalendarApp } from '../GoogleCalendar'; import { GCGetter } from '../helpers/GSGetter'; import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from '@rocket.chat/apps-engine/definition/api'; +import { AppPersistence } from '../helpers/persistence'; +import { IUser } from '@rocket.chat/apps-engine/definition/users'; @@ -17,13 +19,14 @@ export class GCCommand implements ISlashCommand { public async executor(context: SlashCommandContext, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise { + const cont = context.getArguments().join(' '); const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); try { - const loginstatus = await this.app.getGCGetter().login(cont, this.app.getLogger(), read, http, modify, context); + const loginstatus = await this.app.getGCGetter().login(cont, this.app.getLogger(), read, http, modify, context, persis); msg.setText('Slashcommand executed'); await modify.getCreator().finish(msg); } catch (e) { diff --git a/README.md b/README.md index 8228142..238216a 100644 --- a/README.md +++ b/README.md @@ -1 +1,9 @@ -google-calendar +Google Calendar Integration for Rocket.Chat + +Integrates google calendar with your Rocket.Chat server. + +Features : + + + + diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index 4b75839..ef4eaf0 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -1,10 +1,12 @@ -import { HttpStatusCode, IHttp, ILogger, IRead, IHttpResponse, IModify } from '@rocket.chat/apps-engine/definition/accessors'; +import { HttpStatusCode, IHttp, ILogger, IRead, IHttpResponse, IModify, IPersistence } from '@rocket.chat/apps-engine/definition/accessors'; import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; import { GCResults } from '../helpers/GCResult'; import { GoogleCalendarApp } from '../GoogleCalendar'; import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from '@rocket.chat/apps-engine/definition/api'; import { SettingType } from '@rocket.chat/apps-engine/definition/settings'; import { WebhookEndpoint } from '../helpers/Webhook'; +import { AppPersistence } from '../helpers/persistence'; + export class GCGetter { @@ -18,12 +20,14 @@ export class GCGetter { - public async login(phase: string, logger: ILogger, read: IRead, http: IHttp, modify: IModify, context: SlashCommandContext): Promise { + public async login(phase: string, logger: ILogger, read: IRead, http: IHttp, modify: IModify, context: SlashCommandContext, persis: IPersistence): Promise { const Client_id = await read.getEnvironmentReader().getSettings().getValueById('calendar_clientid') || this.dClient_id; const api_key = await read.getEnvironmentReader().getSettings().getValueById('calendar_apikey') || this.dapi_key; const secret = await read.getEnvironmentReader().getSettings().getValueById('calendar_secret_key') || this.dsecret; + + let signedin: boolean = false; const parame = phase; @@ -43,6 +47,12 @@ export class GCGetter { modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); } + + const persistence = new AppPersistence(persis, read.getPersistenceReader()); + const id = await persistence.connectUserToClient(Client_id, context.getSender()); + const atoken = await persistence.getAT(context.getSender()); + + console.log('This is the access token inside GCGetter:', atoken); return signedin = true; } diff --git a/helpers/Webhook.ts b/helpers/Webhook.ts index 71fdd5e..b9cc02d 100644 --- a/helpers/Webhook.ts +++ b/helpers/Webhook.ts @@ -1,10 +1,12 @@ import { HttpStatusCode, IHttp, ILogger, IModify, IPersistence, IRead } from '@rocket.chat/apps-engine/definition/accessors'; import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from '@rocket.chat/apps-engine/definition/api'; -//import { AppPersistence } from '../lib/persistence'; +import { RocketChatAssociationModel, RocketChatAssociationRecord } from '@rocket.chat/apps-engine/definition/metadata'; import { GCGetter } from './GSGetter'; import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; import { GCResults } from '../helpers/GCResult'; +import { IUser } from '@rocket.chat/apps-engine/definition/users'; +import { AppPersistence } from '../helpers/persistence'; export class WebhookEndpoint extends ApiEndpoint { @@ -15,7 +17,7 @@ export class WebhookEndpoint extends ApiEndpoint { private readonly dsecret = '-lYglmNGqFNNazKoQX1m-EC9'; public tokenid; - public async get(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persist: IPersistence, resp: IApiResponse): Promise { + public async get(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persist: IPersistence, user: IUser): Promise { const Client_id = await read.getEnvironmentReader().getSettings().getValueById('calendar_clientid') || this.dClient_id; const secret = await read.getEnvironmentReader().getSettings().getValueById('calendar_secret_key') || this.dsecret; @@ -35,14 +37,23 @@ export class WebhookEndpoint extends ApiEndpoint { console.log('This is the response from post api', newresponse); const acesstoken = new GCResults(newresponse.data); // logger.debug('Auth token received is: ', auth_code); + const atoken = acesstoken; + const persistence = new AppPersistence(persist, read.getPersistenceReader()); + const uid = await persistence.getuid(Client_id); + const id = await persistence.connectUserToAT(acesstoken, uid) + //const userAssociation = new RocketChatAssociationRecord(RocketChatAssociationModel.USER, uid); + //await persist.updateByAssociations([userAssociation], { acesstoken }, true); - this.tokenid = persist.create(acesstoken); + + // this.tokenid = persist.create(acesstoken); if (acesstoken) { - return this.success('Sign-in successful! Please close this window/tab and continue using!'); + //location.assign('http://localhost:3000/home'); + return this.success('
Sign-in successful! Please close this window/tab and continue using!
'); } else throw new Error('Sign-in not successful'); - //return auth_cod + // return auth_cod + //return this.success(); } } \ No newline at end of file diff --git a/helpers/persistence.ts b/helpers/persistence.ts new file mode 100644 index 0000000..753c2a1 --- /dev/null +++ b/helpers/persistence.ts @@ -0,0 +1,35 @@ +import { RocketChatAssociationModel, RocketChatAssociationRecord } from '@rocket.chat/apps-engine/definition/metadata'; +import { IPersistence, IPersistenceRead } from '@rocket.chat/apps-engine/definition/accessors'; +import { IUser } from '@rocket.chat/apps-engine/definition/users'; + +export class AppPersistence { + constructor(private readonly persistence: IPersistence, private readonly persistenceRead: IPersistenceRead) { } + + public async connectUserToClient(clientid: string, user: IUser): Promise { + const userAssociation = new RocketChatAssociationRecord(RocketChatAssociationModel.ROOM, user.id); + const clientAssociation = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, `${clientid}`); + + await this.persistence.updateByAssociations([userAssociation, clientAssociation], { uid: user.id }, true); + } + + public async getuid(Clientid: string): Promise { + + const clientAssociation = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, `${Clientid}`); + const [result] = await this.persistenceRead.readByAssociations([clientAssociation]); + return result ? (result as any).uid : undefined; + } + public async connectUserToAT(atoken: any, user: string): Promise { + const userAssociation = new RocketChatAssociationRecord(RocketChatAssociationModel.USER, user); + + await this.persistence.updateByAssociations([userAssociation], { atoken }, true); + + } + public async getAT(user: IUser): Promise { + const userAssociation = new RocketChatAssociationRecord(RocketChatAssociationModel.USER, user.id); + const [result] = await this.persistenceRead.readByAssociations([userAssociation]); + return result ? (result as any).atoken : undefined; + } + + + +} \ No newline at end of file From 34d0d0d1143d1f000bfffe730c13d4aee6b8b91f Mon Sep 17 00:00:00 2001 From: Kapil Date: Mon, 10 Jun 2019 22:07:49 +0530 Subject: [PATCH 18/41] Updated persistence --- helpers/GSGetter.ts | 6 +++--- helpers/Webhook.ts | 9 +++------ helpers/persistence.ts | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index ef4eaf0..8da4d97 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -25,7 +25,8 @@ export class GCGetter { const Client_id = await read.getEnvironmentReader().getSettings().getValueById('calendar_clientid') || this.dClient_id; const api_key = await read.getEnvironmentReader().getSettings().getValueById('calendar_apikey') || this.dapi_key; const secret = await read.getEnvironmentReader().getSettings().getValueById('calendar_secret_key') || this.dsecret; - + const persistence = new AppPersistence(persis, read.getPersistenceReader()); + const id = await persistence.connectUserToClient(Client_id, context.getSender()); let signedin: boolean = false; @@ -48,8 +49,7 @@ export class GCGetter { modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); } - const persistence = new AppPersistence(persis, read.getPersistenceReader()); - const id = await persistence.connectUserToClient(Client_id, context.getSender()); + const atoken = await persistence.getAT(context.getSender()); console.log('This is the access token inside GCGetter:', atoken); diff --git a/helpers/Webhook.ts b/helpers/Webhook.ts index b9cc02d..74aa5bb 100644 --- a/helpers/Webhook.ts +++ b/helpers/Webhook.ts @@ -17,7 +17,7 @@ export class WebhookEndpoint extends ApiEndpoint { private readonly dsecret = '-lYglmNGqFNNazKoQX1m-EC9'; public tokenid; - public async get(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persist: IPersistence, user: IUser): Promise { + public async get(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persist: IPersistence): Promise { const Client_id = await read.getEnvironmentReader().getSettings().getValueById('calendar_clientid') || this.dClient_id; const secret = await read.getEnvironmentReader().getSettings().getValueById('calendar_secret_key') || this.dsecret; @@ -40,12 +40,9 @@ export class WebhookEndpoint extends ApiEndpoint { const atoken = acesstoken; const persistence = new AppPersistence(persist, read.getPersistenceReader()); const uid = await persistence.getuid(Client_id); - const id = await persistence.connectUserToAT(acesstoken, uid) - //const userAssociation = new RocketChatAssociationRecord(RocketChatAssociationModel.USER, uid); - //await persist.updateByAssociations([userAssociation], { acesstoken }, true); + const id = await persistence.connectUserToAT(acesstoken, uid); + - - // this.tokenid = persist.create(acesstoken); if (acesstoken) { //location.assign('http://localhost:3000/home'); return this.success('
Sign-in successful! Please close this window/tab and continue using!
'); diff --git a/helpers/persistence.ts b/helpers/persistence.ts index 753c2a1..72339f7 100644 --- a/helpers/persistence.ts +++ b/helpers/persistence.ts @@ -14,7 +14,7 @@ export class AppPersistence { public async getuid(Clientid: string): Promise { - const clientAssociation = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, `${Clientid}`); + const clientAssociation = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, Clientid); const [result] = await this.persistenceRead.readByAssociations([clientAssociation]); return result ? (result as any).uid : undefined; } From 01c699a2b01f0ec0997106504ca4e442131f8a8d Mon Sep 17 00:00:00 2001 From: Gautime Date: Mon, 10 Jun 2019 22:13:47 +0530 Subject: [PATCH 19/41] Update README.md --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 238216a..c4d68f3 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,20 @@ -Google Calendar Integration for Rocket.Chat +# Google Calendar Integration for Rocket.Chat Integrates google calendar with your Rocket.Chat server. -Features : +#### Features : +* Authenticate to your gmail account from inside your Rocket.Chat. +* Create your private events in your google calendar fom your Rocket.Chat using just a slashcommand. +* View and update your private events using just a slashcommand. +* Get reminders and notifications of events. +* Create public events inside a room inviting all the users inside the room. + + +## Quick Start Guide + +#### Useful Slashcommands +* `/calendar auth` : To authenticate to your gmail account. +* `/calendar view` : Once the authentication is successful, you can use this command to view the private events on your calendar. From b25c4f6ecb33eb62819d058378b98499385e7936 Mon Sep 17 00:00:00 2001 From: Kapil Date: Tue, 11 Jun 2019 04:50:41 +0530 Subject: [PATCH 20/41] Logged access token inside GCGetter --- helpers/GSGetter.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index 8da4d97..59c06a5 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -27,8 +27,7 @@ export class GCGetter { const secret = await read.getEnvironmentReader().getSettings().getValueById('calendar_secret_key') || this.dsecret; const persistence = new AppPersistence(persis, read.getPersistenceReader()); const id = await persistence.connectUserToClient(Client_id, context.getSender()); - - + let signedin: boolean = false; const parame = phase; @@ -50,14 +49,17 @@ export class GCGetter { } - const atoken = await persistence.getAT(context.getSender()); - - console.log('This is the access token inside GCGetter:', atoken); + return signedin = true; } if (parame == 'logout') { const resnew = await http.get(`https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=http://localhost:3000`); + + const atoken = await persistence.getAT(context.getSender()); + + console.log('This is the access token inside GCGetter:', atoken); + } return signedin; From b3d7ee87ff6b46c557b92883dd8cf739b53b28ec Mon Sep 17 00:00:00 2001 From: Kapil Date: Wed, 12 Jun 2019 22:35:36 +0530 Subject: [PATCH 21/41] Added logout feature --- helpers/GSGetter.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index 59c06a5..9a4ff81 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -33,8 +33,6 @@ export class GCGetter { const parame = phase; if (parame == 'auth') { - //step1,2,3 - // const auth_code = await this.app.getwebhook().stepone(req,end,this.app.getLogger(), http,modify,context); const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); const response = (`${this.urli}client_id=${Client_id}&redirect_uri=http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&access_type=offline&response_type=code`); @@ -54,8 +52,20 @@ export class GCGetter { } if (parame == 'logout') { - const resnew = await http.get(`https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=http://localhost:3000`); - + + const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); + const response = `https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=http://localhost:3000`; + try { + msg.setText(response); + await modify.getCreator().finish(msg); + } catch (e) { + this.app.getLogger().error('Failed sending login url', e); + msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); + + modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); + } + + const atoken = await persistence.getAT(context.getSender()); console.log('This is the access token inside GCGetter:', atoken); From 4cc39db5430825189ad7227e7afc1ea675cf8912 Mon Sep 17 00:00:00 2001 From: Kapil Date: Thu, 13 Jun 2019 03:26:09 +0530 Subject: [PATCH 22/41] View Event call added --- Commands/GCCommands.ts | 4 +-- helpers/GSGetter.ts | 82 +++++++++++++++++++++++++----------------- helpers/Webhook.ts | 2 +- helpers/persistence.ts | 5 +-- 4 files changed, 56 insertions(+), 37 deletions(-) diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts index 8d391e8..e9f0867 100644 --- a/Commands/GCCommands.ts +++ b/Commands/GCCommands.ts @@ -20,13 +20,13 @@ export class GCCommand implements ISlashCommand { public async executor(context: SlashCommandContext, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise { - const cont = context.getArguments().join(' '); + //const cont = context.getArguments().join(' '); const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); try { - const loginstatus = await this.app.getGCGetter().login(cont, this.app.getLogger(), read, http, modify, context, persis); + const loginstatus = await this.app.getGCGetter().login( this.app.getLogger(), read, http, modify, context, persis); msg.setText('Slashcommand executed'); await modify.getCreator().finish(msg); } catch (e) { diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index 9a4ff81..892ffa9 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -6,7 +6,13 @@ import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from '@rocke import { SettingType } from '@rocket.chat/apps-engine/definition/settings'; import { WebhookEndpoint } from '../helpers/Webhook'; import { AppPersistence } from '../helpers/persistence'; +import { stringify } from 'querystring'; +enum Command { + connect = 'auth', + logout = 'logout', + show = 'view', +} export class GCGetter { @@ -20,59 +26,71 @@ export class GCGetter { - public async login(phase: string, logger: ILogger, read: IRead, http: IHttp, modify: IModify, context: SlashCommandContext, persis: IPersistence): Promise { + + + public async login(logger: ILogger, read: IRead, http: IHttp, modify: IModify, context: SlashCommandContext, persis: IPersistence): Promise { const Client_id = await read.getEnvironmentReader().getSettings().getValueById('calendar_clientid') || this.dClient_id; const api_key = await read.getEnvironmentReader().getSettings().getValueById('calendar_apikey') || this.dapi_key; const secret = await read.getEnvironmentReader().getSettings().getValueById('calendar_secret_key') || this.dsecret; const persistence = new AppPersistence(persis, read.getPersistenceReader()); const id = await persistence.connectUserToClient(Client_id, context.getSender()); - + let signedin: boolean = false; - const parame = phase; - if (parame == 'auth') { - const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - const response = (`${this.urli}client_id=${Client_id}&redirect_uri=http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&access_type=offline&response_type=code`); + const [parame] = context.getArguments(); + switch (parame) { + case (Command.connect): { + const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); + const response = (`${this.urli}client_id=${Client_id}&redirect_uri=http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&access_type=offline&response_type=code`); - try { - msg.setText(response); - await modify.getCreator().finish(msg); - } catch (e) { - this.app.getLogger().error('Failed sending login url', e); - msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); + try { + msg.setText(response); + await modify.getCreator().finish(msg); + } catch (e) { + this.app.getLogger().error('Failed sending login url', e); + msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); - modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); + modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); + } } - - - return signedin = true; - } + case (Command.logout): { + + const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); + const response = `https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=http://localhost:3000`; + try { + msg.setText(response); + await modify.getCreator().finish(msg); + } catch (e) { + this.app.getLogger().error('Failed sending login url', e); + msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); + + modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); + } - if (parame == 'logout') { - const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - const response = `https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=http://localhost:3000`; - try { - msg.setText(response); - await modify.getCreator().finish(msg); - } catch (e) { - this.app.getLogger().error('Failed sending login url', e); - msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); + const atoken = await persistence.getAT(context.getSender()); + + console.log('This is the access token inside GCGetter:', atoken); - modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); } + case (Command.show): { - const atoken = await persistence.getAT(context.getSender()); + const newatoken = await persistence.getAT(context.getSender()); - console.log('This is the access token inside GCGetter:', atoken); - - } + const dat = new Date(); + const newdate = dat.toISOString(); + const url = `https://www.googleapis.com/calendar/v3/calendars/primary/events?key=${api_key}&showDeleted=false&timeMin=${newdate}`; + const newresponse = await http.get(url, { headers: { 'Authorization': `Bearer ${newatoken}`, } }); + console.log('This is the AT for list events', newatoken); + console.log('This is view event response', newresponse); - return signedin; + } + + } } diff --git a/helpers/Webhook.ts b/helpers/Webhook.ts index 74aa5bb..3192c62 100644 --- a/helpers/Webhook.ts +++ b/helpers/Webhook.ts @@ -41,7 +41,7 @@ export class WebhookEndpoint extends ApiEndpoint { const persistence = new AppPersistence(persist, read.getPersistenceReader()); const uid = await persistence.getuid(Client_id); const id = await persistence.connectUserToAT(acesstoken, uid); - + if (acesstoken) { //location.assign('http://localhost:3000/home'); diff --git a/helpers/persistence.ts b/helpers/persistence.ts index 72339f7..dce374b 100644 --- a/helpers/persistence.ts +++ b/helpers/persistence.ts @@ -1,6 +1,7 @@ import { RocketChatAssociationModel, RocketChatAssociationRecord } from '@rocket.chat/apps-engine/definition/metadata'; import { IPersistence, IPersistenceRead } from '@rocket.chat/apps-engine/definition/accessors'; import { IUser } from '@rocket.chat/apps-engine/definition/users'; +import { stringify } from 'querystring'; export class AppPersistence { constructor(private readonly persistence: IPersistence, private readonly persistenceRead: IPersistenceRead) { } @@ -26,8 +27,8 @@ export class AppPersistence { } public async getAT(user: IUser): Promise { const userAssociation = new RocketChatAssociationRecord(RocketChatAssociationModel.USER, user.id); - const [result] = await this.persistenceRead.readByAssociations([userAssociation]); - return result ? (result as any).atoken : undefined; + const [result] = await this.persistenceRead.readByAssociation(userAssociation); + return result ? (result as any).atoken.atoken : undefined; } From 1e888ed349d5d9d075d2fbc32ececeb1b6ff9894 Mon Sep 17 00:00:00 2001 From: Kapil Date: Thu, 13 Jun 2019 06:41:31 +0530 Subject: [PATCH 23/41] Display title, start and end time of events --- Commands/GCCommands.ts | 2 +- helpers/GSGetter.ts | 10 ++++++++-- helpers/result.ts | 44 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 helpers/result.ts diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts index e9f0867..ffcc003 100644 --- a/Commands/GCCommands.ts +++ b/Commands/GCCommands.ts @@ -26,7 +26,7 @@ export class GCCommand implements ISlashCommand { try { - const loginstatus = await this.app.getGCGetter().login( this.app.getLogger(), read, http, modify, context, persis); + const loginstatus = await this.app.getGCGetter().login(this.app.getLogger(), read, http, modify, context, persis); msg.setText('Slashcommand executed'); await modify.getCreator().finish(msg); } catch (e) { diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index 892ffa9..b534209 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -7,6 +7,8 @@ import { SettingType } from '@rocket.chat/apps-engine/definition/settings'; import { WebhookEndpoint } from '../helpers/Webhook'; import { AppPersistence } from '../helpers/persistence'; import { stringify } from 'querystring'; +import { displayevents } from '../helpers/result'; + enum Command { connect = 'auth', @@ -85,8 +87,12 @@ export class GCGetter { const newdate = dat.toISOString(); const url = `https://www.googleapis.com/calendar/v3/calendars/primary/events?key=${api_key}&showDeleted=false&timeMin=${newdate}`; const newresponse = await http.get(url, { headers: { 'Authorization': `Bearer ${newatoken}`, } }); - console.log('This is the AT for list events', newatoken); - console.log('This is view event response', newresponse); + + for (var i = 0; i < newresponse.data.items.length; i++) { + // console.log( newresponse.data.items[i].summary); + await displayevents(newresponse.data.items[i], modify, context); + + } } diff --git a/helpers/result.ts b/helpers/result.ts new file mode 100644 index 0000000..76b4033 --- /dev/null +++ b/helpers/result.ts @@ -0,0 +1,44 @@ +import { IModify } from "@rocket.chat/apps-engine/definition/accessors"; +import { SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; + + +export async function displayevents(result: any, modify: IModify, context: SlashCommandContext): Promise { + + console.log('This is inside result function'); + const summ = result.summary as string; + let starttime = result.start.dateTime as string; + let endtime = result.end.dateTime as string; + //const array = starttime.split('T',2); + + const builder = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); + try { + builder.addAttachment({ + title: { + value: summ, + }, + text: 'is a due event starting from', + fields: [{ + short: false, + title: "Start day", + value: starttime, + + }, + + { + short: false, + title: "End Time", + value: endtime, + } + + ] + + + }); + await modify.getCreator().finish(builder); + } catch (e) { + this.app.getLogger().error('Failed displaying events', e); + builder.setText('An error occurred when sending the events as message :disappointed_relieved:'); + } + + +} \ No newline at end of file From 9d952eeb38f007619f6ea3c5fd5671e0d43efc4c Mon Sep 17 00:00:00 2001 From: Kapil Date: Fri, 14 Jun 2019 13:07:38 +0530 Subject: [PATCH 24/41] Date - Time format changed --- helpers/GSGetter.ts | 4 ++-- helpers/result.ts | 41 ++++++++++++++++++++++++----------------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index b534209..01a6946 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -12,7 +12,7 @@ import { displayevents } from '../helpers/result'; enum Command { connect = 'auth', - logout = 'logout', + lgout = 'logout', show = 'view', } @@ -58,7 +58,7 @@ export class GCGetter { } } - case (Command.logout): { + case (Command.lgout): { const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); const response = `https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=http://localhost:3000`; diff --git a/helpers/result.ts b/helpers/result.ts index 76b4033..22259b2 100644 --- a/helpers/result.ts +++ b/helpers/result.ts @@ -6,31 +6,38 @@ export async function displayevents(result: any, modify: IModify, context: Slash console.log('This is inside result function'); const summ = result.summary as string; - let starttime = result.start.dateTime as string; + const starttime = result.start.dateTime as string; let endtime = result.end.dateTime as string; - //const array = starttime.split('T',2); + const startdate = new Date(starttime); + const startyear = startdate.getFullYear(); + const startmonth = (startdate.getMonth() + 1); + const datestart = startdate.getDate();//prints expected format. + const starthours = startdate.getHours(); + const startminutes = startdate.getMinutes(); + + const shortcutdate = new Date(endtime); + const yearnew = shortcutdate.getFullYear(); + const monthnew = (shortcutdate.getMonth() + 1); + const datenew = shortcutdate.getDate();//prints expected format. + const hoursend = shortcutdate.getHours(); + const minutesend = shortcutdate.getMinutes(); + let timezone = starttime.split('+', 2); + let sign; + if (timezone) { + sign = '+'; + } + else { + timezone = starttime.split('-', 2); + sign = '-' + } const builder = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); try { builder.addAttachment({ title: { value: summ, }, - text: 'is a due event starting from', - fields: [{ - short: false, - title: "Start day", - value: starttime, - - }, - - { - short: false, - title: "End Time", - value: endtime, - } - - ] + text: `is a due event on your calendar starting from date ${datestart}/${startmonth}/${startyear} at ${starthours}:${startminutes} (UTC ${sign}${timezone[1]}) to ${datenew}/${monthnew}/${[yearnew]} at ${hoursend}:${minutesend} (UTC ${sign}${timezone[1]}) `, }); From ce1d5522a450ee9738299b1aa9251dcf40bebd13 Mon Sep 17 00:00:00 2001 From: Kapil Date: Sat, 15 Jun 2019 15:10:31 +0530 Subject: [PATCH 25/41] Create event implemented --- helpers/GSGetter.ts | 70 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index 01a6946..868dfed 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -14,13 +14,14 @@ enum Command { connect = 'auth', lgout = 'logout', show = 'view', + make = 'create', } export class GCGetter { private readonly dClient_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; private readonly dapi_key = 'AIzaSyAY1YAPK1lIcx1bgsLOgsRfNfAluVQhuq4'; - private readonly SCOPES = "https://www.googleapis.com/auth/calendar.readonly"; + private readonly SCOPES = "https://www.googleapis.com/auth/calendar"; private readonly urli = 'https://accounts.google.com/o/oauth2/v2/auth?'; private readonly dsecret = '-lYglmNGqFNNazKoQX1m-EC9'; private res; @@ -39,13 +40,14 @@ export class GCGetter { const id = await persistence.connectUserToClient(Client_id, context.getSender()); let signedin: boolean = false; + const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); const [parame] = context.getArguments(); switch (parame) { - case (Command.connect): { - const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - const response = (`${this.urli}client_id=${Client_id}&redirect_uri=http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar.readonly&prompt=consent&access_type=offline&response_type=code`); + + case (Command.connect): + const response = (`${this.urli}client_id=${Client_id}&redirect_uri=http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar&prompt=consent&access_type=offline&response_type=code`); try { msg.setText(response); @@ -55,21 +57,22 @@ export class GCGetter { msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); + } - } + break; - case (Command.lgout): { + case (Command.lgout): - const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - const response = `https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=http://localhost:3000`; + const mesg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); + const logresponse = `https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=http://localhost:3000`; try { - msg.setText(response); - await modify.getCreator().finish(msg); + mesg.setText(logresponse); + await modify.getCreator().finish(mesg); } catch (e) { this.app.getLogger().error('Failed sending login url', e); - msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); + mesg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); - modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); + modify.getNotifier().notifyUser(context.getSender(), mesg.getMessage()); } @@ -77,9 +80,9 @@ export class GCGetter { console.log('This is the access token inside GCGetter:', atoken); - } + break; - case (Command.show): { + case (Command.show): const newatoken = await persistence.getAT(context.getSender()); @@ -94,8 +97,45 @@ export class GCGetter { } - } + break; + + case (Command.make): + + const createatoken = await persistence.getAT(context.getSender()); + const params = context.getArguments().join(' '); + const array = params.split("\""); + const createurl = `https://www.googleapis.com/calendar/v3/calendars/primary/events?key=${api_key}`; + console.log('Create event array elements are these:', array[1], array[3]); + + const datetime = array[3] + 'T' + array[5]; + const date = new Date(datetime); + //const starttime = new Date(date.getTime() - date.getTimezoneOffset() * 60000); + const startdatetime = date.toISOString(); + + const edate = array[3] + 'T' + array[7]; + const enddate = new Date(edate); + const enddatetime = enddate.toISOString(); + + + // console.log('Start date and time in ISO format is: ',startdatetime,'end date time:',enddatetime); + + const createresponse = await http.post(createurl, { headers: { 'Authorization': `Bearer ${createatoken}`, }, data: { 'summary': `${array[1]}`, 'end': { 'dateTime': `${enddatetime}`, }, 'start': { 'dateTime': `${startdatetime}` } } }); + console.log('This is the create event request response: ', createresponse); + if (createresponse.statusCode == HttpStatusCode.OK && createresponse.data.status == "confirmed") + //console.log('Event created wohoooooo!!!'); + try { + msg.addAttachment({ + + text: `Event has been created. Find the event at [${createresponse.data.summary}](${createresponse.data.htmlLink}) `, + + }); + await modify.getCreator().finish(msg); + } catch (e) { + this.app.getLogger().error('Failed creating events', e); + msg.setText('An error occurred when sending the event creation as message :disappointed_relieved:'); + } + break; } } From f81ab639769cca201c2b7833046adec11e851731 Mon Sep 17 00:00:00 2001 From: Kapil Date: Sat, 15 Jun 2019 15:43:16 +0530 Subject: [PATCH 26/41] Error message if event creation fails --- helpers/GSGetter.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index 868dfed..94a5276 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -121,8 +121,7 @@ export class GCGetter { const createresponse = await http.post(createurl, { headers: { 'Authorization': `Bearer ${createatoken}`, }, data: { 'summary': `${array[1]}`, 'end': { 'dateTime': `${enddatetime}`, }, 'start': { 'dateTime': `${startdatetime}` } } }); console.log('This is the create event request response: ', createresponse); - if (createresponse.statusCode == HttpStatusCode.OK && createresponse.data.status == "confirmed") - //console.log('Event created wohoooooo!!!'); + if (createresponse.statusCode == HttpStatusCode.OK && createresponse.data.status == "confirmed") { //console.log('Event created wohoooooo!!!'); try { msg.addAttachment({ @@ -135,6 +134,23 @@ export class GCGetter { this.app.getLogger().error('Failed creating events', e); msg.setText('An error occurred when sending the event creation as message :disappointed_relieved:'); } + } + else { + console.log('This is the error message:', createresponse.data.error.message); + + try { + msg.addAttachment({ + + text: `Event could not be created. It encountered the error: ${createresponse.data.error.message}. Please try again. `, + + + }); + await modify.getCreator().finish(msg); + } catch (e) { + this.app.getLogger().error('Failed creating events', e); + msg.setText('An error occurred when sending the event creation as message :disappointed_relieved:'); + } + } break; } From 0e261ea01b4474fb63a592d7bba71ca9c3ecbdbb Mon Sep 17 00:00:00 2001 From: Kapil Date: Tue, 18 Jun 2019 20:59:30 +0530 Subject: [PATCH 27/41] Added redirect uri config setting --- Commands/GCCommands.ts | 4 +++- GoogleCalendar.ts | 10 ++++++++++ helpers/GSGetter.ts | 20 +++++++++----------- helpers/Webhook.ts | 9 +++------ i18n/en.json | 3 ++- 5 files changed, 27 insertions(+), 19 deletions(-) diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts index ffcc003..e186198 100644 --- a/Commands/GCCommands.ts +++ b/Commands/GCCommands.ts @@ -28,7 +28,9 @@ export class GCCommand implements ISlashCommand { const loginstatus = await this.app.getGCGetter().login(this.app.getLogger(), read, http, modify, context, persis); msg.setText('Slashcommand executed'); - await modify.getCreator().finish(msg); + // await modify.getCreator().finish(msg); + modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); + } catch (e) { this.app.getLogger().error('Failed sending login url', e); //msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); diff --git a/GoogleCalendar.ts b/GoogleCalendar.ts index e2f85bf..4e1ed14 100644 --- a/GoogleCalendar.ts +++ b/GoogleCalendar.ts @@ -71,6 +71,16 @@ export class GoogleCalendarApp extends App { i18nDescription: 'Customize_Calendar_SecretKey', }); + await configuration.settings.provideSetting({ + id: 'redirect_uri', + type: SettingType.STRING, + packageValue: '', + required: true, + public: false, + i18nLabel: 'Customize_Redirect_uri', + i18nDescription: 'Customize_Redirect_URI', + }); + await configuration.slashCommands.provideSlashCommand(new GCCommand(this)); } diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index 94a5276..d96bcf3 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -19,11 +19,8 @@ enum Command { export class GCGetter { - private readonly dClient_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; - private readonly dapi_key = 'AIzaSyAY1YAPK1lIcx1bgsLOgsRfNfAluVQhuq4'; private readonly SCOPES = "https://www.googleapis.com/auth/calendar"; private readonly urli = 'https://accounts.google.com/o/oauth2/v2/auth?'; - private readonly dsecret = '-lYglmNGqFNNazKoQX1m-EC9'; private res; private readonly app: GoogleCalendarApp; @@ -33,9 +30,10 @@ export class GCGetter { public async login(logger: ILogger, read: IRead, http: IHttp, modify: IModify, context: SlashCommandContext, persis: IPersistence): Promise { - const Client_id = await read.getEnvironmentReader().getSettings().getValueById('calendar_clientid') || this.dClient_id; - const api_key = await read.getEnvironmentReader().getSettings().getValueById('calendar_apikey') || this.dapi_key; - const secret = await read.getEnvironmentReader().getSettings().getValueById('calendar_secret_key') || this.dsecret; + const Client_id = await read.getEnvironmentReader().getSettings().getValueById('calendar_clientid'); + const api_key = await read.getEnvironmentReader().getSettings().getValueById('calendar_apikey'); + const secret = await read.getEnvironmentReader().getSettings().getValueById('calendar_secret_key'); + const redirect = await read.getEnvironmentReader().getSettings().getValueById('redirect_uri'); const persistence = new AppPersistence(persis, read.getPersistenceReader()); const id = await persistence.connectUserToClient(Client_id, context.getSender()); @@ -47,7 +45,7 @@ export class GCGetter { switch (parame) { case (Command.connect): - const response = (`${this.urli}client_id=${Client_id}&redirect_uri=http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar&prompt=consent&access_type=offline&response_type=code`); + const response = (`${this.urli}client_id=${Client_id}&redirect_uri=http://${redirect}/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar&prompt=consent&access_type=offline&response_type=code`); try { msg.setText(response); @@ -64,13 +62,13 @@ export class GCGetter { case (Command.lgout): const mesg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - const logresponse = `https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=http://localhost:3000`; + const logresponse = `https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=${redirect}`; try { mesg.setText(logresponse); await modify.getCreator().finish(mesg); } catch (e) { - this.app.getLogger().error('Failed sending login url', e); - mesg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); + this.app.getLogger().error('Failed sending logout url', e); + mesg.setText('An error occurred when trying to send the logout url:disappointed_relieved:'); modify.getNotifier().notifyUser(context.getSender(), mesg.getMessage()); } @@ -78,7 +76,7 @@ export class GCGetter { const atoken = await persistence.getAT(context.getSender()); - console.log('This is the access token inside GCGetter:', atoken); + // console.log('This is the access token inside GCGetter:', atoken); break; diff --git a/helpers/Webhook.ts b/helpers/Webhook.ts index 3192c62..304bd6c 100644 --- a/helpers/Webhook.ts +++ b/helpers/Webhook.ts @@ -11,17 +11,14 @@ import { AppPersistence } from '../helpers/persistence'; export class WebhookEndpoint extends ApiEndpoint { public path = 'webhook'; - private readonly dClient_id = '201256566157-552j1d7qdejuhrnovkoseieu85oomgh5.apps.googleusercontent.com'; - private readonly dapi_key = 'AIzaSyAY1YAPK1lIcx1bgsLOgsRfNfAluVQhuq4'; private readonly urli = 'http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook'; - private readonly dsecret = '-lYglmNGqFNNazKoQX1m-EC9'; public tokenid; public async get(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persist: IPersistence): Promise { - const Client_id = await read.getEnvironmentReader().getSettings().getValueById('calendar_clientid') || this.dClient_id; - const secret = await read.getEnvironmentReader().getSettings().getValueById('calendar_secret_key') || this.dsecret; - const api_key = await read.getEnvironmentReader().getSettings().getValueById('calendar_apikey') || this.dapi_key; + const Client_id = await read.getEnvironmentReader().getSettings().getValueById('calendar_clientid'); + const secret = await read.getEnvironmentReader().getSettings().getValueById('calendar_secret_key'); + const api_key = await read.getEnvironmentReader().getSettings().getValueById('calendar_apikey'); //logger.debug('response from first request is:', request.params);` diff --git a/i18n/en.json b/i18n/en.json index 984d3d0..7e4bebc 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -6,5 +6,6 @@ "calendar_secret_key": "Your Secret Key", "Customize_Calendar_SecretKey": "Insert your Secret Key from API Console", "Calendar_Command_Description": "/calendar [subcommand]", - "Calendar_login": "/calendar {action}" + "Calendar_login": "/calendar {action}", + "redirect_uri": "Enter your server address" } \ No newline at end of file From 7ea1aa42fe80e52e875b1822dfd9f500265eea2e Mon Sep 17 00:00:00 2001 From: Kapil Date: Wed, 19 Jun 2019 14:18:42 +0530 Subject: [PATCH 28/41] Added link with each view event for update/delete --- helpers/GSGetter.ts | 2 +- helpers/result.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index d96bcf3..d9cddde 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -45,7 +45,7 @@ export class GCGetter { switch (parame) { case (Command.connect): - const response = (`${this.urli}client_id=${Client_id}&redirect_uri=http://${redirect}/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar&prompt=consent&access_type=offline&response_type=code`); + const response = (`${this.urli}client_id=${Client_id}&redirect_uri=${redirect}/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar&prompt=consent&access_type=offline&response_type=code`); try { msg.setText(response); diff --git a/helpers/result.ts b/helpers/result.ts index 22259b2..583696e 100644 --- a/helpers/result.ts +++ b/helpers/result.ts @@ -37,7 +37,7 @@ export async function displayevents(result: any, modify: IModify, context: Slash title: { value: summ, }, - text: `is a due event on your calendar starting from date ${datestart}/${startmonth}/${startyear} at ${starthours}:${startminutes} (UTC ${sign}${timezone[1]}) to ${datenew}/${monthnew}/${[yearnew]} at ${hoursend}:${minutesend} (UTC ${sign}${timezone[1]}) `, + text: `is a due event on your calendar starting from date ${datestart}/${startmonth}/${startyear} at ${starthours}:${startminutes} (UTC ${sign}${timezone[1]}) to ${datenew}/${monthnew}/${[yearnew]} at ${hoursend}:${minutesend} (UTC ${sign}${timezone[1]}). [Find and manage the event here](${result.htmlLink}) `, }); From 32731124a3cc8e190904f2402fb338f48c6ff4a6 Mon Sep 17 00:00:00 2001 From: Gautime Date: Wed, 19 Jun 2019 14:24:11 +0530 Subject: [PATCH 29/41] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c4d68f3..10a5d39 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,9 @@ Integrates google calendar with your Rocket.Chat server. #### Useful Slashcommands * `/calendar auth` : To authenticate to your gmail account. * `/calendar view` : Once the authentication is successful, you can use this command to view the private events on your calendar. +* `/calendar create "Title" "Date" "Start time" "Endtime"` : This command can be used to create a private on your primary calendar, where Title is the title of the event you are creating, and date should be in format YYYY-MM-DD and time in 24 hours format. + +* `/calendar logout` : Once you are done with viewing, creating your calendar events and wants to log out of the gmail account, use this command and it will log you out and redirect to your home page. From 2fd9de471ba147d1d1857f3130cce87dbc082685 Mon Sep 17 00:00:00 2001 From: Gautime Date: Wed, 19 Jun 2019 14:25:42 +0530 Subject: [PATCH 30/41] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 10a5d39..f3b0aa1 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ Integrates google calendar with your Rocket.Chat server. #### Useful Slashcommands * `/calendar auth` : To authenticate to your gmail account. -* `/calendar view` : Once the authentication is successful, you can use this command to view the private events on your calendar. +* `/calendar view` : Once the authentication is successful, you can use this command to view the private events on your calendar. Events will be displayed with title, date, start time and end time. You will also get the link, which you can click on and it will take directly to your calendar where you can udpate or delete that event. + * `/calendar create "Title" "Date" "Start time" "Endtime"` : This command can be used to create a private on your primary calendar, where Title is the title of the event you are creating, and date should be in format YYYY-MM-DD and time in 24 hours format. * `/calendar logout` : Once you are done with viewing, creating your calendar events and wants to log out of the gmail account, use this command and it will log you out and redirect to your home page. From af44f54a95db37aa87f8cf28533596ab324e6c99 Mon Sep 17 00:00:00 2001 From: Kapil Date: Sun, 23 Jun 2019 15:30:50 +0530 Subject: [PATCH 31/41] Resolved conflicts --- Commands/GCCommands.ts | 6 +----- helpers/GSGetter.ts | 8 +------- helpers/persistence.ts | 3 --- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts index 24d2137..5452e73 100644 --- a/Commands/GCCommands.ts +++ b/Commands/GCCommands.ts @@ -19,18 +19,14 @@ export class GCCommand implements ISlashCommand { public async executor(context: SlashCommandContext, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise { - - //const cont = context.getArguments().join(' '); - - const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); try { const loginstatus = await this.app.getGCGetter().login(this.app.getLogger(), read, http, modify, context, persis); msg.setText('Slashcommand executed'); - // await modify.getCreator().finish(msg); + // await modify.getCreator().finish(msg); modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index b47a07d..4dc138f 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -21,16 +21,10 @@ enum Command { export class GCGetter { private readonly SCOPES = "https://www.googleapis.com/auth/calendar"; - private readonly urli = 'https://accounts.google.com/o/oauth2/v2/auth?'; private res; private readonly app: GoogleCalendarApp; - - - - - public async login(logger: ILogger, read: IRead, http: IHttp, modify: IModify, context: SlashCommandContext, persis: IPersistence): Promise { @@ -81,7 +75,7 @@ export class GCGetter { const atoken = await persistence.getAT(context.getSender()); - // console.log('This is the access token inside GCGetter:', atoken); + // console.log('This is the access token inside GCGetter:', atoken); break; diff --git a/helpers/persistence.ts b/helpers/persistence.ts index 730c696..f60c331 100644 --- a/helpers/persistence.ts +++ b/helpers/persistence.ts @@ -32,7 +32,4 @@ export class AppPersistence { return result ? (result as any).atoken.atoken : undefined; } - - - } \ No newline at end of file From 893fa3f2177e43a7b73f6ed40bd88c94ffb26c72 Mon Sep 17 00:00:00 2001 From: Gautime Date: Mon, 24 Jun 2019 14:55:56 +0530 Subject: [PATCH 32/41] Create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f6a7f54 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Rocket.Chat + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From f423c23be74a6e5478da2032e8e334703863b554 Mon Sep 17 00:00:00 2001 From: Kapil Date: Thu, 4 Jul 2019 03:38:08 +0530 Subject: [PATCH 33/41] Quickadd Added --- helpers/GSGetter.ts | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index 8fba89b..595aad6 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -8,9 +8,7 @@ import { WebhookEndpoint } from '../helpers/Webhook'; import { AppPersistence } from '../helpers/persistence'; import { stringify } from 'querystring'; import { displayevents } from '../helpers/result'; - -import { stringify } from 'querystring'; -import { displayevents } from '../helpers/result'; +import { ok } from 'assert'; enum Command { @@ -18,12 +16,7 @@ enum Command { lgout = 'logout', show = 'view', make = 'create', -} - -enum Command { - connect = 'auth', - lgout = 'logout', - show = 'view', + quick = 'quickadd', } @@ -51,6 +44,7 @@ export class GCGetter { const [parame] = context.getArguments(); + switch (parame) { case (Command.connect): const response = (`${this.urli}client_id=${Client_id}&redirect_uri=${redirect}/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar&prompt=consent&access_type=offline&response_type=code`); @@ -69,7 +63,7 @@ export class GCGetter { case (Command.lgout): const mesg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - const logresponse = `https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=${redirect}`; + const logresponse = `https://www.google.com/accounts/Logout?continue=${redirect}`; try { mesg.setText(logresponse); await modify.getCreator().finish(mesg); @@ -157,8 +151,24 @@ export class GCGetter { } } break; - } + case (Command.quick): + + const title = context.getArguments().join(' '); + const titlenew = title.split('\"'); + //const fintitle = titlenew.; + const token = await persistence.getAT(context.getSender()); + const quick_url = `https://www.googleapis.com/calendar/v3/calendars/primary/events/quickAdd?key=${api_key}&text=${titlenew[1]}`; + const quickresponse = await http.post(quick_url, { headers: { 'Authorization': `Bearer ${token}`, } }); + console.log('This is the quick-add response', quickresponse); + if (quickresponse && quickresponse.statusCode == HttpStatusCode.OK) { + const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); + msg.setText('Quickadd event succcessfully created!'); + await modify.getCreator().finish(msg); + } + break; + } + } } From 310ccb70606344b03965898d9ab6c088cb7ad471 Mon Sep 17 00:00:00 2001 From: Kapil Date: Thu, 4 Jul 2019 04:10:48 +0530 Subject: [PATCH 34/41] Changed naming convention --- Commands/GCCommands.ts | 2 +- helpers/GCResult.ts | 8 ++-- helpers/GSGetter.ts | 94 +++++++++++++++++++++--------------------- helpers/Webhook.ts | 20 ++++----- helpers/persistence.ts | 18 ++++---- helpers/result.ts | 42 +++++++++---------- 6 files changed, 92 insertions(+), 92 deletions(-) diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts index d6fc7cc..a52088d 100644 --- a/Commands/GCCommands.ts +++ b/Commands/GCCommands.ts @@ -25,7 +25,7 @@ export class GCCommand implements ISlashCommand { try { - const loginstatus = await this.app.getGCGetter().login(this.app.getLogger(), read, http, modify, context, persis); + const login_status = await this.app.getGCGetter().login(this.app.getLogger(), read, http, modify, context, persis); msg.setText('Slashcommand executed'); // await modify.getCreator().finish(msg); diff --git a/helpers/GCResult.ts b/helpers/GCResult.ts index c1d882d..f9e7b41 100644 --- a/helpers/GCResult.ts +++ b/helpers/GCResult.ts @@ -3,20 +3,20 @@ import { HttpStatusCode, IHttp, ILogger, IRead } from '@rocket.chat/apps-engine/ import { IApiRequest } from '@rocket.chat/apps-engine/definition/api'; export class GCResults { - public atoken: string; + public acess_token: string; constructor(data?: any) { if (data) { - this.atoken = data.access_token as string; + this.acess_token = data.access_token as string; } } public result(): string { - if (!this.atoken) { + if (!this.acess_token) { throw new Error('Invalid result'); } - return this.atoken; + return this.acess_token; } } \ No newline at end of file diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index 595aad6..f8e817c 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -29,49 +29,49 @@ export class GCGetter { public async login(logger: ILogger, read: IRead, http: IHttp, modify: IModify, context: SlashCommandContext, persis: IPersistence): Promise { - const Client_id = await read.getEnvironmentReader().getSettings().getValueById('calendar_clientid'); + const client_id = await read.getEnvironmentReader().getSettings().getValueById('calendar_clientid'); const api_key = await read.getEnvironmentReader().getSettings().getValueById('calendar_apikey'); const secret = await read.getEnvironmentReader().getSettings().getValueById('calendar_secret_key'); const redirect = await read.getEnvironmentReader().getSettings().getValueById('redirect_uri'); const persistence = new AppPersistence(persis, read.getPersistenceReader()); - const id = await persistence.connectUserToClient(Client_id, context.getSender()); + const id = await persistence.connectUserToClient(client_id, context.getSender()); let signedin: boolean = false; - const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); + const message = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - const [parame] = context.getArguments(); + const [parameter] = context.getArguments(); - switch (parame) { + switch (parameter) { case (Command.connect): - const response = (`${this.urli}client_id=${Client_id}&redirect_uri=${redirect}/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar&prompt=consent&access_type=offline&response_type=code`); + const response = (`${this.urli}client_id=${client_id}&redirect_uri=${redirect}/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar&prompt=consent&access_type=offline&response_type=code`); try { - msg.setText(response); - await modify.getCreator().finish(msg); + message.setText(response); + await modify.getCreator().finish(message); } catch (e) { this.app.getLogger().error('Failed sending login url', e); - msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); + message.setText('An error occurred when trying to send the login url:disappointed_relieved:'); - modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); + modify.getNotifier().notifyUser(context.getSender(), message.getMessage()); } break; case (Command.lgout): - const mesg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); + // const mesg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); const logresponse = `https://www.google.com/accounts/Logout?continue=${redirect}`; try { - mesg.setText(logresponse); - await modify.getCreator().finish(mesg); + message.setText(logresponse); + await modify.getCreator().finish(message); } catch (e) { this.app.getLogger().error('Failed sending logout url', e); - mesg.setText('An error occurred when trying to send the logout url:disappointed_relieved:'); + message.setText('An error occurred when trying to send the logout url:disappointed_relieved:'); - modify.getNotifier().notifyUser(context.getSender(), mesg.getMessage()); + modify.getNotifier().notifyUser(context.getSender(), message.getMessage()); } @@ -83,16 +83,16 @@ export class GCGetter { case (Command.show): - const newatoken = await persistence.getAT(context.getSender()); + const new_token = await persistence.getAT(context.getSender()); const dat = new Date(); - const newdate = dat.toISOString(); - const url = `https://www.googleapis.com/calendar/v3/calendars/primary/events?key=${api_key}&showDeleted=false&timeMin=${newdate}`; - const newresponse = await http.get(url, { headers: { 'Authorization': `Bearer ${newatoken}`, } }); + const minimum_date = dat.toISOString(); + const url = `https://www.googleapis.com/calendar/v3/calendars/primary/events?key=${api_key}&showDeleted=false&timeMin=${minimum_date}`; + const api_response = await http.get(url, { headers: { 'Authorization': `Bearer ${new_token}`, } }); - for (var i = 0; i < newresponse.data.items.length; i++) { + for (var i = 0; i < api_response.data.items.length; i++) { // console.log( newresponse.data.items[i].summary); - await displayevents(newresponse.data.items[i], modify, context); + await displayevents(api_response.data.items[i], modify, context); } @@ -100,54 +100,54 @@ export class GCGetter { case (Command.make): - const createatoken = await persistence.getAT(context.getSender()); + const access_token = await persistence.getAT(context.getSender()); const params = context.getArguments().join(' '); const array = params.split("\""); - const createurl = `https://www.googleapis.com/calendar/v3/calendars/primary/events?key=${api_key}`; + const create_url = `https://www.googleapis.com/calendar/v3/calendars/primary/events?key=${api_key}`; console.log('Create event array elements are these:', array[1], array[3]); const datetime = array[3] + 'T' + array[5]; const date = new Date(datetime); //const starttime = new Date(date.getTime() - date.getTimezoneOffset() * 60000); - const startdatetime = date.toISOString(); + const start_datetime = date.toISOString(); - const edate = array[3] + 'T' + array[7]; - const enddate = new Date(edate); - const enddatetime = enddate.toISOString(); + const e_date = array[3] + 'T' + array[7]; + const end_date = new Date(e_date); + const end_datetime = end_date.toISOString(); // console.log('Start date and time in ISO format is: ',startdatetime,'end date time:',enddatetime); - const createresponse = await http.post(createurl, { headers: { 'Authorization': `Bearer ${createatoken}`, }, data: { 'summary': `${array[1]}`, 'end': { 'dateTime': `${enddatetime}`, }, 'start': { 'dateTime': `${startdatetime}` } } }); - console.log('This is the create event request response: ', createresponse); - if (createresponse.statusCode == HttpStatusCode.OK && createresponse.data.status == "confirmed") { //console.log('Event created wohoooooo!!!'); + const create_api_response = await http.post(create_url, { headers: { 'Authorization': `Bearer ${access_token}`, }, data: { 'summary': `${array[1]}`, 'end': { 'dateTime': `${end_datetime}`, }, 'start': { 'dateTime': `${start_datetime}` } } }); + console.log('This is the create event request response: ', create_api_response); + if (create_api_response.statusCode == HttpStatusCode.OK && create_api_response.data.status == "confirmed") { //console.log('Event created wohoooooo!!!'); try { - msg.addAttachment({ + message.addAttachment({ - text: `Event has been created. Find the event at [${createresponse.data.summary}](${createresponse.data.htmlLink}) `, + text: `Event has been created. Find the event at [${create_api_response.data.summary}](${create_api_response.data.htmlLink}) `, }); - await modify.getCreator().finish(msg); + await modify.getCreator().finish(message); } catch (e) { this.app.getLogger().error('Failed creating events', e); - msg.setText('An error occurred when sending the event creation as message :disappointed_relieved:'); + message.setText('An error occurred when sending the event creation as message :disappointed_relieved:'); } } else { - console.log('This is the error message:', createresponse.data.error.message); + console.log('This is the error message:', create_api_response.data.error.message); try { - msg.addAttachment({ + message.addAttachment({ - text: `Event could not be created. It encountered the error: ${createresponse.data.error.message}. Please try again. `, + text: `Event could not be created. It encountered the error: ${create_api_response.data.error.message}. Please try again. `, }); - await modify.getCreator().finish(msg); + await modify.getCreator().finish(message); } catch (e) { this.app.getLogger().error('Failed creating events', e); - msg.setText('An error occurred when sending the event creation as message :disappointed_relieved:'); + message.setText('An error occurred when sending the event creation as message :disappointed_relieved:'); } } break; @@ -155,16 +155,16 @@ export class GCGetter { case (Command.quick): const title = context.getArguments().join(' '); - const titlenew = title.split('\"'); + const title_new = title.split('\"'); //const fintitle = titlenew.; const token = await persistence.getAT(context.getSender()); - const quick_url = `https://www.googleapis.com/calendar/v3/calendars/primary/events/quickAdd?key=${api_key}&text=${titlenew[1]}`; - const quickresponse = await http.post(quick_url, { headers: { 'Authorization': `Bearer ${token}`, } }); - console.log('This is the quick-add response', quickresponse); - if (quickresponse && quickresponse.statusCode == HttpStatusCode.OK) { - const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - msg.setText('Quickadd event succcessfully created!'); - await modify.getCreator().finish(msg); + const quick_url = `https://www.googleapis.com/calendar/v3/calendars/primary/events/quickAdd?key=${api_key}&text=${title_new[1]}`; + const quick_api_response = await http.post(quick_url, { headers: { 'Authorization': `Bearer ${token}`, } }); + console.log('This is the quick-add response', quick_api_response); + if (quick_api_response && quick_api_response.statusCode == HttpStatusCode.OK) { + // const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); + message.setText('Quickadd event succcessfully created!'); + await modify.getCreator().finish(message); } break; } diff --git a/helpers/Webhook.ts b/helpers/Webhook.ts index eac69d4..239f86b 100644 --- a/helpers/Webhook.ts +++ b/helpers/Webhook.ts @@ -16,7 +16,7 @@ export class WebhookEndpoint extends ApiEndpoint { public async get(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persist: IPersistence): Promise { - const Client_id = await read.getEnvironmentReader().getSettings().getValueById('calendar_clientid'); + const client_id = await read.getEnvironmentReader().getSettings().getValueById('calendar_clientid'); const secret = await read.getEnvironmentReader().getSettings().getValueById('calendar_secret_key'); const api_key = await read.getEnvironmentReader().getSettings().getValueById('calendar_apikey'); @@ -24,23 +24,23 @@ export class WebhookEndpoint extends ApiEndpoint { const auth_code = request.query.code; const url = 'https://www.googleapis.com/oauth2/v4/token'; - const newresponse = await http.post(url, { data: { 'code': `${auth_code}`, 'client_id': `${Client_id}`, 'client_secret': `${secret}`, 'redirect_uri': `${this.urli}`, 'grant_type': 'authorization_code', } }); + const new_response = await http.post(url, { data: { 'code': `${auth_code}`, 'client_id': `${client_id}`, 'client_secret': `${secret}`, 'redirect_uri': `${this.urli}`, 'grant_type': 'authorization_code', } }); - if (newresponse.statusCode !== HttpStatusCode.OK || !newresponse.data) { - console.log('Did not get a valid response', newresponse); + if (new_response.statusCode !== HttpStatusCode.OK || !new_response.data) { + console.log('Did not get a valid response', new_response); throw new Error('Unable to retrieve response with auth code.'); } - console.log('This is the response from post api', newresponse); - const acesstoken = new GCResults(newresponse.data); + console.log('This is the response from post api', new_response); + const acess_token = new GCResults(new_response.data); // logger.debug('Auth token received is: ', auth_code); - const atoken = acesstoken; + const atoken = acess_token; const persistence = new AppPersistence(persist, read.getPersistenceReader()); - const uid = await persistence.getuid(Client_id); - const id = await persistence.connectUserToAT(acesstoken, uid); + const user_id = await persistence.getuid(client_id); + const id = await persistence.connectUserToAT(acess_token, user_id); - if (acesstoken) { + if (acess_token) { //location.assign('http://localhost:3000/home'); return this.success('
Sign-in successful! Please close this window/tab and continue using!
'); } diff --git a/helpers/persistence.ts b/helpers/persistence.ts index f60c331..77dd5f6 100644 --- a/helpers/persistence.ts +++ b/helpers/persistence.ts @@ -7,28 +7,28 @@ export class AppPersistence { constructor(private readonly persistence: IPersistence, private readonly persistenceRead: IPersistenceRead) { } public async connectUserToClient(clientid: string, user: IUser): Promise { - const userAssociation = new RocketChatAssociationRecord(RocketChatAssociationModel.ROOM, user.id); - const clientAssociation = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, `${clientid}`); + const user_association = new RocketChatAssociationRecord(RocketChatAssociationModel.ROOM, user.id); + const client_association = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, `${clientid}`); - await this.persistence.updateByAssociations([userAssociation, clientAssociation], { uid: user.id }, true); + await this.persistence.updateByAssociations([user_association, client_association], { uid: user.id }, true); } public async getuid(Clientid: string): Promise { - const clientAssociation = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, Clientid); - const [result] = await this.persistenceRead.readByAssociations([clientAssociation]); + const client_association = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, Clientid); + const [result] = await this.persistenceRead.readByAssociations([client_association]); return result ? (result as any).uid : undefined; } public async connectUserToAT(atoken: any, user: string): Promise { - const userAssociation = new RocketChatAssociationRecord(RocketChatAssociationModel.USER, user); + const user_association = new RocketChatAssociationRecord(RocketChatAssociationModel.USER, user); - await this.persistence.updateByAssociations([userAssociation], { atoken }, true); + await this.persistence.updateByAssociations([user_association], { atoken }, true); } public async getAT(user: IUser): Promise { - const userAssociation = new RocketChatAssociationRecord(RocketChatAssociationModel.USER, user.id); + const user_association = new RocketChatAssociationRecord(RocketChatAssociationModel.USER, user.id); - const [result] = await this.persistenceRead.readByAssociation(userAssociation); + const [result] = await this.persistenceRead.readByAssociation(user_association); return result ? (result as any).atoken.atoken : undefined; } diff --git a/helpers/result.ts b/helpers/result.ts index 511651b..4a4bc48 100644 --- a/helpers/result.ts +++ b/helpers/result.ts @@ -5,39 +5,39 @@ import { SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashco export async function displayevents(result: any, modify: IModify, context: SlashCommandContext): Promise { console.log('This is inside result function'); - const summ = result.summary as string; - const starttime = result.start.dateTime as string; - let endtime = result.end.dateTime as string; - - const startdate = new Date(starttime); - const startyear = startdate.getFullYear(); - const startmonth = (startdate.getMonth() + 1); - const datestart = startdate.getDate();//prints expected format. - const starthours = startdate.getHours(); - const startminutes = startdate.getMinutes(); - - const shortcutdate = new Date(endtime); - const yearnew = shortcutdate.getFullYear(); - const monthnew = (shortcutdate.getMonth() + 1); - const datenew = shortcutdate.getDate();//prints expected format. - const hoursend = shortcutdate.getHours(); - const minutesend = shortcutdate.getMinutes(); - let timezone = starttime.split('+', 2); + const summary = result.summary as string; + const start_time = result.start.dateTime as string; + let end_time = result.end.dateTime as string; + + const start_date = new Date(start_time); + const start_year = start_date.getFullYear(); + const start_month = (start_date.getMonth() + 1); + const date_start = start_date.getDate();//prints expected format. + const start_hours = start_date.getHours(); + const start_minutes = start_date.getMinutes(); + + const short_cut_date = new Date(end_time); + const year_new = short_cut_date.getFullYear(); + const month_new = (short_cut_date.getMonth() + 1); + const date_new = short_cut_date.getDate();//prints expected format. + const hours_end = short_cut_date.getHours(); + const minutes_end = short_cut_date.getMinutes(); + let timezone = start_time.split('+', 2); let sign; if (timezone) { sign = '+'; } else { - timezone = starttime.split('-', 2); + timezone = start_time.split('-', 2); sign = '-' } const builder = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); try { builder.addAttachment({ title: { - value: summ, + value: summary, }, - text: `is a due event on your calendar starting from date ${datestart}/${startmonth}/${startyear} at ${starthours}:${startminutes} (UTC ${sign}${timezone[1]}) to ${datenew}/${monthnew}/${[yearnew]} at ${hoursend}:${minutesend} (UTC ${sign}${timezone[1]}). [Find and manage the event here](${result.htmlLink}) `, + text: `is a due event on your calendar starting from date ${date_start}/${start_month}/${start_year} at ${start_hours}:${start_minutes} (UTC ${sign}${timezone[1]}) to ${date_new}/${month_new}/${[year_new]} at ${hours_end}:${minutes_end} (UTC ${sign}${timezone[1]}). [Find and manage the event here](${result.htmlLink}) `, From 5d1f9e2cdc642d425f247b8f5d9c2e8d24158939 Mon Sep 17 00:00:00 2001 From: Gautime Date: Thu, 4 Jul 2019 04:21:12 +0530 Subject: [PATCH 35/41] Update README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index a361136..8f34e5e 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,13 @@ Integrates google calendar with your Rocket.Chat server. * Get reminders and notifications of events. * Create public events inside a room inviting all the users inside the room. +## How to use it? +* Download or clone the repository to your local system. +* Get your local Rocket.Chat server running. +* Navigate inside the folder using terminal. +* Run command `rc-apps deploy --url http://localhost:3000 --username {your_username} --password {your_password}` +* This gets the app installed in your local server, now navigate to app screen inside Options -> Administration -> Apps -> Google Calendar +* Activate the app and start using it inside any of your room! ## Quick Start Guide @@ -21,7 +28,10 @@ Integrates google calendar with your Rocket.Chat server. * `/calendar logout` : Once you are done with viewing, creating your calendar events and wants to log out of the gmail account, use this command and it will log you out and redirect to your home page. +* `/calendar quickadd {title of the event}` - This slashcommand can be used to create an event starting from time the slashcommand is called to one hour in duration. +### Feedback and Suggestions +Contribute to this repository by opening an issue if you have any feedback or suggestions for improvements or even some feature request! From ec2b5557f480995ad6281ad8bfca1bd3b43a6981 Mon Sep 17 00:00:00 2001 From: Gautime Date: Thu, 4 Jul 2019 04:57:33 +0530 Subject: [PATCH 36/41] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a6b8516..b0cb7e3 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Integrates google calendar with your Rocket.Chat server. * Navigate inside the folder using terminal. * Run command `rc-apps deploy --url http://localhost:3000 --username {your_username} --password {your_password}` * This gets the app installed in your local server, now navigate to app screen inside Options -> Administration -> Apps -> Google Calendar -* Activate the app and start using it inside any of your room! +* Activate the app and put in the credentials and start using it inside any of your room! ## Quick Start Guide From 5fcda42154ab899efad6b01bd5be5258a10b0987 Mon Sep 17 00:00:00 2001 From: Kapil Date: Thu, 4 Jul 2019 14:18:11 +0530 Subject: [PATCH 37/41] Updated changes --- helpers/GSGetter.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index ffb84df..7a1c874 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -6,20 +6,7 @@ import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from '@rocke import { SettingType } from '@rocket.chat/apps-engine/definition/settings'; import { WebhookEndpoint } from '../helpers/Webhook'; import { AppPersistence } from '../helpers/persistence'; -import { stringify } from 'querystring'; import { displayevents } from '../helpers/result'; -import { ok } from 'assert'; - -import { stringify } from 'querystring'; -import { displayevents } from '../helpers/result'; - - -enum Command { - connect = 'auth', - lgout = 'logout', - show = 'view', - make = 'create', -} enum Command { connect = 'auth', From ad4f65de9da03be168c3b02152b688f621a498e7 Mon Sep 17 00:00:00 2001 From: Kapil Date: Fri, 5 Jul 2019 15:50:59 +0530 Subject: [PATCH 38/41] Updated persistence --- helpers/persistence.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers/persistence.ts b/helpers/persistence.ts index 77dd5f6..24be567 100644 --- a/helpers/persistence.ts +++ b/helpers/persistence.ts @@ -29,7 +29,7 @@ export class AppPersistence { const user_association = new RocketChatAssociationRecord(RocketChatAssociationModel.USER, user.id); const [result] = await this.persistenceRead.readByAssociation(user_association); - return result ? (result as any).atoken.atoken : undefined; + return result ? (result as any).atoken.acess_token : undefined; } } \ No newline at end of file From 64256395bb30e8233bc00e834c0b261b32e320c3 Mon Sep 17 00:00:00 2001 From: Douglas Gubert Date: Sat, 13 Jul 2019 10:54:40 -0300 Subject: [PATCH 39/41] Fix typo on variable name --- helpers/GCResult.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helpers/GCResult.ts b/helpers/GCResult.ts index f9e7b41..564281f 100644 --- a/helpers/GCResult.ts +++ b/helpers/GCResult.ts @@ -3,7 +3,7 @@ import { HttpStatusCode, IHttp, ILogger, IRead } from '@rocket.chat/apps-engine/ import { IApiRequest } from '@rocket.chat/apps-engine/definition/api'; export class GCResults { - public acess_token: string; + public access_token: string; constructor(data?: any) { @@ -19,4 +19,4 @@ export class GCResults { return this.acess_token; } -} \ No newline at end of file +} From 61fff555462bbee63d8790e485669ed7efbd623c Mon Sep 17 00:00:00 2001 From: Douglas Gubert Date: Sat, 13 Jul 2019 10:57:09 -0300 Subject: [PATCH 40/41] Revert "Fix typo on variable name" This reverts commit 64256395bb30e8233bc00e834c0b261b32e320c3. --- helpers/GCResult.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helpers/GCResult.ts b/helpers/GCResult.ts index 564281f..f9e7b41 100644 --- a/helpers/GCResult.ts +++ b/helpers/GCResult.ts @@ -3,7 +3,7 @@ import { HttpStatusCode, IHttp, ILogger, IRead } from '@rocket.chat/apps-engine/ import { IApiRequest } from '@rocket.chat/apps-engine/definition/api'; export class GCResults { - public access_token: string; + public acess_token: string; constructor(data?: any) { @@ -19,4 +19,4 @@ export class GCResults { return this.acess_token; } -} +} \ No newline at end of file From 1cbc9447896b3ee8969277b6e32b5661a57f4379 Mon Sep 17 00:00:00 2001 From: Kapil Gautam Date: Fri, 16 Aug 2019 23:12:47 +0530 Subject: [PATCH 41/41] Google/calendar list (#5) * Fetching all calendars * Added calendar buttons * Calendars and buttons in single message * Store preferred calendar in persistence * Updated calendar list feature * Update README.md * Updated workflow * Removed logs * Updated * Google/public (#11) * Public events creation * Changed string concatenation * Creating Public events * Update GSGetter.ts * Update GSGetter.ts --- Commands/GCCommands.ts | 12 +-- GoogleCalendar.ts | 2 - README.md | 5 ++ helpers/GSGetter.ts | 167 +++++++++++++++++++++++++++++++---------- helpers/Webhook.ts | 19 +---- helpers/persistence.ts | 24 ++++-- helpers/result.ts | 22 ++---- 7 files changed, 165 insertions(+), 86 deletions(-) diff --git a/Commands/GCCommands.ts b/Commands/GCCommands.ts index a52088d..0c28c5a 100644 --- a/Commands/GCCommands.ts +++ b/Commands/GCCommands.ts @@ -1,13 +1,10 @@ import { IHttp, IModify, IPersistence, IRead } from '@rocket.chat/apps-engine/definition/accessors'; import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; import { GoogleCalendarApp } from '../GoogleCalendar'; -import { GCGetter } from '../helpers/GSGetter'; import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from '@rocket.chat/apps-engine/definition/api'; import { AppPersistence } from '../helpers/persistence'; import { IUser } from '@rocket.chat/apps-engine/definition/users'; - - export class GCCommand implements ISlashCommand { public command = 'calendar'; @@ -26,15 +23,8 @@ export class GCCommand implements ISlashCommand { const login_status = await this.app.getGCGetter().login(this.app.getLogger(), read, http, modify, context, persis); - - msg.setText('Slashcommand executed'); - // await modify.getCreator().finish(msg); - modify.getNotifier().notifyUser(context.getSender(), msg.getMessage()); - - } catch (e) { - this.app.getLogger().error('Failed sending login url', e); - //msg.setText('An error occurred when trying to send the login url:disappointed_relieved:'); + this.app.getLogger().error('Failed executing slashcommand', e); } } diff --git a/GoogleCalendar.ts b/GoogleCalendar.ts index 47f1bf0..06dab2d 100644 --- a/GoogleCalendar.ts +++ b/GoogleCalendar.ts @@ -22,7 +22,6 @@ export class GoogleCalendarApp extends App { constructor(info: IAppInfo, logger: ILogger, accessors: IAppAccessors) { super(info, logger, accessors); this.gcGetter = new GCGetter(); - //this.webhook= new WebhookEndpoint(this); } public getGCGetter(): GCGetter { @@ -81,7 +80,6 @@ export class GoogleCalendarApp extends App { i18nDescription: 'Customize_Redirect_URI', }); - await configuration.slashCommands.provideSlashCommand(new GCCommand(this)); } diff --git a/README.md b/README.md index b0cb7e3..192a889 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ Integrates google calendar with your Rocket.Chat server. * Authenticate to your gmail account from inside your Rocket.Chat. * Create your private events in your google calendar fom your Rocket.Chat using just a slashcommand. * View and update your private events using just a slashcommand. +* Create a quick event using *quickadd* slashcommand. +* View all the calendars present on your profile and can even select any one of those calendars to work with. * Get reminders and notifications of events. * Create public events inside a room inviting all the users inside the room. @@ -36,6 +38,9 @@ Integrates google calendar with your Rocket.Chat server. * `/calendar quickadd {title of the event}` - This slashcommand can be used to create an event starting from time the slashcommand is called to one hour in duration. +* `/calendar list` - Shows you the list of the calendars that are present on your user profile. For each calendar there is a button, which you can click and decide which calendar to communicate with and that calendar will be used for fetching and editing events (though this is optional, Google Calendar app uses your primary calendar by default.) + +* `/calendar invite "Title" "Date" "Starttime" "Endtime" ` - This slashcommand will create public events which will include inviting all the users present inside the room (in which command is called) to this event. All the users will receive the event invite through e-mails. They can respond to that invite and the organizer will receive their response notifications via e-mails. ### Feedback and Suggestions Contribute to this repository by opening an issue if you have any feedback or suggestions for improvements or even some feature request! diff --git a/helpers/GSGetter.ts b/helpers/GSGetter.ts index 1a2c68a..7659e45 100644 --- a/helpers/GSGetter.ts +++ b/helpers/GSGetter.ts @@ -1,10 +1,10 @@ import { HttpStatusCode, IHttp, ILogger, IRead, IHttpResponse, IModify, IPersistence } from '@rocket.chat/apps-engine/definition/accessors'; import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; -import { GCResults } from '../helpers/GCResult'; +import { MessageActionType } from '@rocket.chat/apps-engine/definition/messages/MessageActionType'; import { GoogleCalendarApp } from '../GoogleCalendar'; -import { WebhookEndpoint } from '../helpers/Webhook'; import { AppPersistence } from '../helpers/persistence'; import { displayevents } from '../helpers/result'; +import { IUser } from '@rocket.chat/apps-engine/definition/users'; enum Command { connect = 'auth', @@ -12,11 +12,15 @@ enum Command { show = 'view', make = 'create', quick = 'quickadd', + calendar = 'list', + config = 'configure', + public = 'invite', +} export class GCGetter { - private readonly SCOPES = "https://www.googleapis.com/auth/calendar"; + private readonly SCOPES = 'https://www.googleapis.com/auth/calendar'; private readonly urli = 'https://accounts.google.com/o/oauth2/v2/auth?'; private res; private readonly app: GoogleCalendarApp; @@ -32,9 +36,6 @@ export class GCGetter { const persistence = new AppPersistence(persis, read.getPersistenceReader()); const id = await persistence.connectUserToClient(client_id, context.getSender()); - - let signedin: boolean = false; - const message = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); const [parameter] = context.getArguments(); @@ -42,11 +43,20 @@ export class GCGetter { switch (parameter) { case (Command.connect): - const response = (`${this.urli}client_id=${client_id}&redirect_uri=${redirect}/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=https://www.googleapis.com/auth/calendar&prompt=consent&access_type=offline&response_type=code`); + const response = (`${this.urli}client_id=${client_id}&redirect_uri=${redirect}/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook&scope=${this.SCOPES}&prompt=consent&access_type=offline&response_type=code`); try { - message.setText(response); + message.addAttachment({ + text: 'Click the button to authenticate to your Gmail account.', + actions: [{ + type: MessageActionType.BUTTON, + text: 'Authenticate', + msg_in_chat_window: false, + url: `${response}`, + }], + }); + await modify.getCreator().finish(message); } catch (e) { this.app.getLogger().error('Failed sending login url', e); @@ -58,12 +68,18 @@ export class GCGetter { break; case (Command.lgout): - - // const mesg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); - const logresponse = `https://www.google.com/accounts/Logout?continue=${redirect}`; + const logresponse = `https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=${redirect}`; try { - message.setText(logresponse); + message.addAttachment({ + text: 'Click the button to logout your Gmail account.', + actions: [{ + type: MessageActionType.BUTTON, + text: 'Logout', + msg_in_chat_window: false, + url: `${logresponse}`, + }], + }); await modify.getCreator().finish(message); } catch (e) { this.app.getLogger().error('Failed sending logout url', e); @@ -74,23 +90,20 @@ export class GCGetter { } - const atoken = await persistence.getAT(context.getSender()); - - // console.log('This is the access token inside GCGetter:', atoken); + const atoken = await persistence.get_access_token(context.getSender()); break; case (Command.show): - const new_token = await persistence.getAT(context.getSender()); + const new_token = await persistence.get_access_token(context.getSender()); const dat = new Date(); const minimum_date = dat.toISOString(); const url = `https://www.googleapis.com/calendar/v3/calendars/primary/events?key=${api_key}&showDeleted=false&timeMin=${minimum_date}`; - const api_response = await http.get(url, { headers: { 'Authorization': `Bearer ${new_token}`, } }); + const api_response = await http.get(url, { headers: { Authorization: `Bearer ${new_token}` } }); - for (var i = 0; i < api_response.data.items.length; i++) { - // console.log( newresponse.data.items[i].summary); + for (let i = 0; i < api_response.data.items.length; i++) { await displayevents(api_response.data.items[i], modify, context); } @@ -99,27 +112,19 @@ export class GCGetter { case (Command.make): - const access_token = await persistence.getAT(context.getSender()); + const access_token = await persistence.get_access_token(context.getSender()); const params = context.getArguments().join(' '); const array = params.split("\""); const create_url = `https://www.googleapis.com/calendar/v3/calendars/primary/events?key=${api_key}`; - console.log('Create event array elements are these:', array[1], array[3]); const datetime = array[3] + 'T' + array[5]; const date = new Date(datetime); - //const starttime = new Date(date.getTime() - date.getTimezoneOffset() * 60000); const start_datetime = date.toISOString(); - const e_date = array[3] + 'T' + array[7]; const end_date = new Date(e_date); const end_datetime = end_date.toISOString(); - - - // console.log('Start date and time in ISO format is: ',startdatetime,'end date time:',enddatetime); - const create_api_response = await http.post(create_url, { headers: { 'Authorization': `Bearer ${access_token}`, }, data: { 'summary': `${array[1]}`, 'end': { 'dateTime': `${end_datetime}`, }, 'start': { 'dateTime': `${start_datetime}` } } }); - console.log('This is the create event request response: ', create_api_response); - if (create_api_response.statusCode == HttpStatusCode.OK && create_api_response.data.status == "confirmed") { //console.log('Event created wohoooooo!!!'); + if (create_api_response.statusCode == HttpStatusCode.OK && create_api_response.data.status == "confirmed") { try { message.addAttachment({ @@ -132,8 +137,7 @@ export class GCGetter { this.app.getLogger().error('Failed creating events', e); message.setText('An error occurred when sending the event creation as message :disappointed_relieved:'); } - } - else { + } else { console.log('This is the error message:', create_api_response.data.error.message); try { @@ -155,20 +159,107 @@ export class GCGetter { const title = context.getArguments().join(' '); const title_new = title.split('\"'); - //const fintitle = titlenew.; - const token = await persistence.getAT(context.getSender()); + const token = await persistence.get_access_token(context.getSender()); const quick_url = `https://www.googleapis.com/calendar/v3/calendars/primary/events/quickAdd?key=${api_key}&text=${title_new[1]}`; - const quick_api_response = await http.post(quick_url, { headers: { 'Authorization': `Bearer ${token}`, } }); - console.log('This is the quick-add response', quick_api_response); - if (quick_api_response && quick_api_response.statusCode == HttpStatusCode.OK) { + const quick_api_response = await http.post(quick_url, { headers: { Authorization: `Bearer ${token}`, } }); + if (quick_api_response && quick_api_response.statusCode === HttpStatusCode.OK) { // const msg = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); message.setText('Quickadd event succcessfully created!'); await modify.getCreator().finish(message); } break; - } - } + case (Command.calendar): + + const list_token = await persistence.get_access_token(context.getSender()); + const list_url = `https://www.googleapis.com/calendar/v3/users/me/calendarList?key=${api_key}`; + const list_api_response = await http.get(list_url, { headers: { Authorization: `Bearer ${list_token}`, } }); + let current_calendar = await persistence.get_preferred_calendar_id(context.getSender()); + (list_api_response.data.items as Array).forEach((value) => { + + if (current_calendar == value.id || value.primary && current_calendar == undefined) { + message.addAttachment({ + color: value.backgroundColor, + text: value.summary, + }); + } else { + message.addAttachment({ + color: value.backgroundColor, + text: value.summary, + actions: [{ + type: MessageActionType.BUTTON, + text: 'Set as default', + msg_in_chat_window: true, + msg: `/calendar configure ${value.id}`, + }], + }); + } + }); + await modify.getCreator().finish(message); + break; + + case (Command.config): + + const calendar = context.getArguments(); + const id = await persistence.connect_user_to_calendar_id(calendar[1], context.getSender()); + const final_calendar_id = await persistence.get_preferred_calendar_id(context.getSender()); + break; + + case (Command.public): + + const user_id = await read.getRoomReader().getMembers(context.getRoom().id); + let email_ids: Array = user_id; + let mapping: Array = []; + + for (let index = 0; index < user_id.length; index++) { + email_ids[index] = user_id[index].emails[0].address; + } + await modify.getCreator().finish(message); + const invite_token = await persistence.get_access_token(context.getSender()); + const invite_parameters = context.getArguments().join(' '); + const invite_array = invite_parameters.split("\""); + const invite_url = `https://www.googleapis.com/calendar/v3/calendars/primary/events?key=${api_key}&sendUpdates=all`; + + const invite_datetime = invite_array[3] + 'T' + invite_array[5]; + const invite_date = new Date(invite_datetime); + const invitestart_datetime = invite_date.toISOString(); + const invite_e_date = invite_array[3] + 'T' + invite_array[7]; + const inviteend_date = new Date(invite_e_date); + const invite_end_datetime = inviteend_date.toISOString(); + + for (let index = 0; index < email_ids.length; index++) { + mapping.push({ email: email_ids[index] }); + } + const invite_api_response = await http.post(invite_url, { headers: { Authorization: `Bearer ${invite_token}`, }, data: { 'summary': `${invite_array[1]}`, 'end': { 'dateTime': `${invite_end_datetime}`, }, 'attendees': mapping, 'start': { 'dateTime': `${invitestart_datetime}` }, } }); + if (invite_api_response.statusCode === HttpStatusCode.OK && invite_api_response.data.status === 'confirmed') { + try { + message.addAttachment({ + text: `Event has been created. Find the event at [${invite_api_response.data.summary}](${invite_api_response.data.htmlLink}) `, + + + }); + await modify.getCreator().finish(message); + } catch (e) { + this.app.getLogger().error('Failed creating events', e); + message.setText('An error occurred when sending the event creation as message :disappointed_relieved:'); + } + } else { + try { + message.addAttachment({ + + text: `Event could not be created. It encountered the error: ${invite_api_response.data.error.message}. Please try again. `, + + + }); + await modify.getCreator().finish(message); + } catch (e) { + this.app.getLogger().error('Failed creating events', e); + message.setText('An error occurred when sending the event creation as message :disappointed_relieved:'); + } + } + break; + } + } } diff --git a/helpers/Webhook.ts b/helpers/Webhook.ts index 239f86b..662963c 100644 --- a/helpers/Webhook.ts +++ b/helpers/Webhook.ts @@ -1,18 +1,13 @@ import { HttpStatusCode, IHttp, ILogger, IModify, IPersistence, IRead } from '@rocket.chat/apps-engine/definition/accessors'; import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from '@rocket.chat/apps-engine/definition/api'; -import { RocketChatAssociationModel, RocketChatAssociationRecord } from '@rocket.chat/apps-engine/definition/metadata'; -import { GCGetter } from './GSGetter'; -import { ISlashCommand, ISlashCommandPreview, ISlashCommandPreviewItem, SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; import { GCResults } from '../helpers/GCResult'; -import { IUser } from '@rocket.chat/apps-engine/definition/users'; import { AppPersistence } from '../helpers/persistence'; - export class WebhookEndpoint extends ApiEndpoint { public path = 'webhook'; - private readonly urli = 'http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook'; public tokenid; + private readonly urli = 'http://localhost:3000/api/apps/public/c759c4f1-a3c1-4202-8238-c6868633ed87/webhook'; public async get(request: IApiRequest, endpoint: IApiEndpointInfo, read: IRead, modify: IModify, http: IHttp, persist: IPersistence): Promise { @@ -20,8 +15,6 @@ export class WebhookEndpoint extends ApiEndpoint { const secret = await read.getEnvironmentReader().getSettings().getValueById('calendar_secret_key'); const api_key = await read.getEnvironmentReader().getSettings().getValueById('calendar_apikey'); - //logger.debug('response from first request is:', request.params);` - const auth_code = request.query.code; const url = 'https://www.googleapis.com/oauth2/v4/token'; const new_response = await http.post(url, { data: { 'code': `${auth_code}`, 'client_id': `${client_id}`, 'client_secret': `${secret}`, 'redirect_uri': `${this.urli}`, 'grant_type': 'authorization_code', } }); @@ -37,17 +30,13 @@ export class WebhookEndpoint extends ApiEndpoint { const atoken = acess_token; const persistence = new AppPersistence(persist, read.getPersistenceReader()); const user_id = await persistence.getuid(client_id); - const id = await persistence.connectUserToAT(acess_token, user_id); - + const id = await persistence.connect_user_to_token(acess_token, user_id); if (acess_token) { - //location.assign('http://localhost:3000/home'); return this.success('
Sign-in successful! Please close this window/tab and continue using!
'); - } - else + } else { throw new Error('Sign-in not successful'); - // return auth_cod - //return this.success(); + } } } diff --git a/helpers/persistence.ts b/helpers/persistence.ts index 24be567..93abf1a 100644 --- a/helpers/persistence.ts +++ b/helpers/persistence.ts @@ -1,8 +1,7 @@ import { RocketChatAssociationModel, RocketChatAssociationRecord } from '@rocket.chat/apps-engine/definition/metadata'; -import { IPersistence, IPersistenceRead } from '@rocket.chat/apps-engine/definition/accessors'; +import { IPersistence, IPersistenceRead, IRead, IRoomRead, IHttp, IModify } from '@rocket.chat/apps-engine/definition/accessors'; import { IUser } from '@rocket.chat/apps-engine/definition/users'; - export class AppPersistence { constructor(private readonly persistence: IPersistence, private readonly persistenceRead: IPersistenceRead) { } @@ -19,17 +18,32 @@ export class AppPersistence { const [result] = await this.persistenceRead.readByAssociations([client_association]); return result ? (result as any).uid : undefined; } - public async connectUserToAT(atoken: any, user: string): Promise { + public async connect_user_to_token(atoken: any, user: string): Promise { const user_association = new RocketChatAssociationRecord(RocketChatAssociationModel.USER, user); await this.persistence.updateByAssociations([user_association], { atoken }, true); } - public async getAT(user: IUser): Promise { + public async get_access_token(user: IUser): Promise { const user_association = new RocketChatAssociationRecord(RocketChatAssociationModel.USER, user.id); const [result] = await this.persistenceRead.readByAssociation(user_association); return result ? (result as any).atoken.acess_token : undefined; } -} \ No newline at end of file + + public async connect_user_to_calendar_id(calendar: any, user: IUser): Promise { + const user_association = new RocketChatAssociationRecord(RocketChatAssociationModel.USER, user.id); + const calendarid = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, 'selected calendar'); + await this.persistence.updateByAssociations([user_association, calendarid], { calendar }, true); + + } + + public async get_preferred_calendar_id(user: IUser): Promise { + + const user_association = new RocketChatAssociationRecord(RocketChatAssociationModel.USER, user.id); + const calendarid = new RocketChatAssociationRecord(RocketChatAssociationModel.MISC, 'selected calendar'); + const [result] = await this.persistenceRead.readByAssociations([user_association, calendarid]); + return result ? (result as any).calendar : 'primary'; + } +} diff --git a/helpers/result.ts b/helpers/result.ts index 2415d2e..17c6338 100644 --- a/helpers/result.ts +++ b/helpers/result.ts @@ -1,10 +1,9 @@ -import { IModify } from "@rocket.chat/apps-engine/definition/accessors"; +import { IModify } from '@rocket.chat/apps-engine/definition/accessors'; import { SlashCommandContext } from '@rocket.chat/apps-engine/definition/slashcommands'; export async function displayevents(result: any, modify: IModify, context: SlashCommandContext): Promise { - console.log('This is inside result function'); const summary = result.summary as string; const start_time = result.start.dateTime as string; let end_time = result.end.dateTime as string; @@ -12,24 +11,23 @@ export async function displayevents(result: any, modify: IModify, context: Slash const start_date = new Date(start_time); const start_year = start_date.getFullYear(); const start_month = (start_date.getMonth() + 1); - const date_start = start_date.getDate();//prints expected format. + const date_start = start_date.getDate(); const start_hours = start_date.getHours(); const start_minutes = start_date.getMinutes(); const short_cut_date = new Date(end_time); const year_new = short_cut_date.getFullYear(); const month_new = (short_cut_date.getMonth() + 1); - const date_new = short_cut_date.getDate();//prints expected format. + const date_new = short_cut_date.getDate(); const hours_end = short_cut_date.getHours(); const minutes_end = short_cut_date.getMinutes(); let timezone = start_time.split('+', 2); let sign; if (timezone) { sign = '+'; - } - else { + } else { timezone = start_time.split('-', 2); - sign = '-' + sign = '-'; } const builder = modify.getCreator().startMessage().setSender(context.getSender()).setRoom(context.getRoom()); try { @@ -37,17 +35,11 @@ export async function displayevents(result: any, modify: IModify, context: Slash title: { value: summary, }, - text: `is a due event on your calendar starting from date ${date_start}/${start_month}/${start_year} at ${start_hours}:${start_minutes} (UTC ${sign}${timezone[1]}) to ${date_new}/${month_new}/${[year_new]} at ${hours_end}:${minutes_end} (UTC ${sign}${timezone[1]}). [Find and manage the event here](${result.htmlLink}) `, - - - - + text: `is a due event on your calendar starting from date ${date_start}/${start_month}/${start_year} at ${start_hours}:${start_minutes}(UTC ${sign}${timezone[1]}) to ${date_new}/${month_new}/${[year_new]} at ${hours_end}:${minutes_end} (UTC ${sign}${timezone[1]}). [Find and manage the event here](${result.htmlLink}) `, }); await modify.getCreator().finish(builder); } catch (e) { this.app.getLogger().error('Failed displaying events', e); builder.setText('An error occurred when sending the events as message :disappointed_relieved:'); } - - -} \ No newline at end of file +}