When watching for changes to a collection of events on a given calendar, how often do I need to make a watch request?
Where would I put my code to make a watch request? Does it only need to be done once?
My code below gets an access token and makes a post to create a watch channel, however I'm not sure where to host the code or how often I need to run it:
let { google } = require("googleapis");
let functions = require("firebase-functions");
let privatekey = require("./config.json");
let axios = require("axios");
let jwt = new google.auth.JWT(
privatekey.client_email,
null,
privatekey.private_key,
["https://www.googleapis.com/auth/calendar"]
);
const token = await jwt.authorize();
let headers = {
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/json;charset=UTF-8",
Authorization: token.token_type + " " + token.access_token
};
let data = {
id: randomId,
type: "web_hook",
address: "https://rguc-calendars.firebaseapp.com/notifications",
params: {
ttl: 3600
}
};
axios
.post(
"https://www.googleapis.com/calendar/v3/calendars/thirdyear#rguc.co.uk/events/watch",
data,
{ headers }
)
.then(function(response) {
// success
})
.catch(function(error) {
// error
});
push notifications
The Google Calendar API provides push notifications that let you watch
for changes to resources. You can use this feature to improve the
performance of your application. It allows you to eliminate the extra
network and compute costs involved with polling resources to determine
if they have changed. Whenever a watched resource changes, the Google
Calendar API notifies your application.
Register the domain of your receiving URL.
For example, if you plan to use https://example.com/notifications as your receiving URL, you need to register https://example.com.
Set up your receiving URL, or "Webhook" callback receiver.
This is an HTTPS server that handles the API notification messages that are triggered when a resource changes.
Set up a notification channel for each resource endpoint you want to watch.
A channel specifies routing information for notification messages. As part of the channel setup, you identify the specific URL where you want to receive notifications. Whenever a channel's resource changes, the Google Calendar API sends a notification message as a POST request to that URL.
Once you have set up the watch google will notify you when ever there is a change you wont have to call it again.
Related
I'm trying to work on a Nuxt SSR frontend that uses a Django backend with Session Authentication.
I would like to have some SSR pages as well as client rendered pages in my frontend, so i'm using Universal mode.
The problem is that i did not find a working approach to check if a user is authenticated before loading a page, so i can't restrict pages to anonymous users. In order to check if a user is authenticated, Django will check if the request's headers contain a cookie, and according to that return if the user is authenticated or not.
Here is what i tried:
1) Middleware
export default async function ({context, redirect}) {
axios.defaults.withCredentials = true;
return axios({
method: 'get',
url: 'http://127.0.0.1:8000/checkAuth',
withCredentials: true,
}).then(function (response) {
//Redirect if user is authenticated
}).catch(function (error) {
console.log(error)
});
}
Here i'm sending a request to my backend to check if the user is authenticated. The problem is that the middleware is executed from server side, which means there will never be any cookie in the request, even if the user is authenticated. This means that every time i refresh the page, according to the middleware the user is always anonymous, even when the user is authenticated.
2) Plugin
export default function (context, inject) {
if (process.client){
console.log('client')
return axios({
method: 'get',
url: 'http://127.0.0.1:8000/checkAuth',
withCredentials: true,
}).then(function (response) {
//IF AUTHENTICATED, REDIRECT
context.redirect('/')
}).catch(function (error) {
console.log(error)
});
} else {
console.log('server')
}
}
Here i'm trying the same but with a plugin, and i'm "forcing" the plugin to check if the user is authenticated on the backend only when the plugin executes from client side. This works, cookies are sent in the headers and Django receives the cookie, but the problem with this solution is that Nuxt doesn't allow redirecting to other pages from a plugin (https://github.com/nuxt/nuxt.js/issues/4491).
3) Using beforeMount() in Vue
I tried to do that using beforeMount() from my Vue pages, but the problem is that since it will execute AFTER idration, the page will be loaded and after 1/2 seconds the redirect happens, which is kind of ugly.
Is it possible that there isn't a way to do this? Any kind of advice is appreciated
EDIT: the problem is not that i don't know how to code this, the problem is that when Nuxt sends a request to my backend from the server side middleware, the request will not contain any cookie, and because of this my Django backend cannot check the session cookie, which means that the backend cannot check whether or not the user is authenticated. The same code works when the middleware is executed from client side (if i navigate directly to the page instead of refreshing), because the request will contain the cookies.
I'm trying to understand if this is normal or not, but this could be an issue with Nuxt.
I know this a year old question and it was probably about nuxt 2, now nuxt 3 is out and running and I found my self with the same problem and here is how I solved it, just in case someone stumble here just like I did.
With Nuxt 3 server side you can use useFetch with the options headers: useRequestHeaders(['cookie'])
const { data, error, pending, refresh } = await useFetch(api.auth,
{
credentials: "include",
headers: useRequestHeaders(['cookie'])
}
);
There are a few issues you need to be aware of:
_ The cache, if you perform the same request with the same parameters it will return the same cached response (it won't even call the end point API). Try to use the key option with different values or the returned refresh method and check the doc "Data fetching" for more info.
_ The cookies, any cookie generate server side won't be shared with the client side, this means if the API generate a new token or session cookie on server side the browser won't receive those cookies and may generate new ones, this may get you in some 400 - bad request if you use session with CSRF, check this issue for more info.
I do have a working middleware with this
export default ({ redirect, store }) => {
if (store?.$auth?.$state?.loggedIn) {
redirect('https://secure.url')
} else {
redirect('https://login.please')
}
})
I am learning TestCafe and am trying to create an account on a website and then logging in to Gmail to find the activation link. When I try to do this I just get a browser isn't secure message when I get to the part to enter a password. How do I get Gmail to trust TestCafe?
While you might succeed in doing so, this is not a good approach because:
it's slow doing this via GUI
it's britle because selectors will likely change, and you have no control over Google email selectors, so you won't even know if they change them
A better approach wuld be to use a service like Mailosaur where you can create an account and receive emails that you can later query via an API. Instead of doing a whole e2e flow over GUI, you request an email on Mailosaur's API, and if such an email exists, you'll receive a response you can parse and check for various things.
I've done this in the past, you can see my post here: https://sqa.stackexchange.com/questions/40427/automating-verification-of-sent-email-sms-messages/45721#45721 It's exactly Mailosaur and Testcafe (plus it requires axios as a package), so it seems to be what you're looking for.
To add the same code here:
import config from '../config';
import { customAlphabet } from 'nanoid';
import axios from 'axios';
import Newsletter from '../Objects/newsletter';
async function request (reqObject) {
try {
return await axios(reqObject);
} catch (error) {
console.error(error);
}
}
function serverId () {
return process.env.MAILOSAUR_SERVER_ID;
}
function mailosaurFullEmail (id) {
return (id ? id : nanoid()) + '.' + serverId()
+ '#' + config.mailosaurDomain;
}
fixture `Newsletter`
.page(baseUrl);
test
('Sign Up For Newsletter', async t => {
const id = (customAlphabet('1234567890', 10))();
await t
.typeText(Newsletter.newsEmailInput, mailosaurFullEmail(id))
.click(Newsletter.consent)
.click(Newsletter.sendButton);
let res = await request({
method: 'POST',
url: config.mailosaurUrlEmail + serverId(),
headers: {
'Authorization': 'Basic '
+ Buffer.from(process.env.MAILOSAUR_API_KEY)
.toString('base64'),
'Content-Type': 'application/json'
},
data: {
sentTo: mailosaurFullEmail(id)
}
});
await t
.expect(res.status).eql(200);
});
and it requires some config values:
{
"mailosaurUrlEmail": "https://mailosaur.com/api/messages/await?server=",
"mailosaurDomain": "mailosaur.io"
}
This is definitely much better, but it still has some limitations:
Mailosaur's API can still change, so it won't be exactly without any maintenance
it assumes that an email is sent immediately after a user action (newsletter in my case), but that might be far from reality in many situations such as when emails are sent to a queue where it can easily take several minutes to send an email
If you absolutely have to do it via Gmail, you will still be better off looking at their API that should allow you to search and query email messages as well.
There is an issue related to the Google login. You can try turning on the "Allow less secure apps" Google account setting to workaround this issue. Please note that this setting is available for the disabled 2-Step Verification.
I have created a simple express server and added a /slack/receive route to handle webhook requests from the Slack events API:
// routes.js (which is used by my app defined in server.js)
...
let slack = require('./controllers/slack');
router.post('/slack/receive', slack.receive);
...
I then use Botkit to create a simple Slack application:
// controllers/slack.js
'use strict';
const logger = require('../config/winston');
// initialise firebase storage for botkit
const admin = require('firebase-admin');
var serviceAccount = require('../config/firebase.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
var db = admin.firestore();
db.settings({
timestampsInSnapshots: true
})
// initialise botkit for slack
const botkit = require('botkit');
const controller = botkit.slackbot({
storage: require('botkit-storage-firestore')({ database: db }),
clientId: process.env.SLACK_CLIENT_ID,
clientSecret: process.env.SLACK_CLIENT_SECRET,
clientSigningSecret: process.env.SLACK_SIGNING_SECRET,
redirectUri: process.env.SLACK_REDIRECT,
disable_startup_messages: true,
send_via_rtm: false,
debug: true,
scopes: ['bot', 'chat:write:bot'],
})
controller.hears('Hello', 'direct_mention,direct_message', (bot, message) => {
logger.info(message);
bot.reply(message, 'I heard a message!');
})
exports.receive = (req, res, next) => {
res.sendStatus(200);
logger.debug(req.body);
controller.handleWebhookPayload(req, res);
};
The server initialises correctly, but as soon as the slack webhook receives a request the following error happens:
Could not load team while processing webhook: Error: could not find team T5VDRMWKX
at E:\Documents\upper-revolutions\node_modules\botkit\lib\SlackBot.js:169:24
at firebaseRef.doc.get.then.catch.err (E:\Documents\upper-revolutions\node_modules\botkit-storage-firestore\src\index.js:86:13)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:118:7)
So far I have found that:
Having/not having storage in the botkit slackbot makes no difference
The error happens within the handleWebhookPayload method as code within controller.hears() does not get executed
This error occurs because botkit needs some form of storage where it can store all the teams (channels and users too) and retrive it later on.
So, When your method handleWebhookPayload gets executed it calls another method called
findAppropriateTeam that will query for the specified team record in the storage provided by you (It might be mongoDB or a JSON file or other). The error is saying that you do not have any record in the storage with the id provided.
So this might implicate two things:
You did not provide a storage for botkit to work
You did not save the team id in the storage
The solution to the first problem is quite simple. You just need to install mongodb in your machine and then pass to botkit the MONGO_URL.
NOTE: I see that you are using the botkit simple storage and this might be the problem since I also have experieced some troubles with this kind of storage not saving records.
const controller = botkit.slackbot({
storage: 'mongodb//localhost:27017:/yourdb',
})
//OR
const controller = botkit.slackbot({
storage: process.env.MONGO_URL,
})
The possible solution to the second problem:
I will assume you are using botkit locally, so you must be using some tunneling like ngrok or localtunnel. In that case make sure:
You provided the redirect URL to Slack (Ex, https://your_url/oauth)
You accessed the https://your_url/login page
Botkit saves your team id on the provided storage when you access the /login route and authorizes the app. So if you skipped that part then botkit won't save your team id and therfore will throw an error when you receive events later on.
Check this like [https://github.com/howdyai/botkit/issues/938] for discutions on the topic
I hope this helps!
I have a little problem with my application.
My architecture:
Angular 6 (front)
NodeJS + Express + MongoDB (back)
There is a part, in my NodeJS application, that communicates with a REST API.
When an user clicks on button on the Angular WebSite, I send a request to Express.
In my Express application, I send another request to the API to retrieve information.
But this process takes a lot of time. My request timeout
What is the best solution to keep my process working after the Express reply has been sent?
Should I do otherwise?
Assuming the problem is with timeout, you can increase the default timeout:
You may set the timeout either globally for entire server. Read more here:
var server = app.listen(app.get('port'), function() {
//Server is running
});
server.timeout = 1000; //1000 is one second.
or just for specific route. Read more here:
app.post('/xxx', function (req, res) {
req.setTimeout(500000);
});
You can also change the timeout for the other API request you are making. Read more here
//Assuming you are using request module.
var options = {
url: 'http://url',
timeout: 120000
}
request(options, function(err, resp, body) {});
My react web application uses axios to make an API post request.
The API needs a parameter called token for each post request.
Is there a way to always add the token parameter for each post request I do, so I don't have to add it manually every time, and where to save this token in a secure location?
I feel what I do now is a bit redundant. Example:
axios.post('apiUrl.com', {
token: 'abcdefg12345678',
userId: 1
}).then(() => {//do something});
Use axios interceptors. If you add a request interceptor, you can make a change (add token) to each request:
axios.interceptors.request.use(function(config) {
config.data = config.data || {};
config.data.token = 'abcdefg12345678';
return config;
});