googleapis / google-api-nodejs-client

Google's officially supported Node.js client library for accessing Google APIs. Support for authorization and authentication with OAuth 2.0, API Keys and JWT (Service Tokens) is included.
https://googleapis.dev/nodejs/googleapis/latest/
Apache License 2.0
11.35k stars 1.92k forks source link

event insert NodeJs quickstart example not working #1919

Closed kdw2060 closed 4 years ago

kdw2060 commented 4 years ago

Hi,

First I've set up the NodeJs quickstart example: https://developers.google.com/calendar/quickstart/node The listing of existing events works.

Then I added this example code: https://developers.google.com/calendar/v3/reference/events/insert#examples (nodeJs example) and changed the SCOPE as instructed to generate a new token.json

This first gives me a 'calendar is not defined' error on the insert function. So I've adapted the example code to:

function insertEvent(auth, calId, event) {
  const calendar = google.calendar({version: 'v3', auth});
  calendar.events.insert({
    auth: auth,
    calendarId: calId,
    resource: event,
  }, function(err, event) {
...

Then I'm calling my insertEvent function with the necessary parameters. This works, but now in stead of the 'calendar not defined' error I get a 'login required' error.

Tried to fix that by adding

authorize(JSON.parse(content), insertEvent);

to this bit of the quickstart example:

fs.readFile('credentials.json', (err, content) => {
  if (err) return console.log('Error loading client secret file:', err);
  // Authorize a client with credentials, then call the Google Calendar API.
  authorize(JSON.parse(content), listEvents);
  authorize(JSON.parse(content), insertEvent);
});

But that doesn't fix the issue and throws yet another error: 'Missing required parameters: calendarIdundefined'

Any ideas on how to get the insert function to work?

bcoe commented 4 years ago

@kdw2060 could you provide a more thorough example of the code you're running, including both the request you're making, and how you're instantiating the GoogleAuth client? It's hard to tell from these snippets exactly what might be going on.

kdw2060 commented 4 years ago

Hi @bcoe thanks for having a look. It's basically just the quickstart example from Google's documentation with a simple function added to insert an event in a specific calendar. This is the full code:

const fs = require('fs');
const readline = require('readline');
const {google} = require('googleapis');

const calId = {calenderId}  //removed actual id for privacy reasons

// If modifying these scopes, delete token.json.
const SCOPES = ['https://www.googleapis.com/auth/calendar'];
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
const TOKEN_PATH = 'token.json';

// Load client secrets from a local file.
fs.readFile('credentials.json', (err, content) => {
  if (err) return console.log('Error loading client secret file:', err);
  // Authorize a client with credentials, then call the Google Calendar API.
  authorize(JSON.parse(content), listEvents);
  //authorize(JSON.parse(content), insertEvent);
});

/**
 * Create an OAuth2 client with the given credentials, and then execute the
 * given callback function.
 * @param {Object} credentials The authorization client credentials.
 * @param {function} callback The callback to call with the authorized client.
 */
function authorize(credentials, callback) {
  const {client_secret, client_id, redirect_uris} = credentials.installed;
  const oAuth2Client = new google.auth.OAuth2(
      client_id, client_secret, redirect_uris[0]);

  // Check if we have previously stored a token.
  fs.readFile(TOKEN_PATH, (err, token) => {
    if (err) return getAccessToken(oAuth2Client, callback);
    oAuth2Client.setCredentials(JSON.parse(token));
    callback(oAuth2Client);
  });
}

/**
 * Get and store new token after prompting for user authorization, and then
 * execute the given callback with the authorized OAuth2 client.
 * @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
 * @param {getEventsCallback} callback The callback for the authorized client.
 */
function getAccessToken(oAuth2Client, callback) {
  const authUrl = oAuth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: SCOPES,
  });
  console.log('Authorize this app by visiting this url:', authUrl);
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  rl.question('Enter the code from that page here: ', (code) => {
    rl.close();
    oAuth2Client.getToken(code, (err, token) => {
      if (err) return console.error('Error retrieving access token', err);
      oAuth2Client.setCredentials(token);
      // Store the token to disk for later program executions
      fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
        if (err) return console.error(err);
        console.log('Token stored to', TOKEN_PATH);
      });
      callback(oAuth2Client);
    });
  });
}

/**
 * Lists the next 10 events on the user's primary calendar.
 * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
 */
function listEvents(auth) {
  const calendar = google.calendar({version: 'v3', auth});
  calendar.events.list({
    calendarId: calId,
    timeMin: (new Date()).toISOString(),
    maxResults: 10,
    singleEvents: true,
    orderBy: 'startTime',
  }, (err, res) => {
    if (err) return console.log('The API returned an error: ' + err);
    const events = res.data.items;
    if (events.length) {
      console.log('Upcoming 10 events:');
      events.map((event, i) => {
        const start = event.start.dateTime || event.start.date;
        console.log(`${start} - ${event.summary}`);
      });
    } else {
      console.log('No upcoming events found.');
    }
  });
}

function insertEvent(auth, calId, wedstrijd) {
  const calendar = google.calendar({version: 'v3', auth});
  // line above is not in documentation but without it you get 'no calendar defined'
  calendar.events.insert({
    auth: auth,
    calendarId: calId,
    resource: wedstrijd,
  }, function(err, event) {
    if (err) {
      console.log('There was an error contacting the Calendar service: ' + err + err.code);
      return;
    }
    console.log('Event created: %s', event.htmlLink);
  });
}

var wedstrijd = {
  'summary': 'Testwedstrijd',
  'location': 'BER 2 - Sporthal Het Rooi 2, Berchem',
  'start': {
    'dateTime': '2020-01-03T18:00:00+01:00',
    'timeZone': 'Europe/Brussels',
  },
  'end': {
    'dateTime': '2020-01-03T19:30:00+01:00',
    'timeZone': 'Europe/Brussels',
  },
};

insertEvent(calId, wedstrijd);

I've tried several edits in the insertEvent function for the auth parameter, but can't find a working version.

bcoe commented 4 years ago

@kdw2060 it looks like you're not passing the auth instance to insertEvent, I think you'd want something more like this:

/**
 * Create an OAuth2 client with the given credentials, and then execute the
 * given callback function.
 * @param {Object} credentials The authorization client credentials.
 * @param {function} callback The callback to call with the authorized client.
 */
function authorize(callback) {
  // Load client secrets from a local file.
  const content = fs.readFileSync('credentials.json', 'utf8');
  const credentials = JSON.parse(content);
  // Check if we have previously stored a token.
  fs.readFile(TOKEN_PATH, (err, token) => {
    if (err) return getAccessToken(oAuth2Client, callback);
    oAuth2Client.setCredentials(JSON.parse(token));
    callback(oAuth2Client);
  });
});

authorize((auth) => {
  insertEvent(auth, calId, wedstrijd);
});

☝️ the calendar methods need to accept an auth object, which they then use to make requests. In your example code you're calling callback(oAuth2Client);, this would result in an auth client being set but no calId or wedstrijd.

kdw2060 commented 4 years ago

thanks @bcoe , but still no succes I'm afraid. The authorize function throws the error credentials is not defined now. I see you adapted the authorize function somewhat, running it like that however doesn't work because oAuth2Client is then undefined.

Leaving the lines you removed:

const {client_secret, client_id, redirect_uris} = credentials.installed;
  const oAuth2Client = new google.auth.OAuth2(
      client_id, client_secret, redirect_uris[0]);

solves that issue but then throws the mentioned error.

bcoe commented 4 years ago

@kdw2060 could you provide a gist with the code in its current form?

kdw2060 commented 4 years ago

closing, found a working example here: https://github.com/murilloves/nodejs-google-calendar-crud