¿Cómo interactuar con Google Agenda?

Resuelto
emrh Mensajes publicados 439 Estado Miembro -  
emrh Mensajes publicados 439 Estado Miembro -

Hola a todos,

Me gustaría añadir a mi aplicación web la posibilidad de interactuar con Google Calendar.
He visto uno o dos tutoriales y luego la documentación de Google. Contacté a Ionos, mi hosting, para decirle que quería acceder por ssh a mi servidor para instalar Composer, pero como estoy en un hosting compartido no será posible. Sin embargo, me explicó que podía desarrollar en local y luego transferir mis archivos... ¡Y empecé a hacer eso!

Por lo tanto, seguí las indicaciones dadas aquí: https://developers.google.com/calendar/api/quickstart/php

Lanzo php quickstart.php y copio la dirección obtenida en mi navegador Chrome, y ahí, Google me informa: "Error 403 : access_denied The developer hasn’t given you access to this app. It’s currently being tested and it hasn’t been verified by Google".

Estoy casi seguro de que el problema proviene del "URI de redirección autorizado" ingresado en la API de Google Calendar... Pero no sé qué poner además de la dirección de mi sitio web!
(Problema visto aquí también :
https://stackoverflow.com/questions/34707227/google-client-api-missing-require-parameter-redirect-uri
pero no veo cómo adaptar la solución propuesta a mi caso).

¿Tienen alguna idea para que pueda desbloquear esta situación?

Gracias de antemano por vuestra ayuda! 

Linux / Chrome 103.0.0.0

10 respuestas

  1. jordane45 Mensajes publicados 30426 Fecha de registro   Estado Moderador Última intervención   4 830
     

    Hola

    Al lanzar tu script por primera vez es probable que te haya mostrado un código para escribir en la consola.

    Si lo hiciste en local, debes eliminar el token y regenerarlo desde tu sitio web.

    Atento... el uso de esta API desde un servidor compartido no está garantizado... A veces, la IP del servidor está bloqueada por Google... y es complicado hacer que se desbloquee.


    .
    Atentamente,
    Jordane

    0
  2. emrh Mensajes publicados 439 Estado Miembro 20
     

    Gracias Jordan por este aviso... ¿Me recomiendas dejarlo de lado?

    En realidad, me gustaría "simplemente" que mi formulario de registro de contrato de alquiler pueda, con las fechas de entrada y salida, añadir una entrada en Google Calendar...

    Cuando ejecuté el comando php quickstart.php desde mi terminal obtuve un enlace que pegué en Chrome, el cual me pidió seleccionar una cuenta de Google. Elegí la que necesitaba acceder al calendario.
    Y fue allí cuando vi la información: The developer hasn’t given you access to this app. It’s currently being tested and it hasn’t been verified by Google.
    Modifiqué la URI de mi API a http://127.0.0.1/monsite/api/quickstart.php, pero sigo teniendo el mismo error!

    No sé cómo eliminar el token del que hablas porque no sé dónde está!
    No puedo generar ninguna línea de comando desde mi sitio web porque no tengo acceso por SSH y si ejecuto el archivo quickstart.php desde mi navegador recibo el mensaje de error :
    Fatal error: Uncaught Exception: This application must be run on the command line

    0
  3. emrh Mensajes publicados 439 Estado Miembro 20
     

    Después de ver 2 o 3 tutoriales de YouTube (sin encontrar mucho sobre el tema) en un inglés con un acento indio muy marcado, aun así conseguí avanzar en mi proyecto de interaccionar con Google Calendar. Creé en mi consola.cloud.google.com los accesos correctos a mi cuenta con, esta vez, permisos funcionales.

    Ahora llego mediante esta página de prueba https://developers.google.com/calendar/api/v3/reference/events/insert?hl=fr&apix=true#try-it para escribir en mi agenda...

    El problema es que estos tutoriales no están muy claros respecto al procedimiento para escribir desde mis páginas web en php en mi agenda...

    Tengo este fragmento de código :

    <?php $event = new Google_Service_Calendar_Event(array( 'summary' => 'TEST', 'location' => '800 Howard St., San Francisco, CA 94103', 'description' => 'A chance to hear more about Google\'s developer products.', 'start' => array( 'date' => '2022-01-01', 'timeZone' => 'America/Los_Angeles', ), 'end' => array( 'date' => '2022-01-05', 'timeZone' => 'America/Los_Angeles', ), 'recurrence' => array( 'RRULE:FREQ=DAILY;COUNT=2' ), 'attendees' => array(), 'reminders' => array( 'useDefault' => FALSE, 'overrides' => array( array('method' => 'email', 'minutes' => 24 * 60), array('method' => 'popup', 'minutes' => 10), ), ), )); $calendarId = 'monagenda.rhnorhnerhencpacnn.calendar.google.com'; $event = $service->events->insert($calendarId, $event); printf('Event created: %s\n', $event->htmlLink); ?>

    Quien me da este error :
    Fatal error: Uncaught Error: Class 'Google_Service_Calendar_Event' not found in /var/www/html/gite/gestion/api/event.php

    ¿Podrías asesorarme?

    0
    1. emrh Mensajes publicados 439 Estado Miembro 20
       

      También encontré este trozo de código, que en parte se parece al anterior, pero es más completo porque contiene un acceso a mi credentials.json :

      // Salir si se accede directamente defined('ABSPATH') || exit; ini_set('memory_limit', '-1'); ini_set('max_execution_time', '-1'); ini_set('display_errors', 1); /** * update google code */ add_action('wp_footer', 'create_google_calendar_events'); function create_google_calendar_events() { $credentials = __DIR__ . '/credentials.json'; require __DIR__ . '/vendor/autoload.php'; $client = new Google_Client(); $client->setApplicationName('testoo'); $client->getScope(array(Google_Service_Calendar::CALENDAR)); $client->setAuthConfig($credentials); $client->setAccessType('offline'); $client->getAccessToken(); $client->getRefreshToken(); $service = new Google_Service_Calendar($client); $event = new Google_Service_Calendar_event(array( 'summary' => 'testing', 'location' => '800 Howard', 'description' => 'Bla Bla Bla', 'start' => array( 'date' => '2022-01-02', 'timeZone' => 'America/Los_Angeles', ), 'end' => array( 'date' => '2022-01-05', 'timeZone' => 'America/Los_Angeles', ), 'recurrence' => array( 'RRULE:FREQ=DAILY;COUNT=2' ), 'attendees' => array(), 'reminders' => array(), 'useDefault' => FALSE, 'overrides' => array( array('method' => 'email', 'minutes' => 24 * 60), array('method' => 'popup', 'minutes' => 10), ), ), );//)); $calendarId = 'eozirenonrezntornnr@group.calendar.google.com'; $event = $service->events->insert($calendarId, $event); print_r($event->htmlLink); } ?>

      Malheureusement je n’arrive pas à récupérer les 12 premières lignes, du coup, même en neutralisant l’appel de la fonction la page reste désespérément vide ainsi que le calendrier !

      0
  4. emrh Mensajes publicados 439 Estado Miembro 20
     

    Finalmente, el archivo quickstart.php de Google da más bien un buen resultado (no hay errores al menos) pero todavía no veo cómo escribir en mi calendario:

    <?php require __DIR__ . '/vendor/autoload.php'; /*if (php_sapi_name() != 'cli') { throw new Exception('This application must be run on the command line.'); }*/ use Google\Client; use Google\Service\Calendar; /** * Returns an authorized API client. * @return Client the authorized client object */ function getClient() { $client = new Client(); $client->setApplicationName('Google Calendar API PHP Quickstart'); $client->setScopes(Google_Service_Calendar::CALENDAR); //<= SELON DOC developers.google.com $client->setAuthConfig('credentials.json'); $client->setAccessType('offline'); $client->setPrompt('select_account consent'); // Load previously authorized token from a file, if it exists. // 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. $tokenPath = 'token.json'; if (file_exists($tokenPath)) { $accessToken = json_decode(file_get_contents($tokenPath), true); $client->setAccessToken($accessToken); } // If there is no previous token or it's expired. if ($client->isAccessTokenExpired()) { // Refresh the token if possible, else fetch a new one. if ($client->getRefreshToken()) { $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken()); } else { // Request authorization from the user. $authUrl = $client->createAuthUrl(); printf("Open the following link in your browser:\n%s\n", $authUrl); print 'Enter verification code: '; $authCode = trim(fgets(STDIN)); // Exchange authorization code for an access token. $accessToken = $client->fetchAccessTokenWithAuthCode($authCode); $client->setAccessToken($accessToken); // Check to see if there was an error. if (array_key_exists('error', $accessToken)) { throw new Exception(join(', ', $accessToken)); } } // Save the token to a file. if (!file_exists(dirname($tokenPath))) { mkdir(dirname($tokenPath), 0700, true); } file_put_contents($tokenPath, json_encode($client->getAccessToken())); } return $client; } // Get the API client and construct the service object. $client = getClient(); $service = new Calendar($client); // Print the next 10 events on the user's calendar. try{ $calendarId = 'xxxxxxxxxxxxxxxxxxx@group.calendar.google.com'; $optParams = array( 'maxResults' => 10, 'orderBy' => 'startTime', 'singleEvents' => true, 'timeMin' => date('c'), ); $results = $service->events->listEvents($calendarId, $optParams); $events = $results->getItems(); if (empty($events)) { print "No upcoming events found.\n"; } else { print "Upcoming events:\n"; foreach ($events as $event) { $start = $event->start->dateTime; if (empty($start)) { $start = $event->start->date; } printf("%s (%s)\n", $event->getSummary(), $start); } } } } catch(Exception $e) { // TODO(developer) - handle error appropriately echo 'Message: ' .$e->getMessage(); } ?>

    RESULTADO :

    No upcoming events found.

    0
  5. emrh Mensajes publicados 439 Estado Miembro 20
     

    1. Eliminación del proyecto inicial
    2. Creación de un nuevo proyecto "Gestion-Agenda" en console.cloud.google.com
    3. Activación de la biblioteca Google Calendar Api
    4. Creación de un tipo de usuario Externo para OAuth 2.0
    5. Creación de un identificador de Cuenta de Servicio
    6. Adición de una clave de tipo JSON a esta cuenta de servicio (guardada en credentials.json en el mismo nivel que quickstart.php)
    7. Modificación de quickstart.php para añadir un evento :

    <?php require __DIR__ . '/vendor/autoload.php'; /* if (php_sapi_name() != 'cli') { throw new Exception('This application must be run on the command line.'); } */ use Google\Client; use Google\Service\Calendar; /** * Returns an authorized API client. * @return Client the authorized client object */ function getClient() { $client = new Client(); $client->setApplicationName('Google Calendar API PHP Quickstart'); $client->setScopes('https://www.googleapis.com/auth/calendar');//.events.readonly'); $client->setAuthConfig('credentials.json'); $client->setAccessType('offline'); $client->setPrompt('select_account consent'); // Load previously authorized token from a file, if it exists. // 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. $tokenPath = 'token.json'; if (file_exists($tokenPath)) { $accessToken = json_decode(file_get_contents($tokenPath), true); $client->setAccessToken($accessToken); } // If there is no previous token or it's expired. if ($client->isAccessTokenExpired()) { // Refresh the token if possible, else fetch a new one. if ($client->getRefreshToken()) { $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken()); } else { // Request authorization from the user. $authUrl = $client->createAuthUrl(); printf("Open the following link in your browser:\n%s\n", $authUrl); print 'Enter verification code: '; $authCode = trim(fgets(STDIN)); // Exchange authorization code for an access token. $accessToken = $client->fetchAccessTokenWithAuthCode($authCode); $client->setAccessToken($accessToken); // Check to see if there was an error. if (array_key_exists('error', $accessToken)) { throw new Exception(join(', ', $accessToken)); } } // Save the token to a file. if (!file_exists(dirname($tokenPath))) { mkdir(dirname($tokenPath), 0700, true); } file_put_contents($tokenPath, json_encode($client->getAccessToken())); } return $client; } // Get the API client and construct the service object. $client = getClient(); $service = new Calendar($client); // Print the next 10 events on the user's calendar. /*try{ $calendarId = 'primary'; $optParams = array( 'maxResults' => 10, 'orderBy' => 'startTime', 'singleEvents' => true, 'timeMin' => date('c'), ); $results = $service->events->listEvents($calendarId, $optParams); $events = $results->getItems(); if (empty($events)) { print "No upcoming events found.\n"; } else { print "Upcoming events:\n"; foreach ($events as $event) { $start = $event->start->dateTime; if (empty($start)) { $start = $event->start->date; } printf("%s (%s)\n", $event->getSummary(), $start); } } } catch(Exception $e) { // TODO(developer) - handle error appropriately echo 'Message: ' .$e->getMessage(); }*/ // AJOUTÉ À L'AGENDA : try{ $event = new Google_Service_Calendar_Event(array( 'summary' => 'TEST AJOUT', 'location' => '800 Howard St., San Francisco, CA 94103', 'description' => 'A chance to hear more about Google\'s developer products.', 'start' => array( 'date' => '2023-01-01', 'timeZone' => 'America/Los_Angeles', ), 'end' => array( 'date' => '2023-01-04', 'timeZone' => 'America/Los_Angeles', ), 'recurrence' => array( 'RRULE:FREQ=DAILY;COUNT=2' ), 'attendees' => array(), 'reminders' => array( 'useDefault' => FALSE, 'overrides' => array( array('method' => 'email', 'minutes' => 24 * 60), array('method' => 'popup', 'minutes' => 10), ), ), )); $calendarId = 'primary'; $event = $service->events->insert($calendarId, $event); printf('Event created: %s\n', $event->htmlLink); } catch(Exception $e) { // TODO(developer) - handle error appropriately echo 'Message: ' .$e->getMessage(); } ?>

    MESSAGE AFFICHÉ À L’EXÉCUTION DE QUICKSTART.PHP : 
    Event created: https://www.google.com/calendar/event?eid=RRRWNwdm5vYjBpcnRRRRRRcjFqb2dfMjAyMjARRRRRdGlvbi1hZ2VuZGRRRRR2VuZGEtMzU3NDA5LmlhbS5RRRRVydmljZWFjRRRRRbnQuY29t%5Cn

    Con más detalles pero todavía nada en la agenda!

    El mismo código quickstart.php en lectura de agenda, es decir descomentando la parte // Print the next 10 events on the user's calendar. me da :
    Upcoming events: TEST AJOUT (2023-01-01) TEST AJOUT (2023-01-02)

    0
    1. yg_be Mensajes publicados 23437 Fecha de registro   Estado Colaborador Última intervención   1 588
       

      hola,

      Si entiendo bien, escribes "siempre nada en la agenda", mientras que tu código "en lectura de la agenda" prueba que los eventos están en la agenda.

      ¿Nos has explicado qué pasaba cuando utilizabas el enlace al evento creado?

      ¿No sería preferible no usar siempre el mismo título para estos eventos, por ejemplo añadiendo el momento de ejecución del script en el título?

      0
    2. emrh Mensajes publicados 439 Estado Miembro 20 > yg_be Mensajes publicados 23437 Fecha de registro   Estado Colaborador Última intervención  
       

      Hola yg_be,

      Lo has entendido bien, "Todavía nada en la agenda" significa que cuando uso Google Chrome para ir a mi agenda, si voy a ENERO de 2023, ¡todo está vacío!
      Sin embargo, si neutralizo la parte del código relativa a la inserción de datos para activar la de lectura, y hago F5 en quickstart.php, ¡encuentra bien mi añadido (cf Upcoming events...).

      Lo que sucede cuando uso el enlace hacia el evento creado:
      Mi navegador abre Google Angenda en el mes de julio de 2022

      ¿Siempre usar el mismo título para estos eventos?
      Cambio regularmente mis denominaciones, pero no cambia nada

      0
    3. emrh Mensajes publicados 439 Estado Miembro 20 > emrh Mensajes publicados 439 Estado Miembro
       

      Próximos eventos: TEST AJOUT (2023-01-01) TEST AJOUT (2023-01-01) ETIENNE (2023-01-01T16:00:00Z) ETIENNE (2023-01-01T16:00:00Z) TEST AJOUT (2023-01-02) TEST AJOUT (2023-01-02) ETIENNE (2023-01-02T16:00:00Z) ETIENNE (2023-01-02T16:00:00Z)

      0
    4. emrh Mensajes publicados 439 Estado Miembro 20 > emrh Mensajes publicados 439 Estado Miembro
       

      Si cambio el $calendarId = 'primary'; por la ID de mi calendario:
      Mensaje: { "error": { "errors": [ { "domain": "global", "reason": "notFound", "message": "Not Found" } ], "code": 404, "message": "Not Found" } }

      (tanto al insertar como al leer)

      0
    5. yg_be Mensajes publicados 23437 Fecha de registro   Estado Colaborador Última intervención   1 588 > emrh Mensajes publicados 439 Estado Miembro
       

      Propuse cambiar el título para confirmar que el programa lector realmente encuentra los últimos eventos creados.

      ¿En el navegador, en Google Calendar, no ves ninguna otra agenda para la misma cuenta?

      Yo, probaría, desde el navegador, en Google Calendar, crear una nueva agenda (para la misma cuenta) y luego usar su nombre como $calendarId.

      0
  6. emrh Mensajes publicados 439 Estado Miembro 20
     

    La cuenta de Google usa varios calendarios, cada empleado tiene el suyo (5) + el que he creado GESTION.

    Todos están marcados como "visible".

    Todas las tentativas de reemplazar $calendarId por algo distinto de 'primary' terminan con el mensaje #10

    0
  7. emrh Mensajes publicados 439 Estado Miembro 20
     

    Una pequeña información adicional, mis pruebas se realizan desde mi portátil y me parece haber leído que hay que estar en https...
    Por eso, transferí mis 17.000 archivos (?!) google, composer, paragonie, .... a mi servidor Ionos que sí está en https y ahora tengo este error al insertar en el calendario:

     Mensaje: { "error": { "code": 403, "message": "Request had insufficient authentication scopes.", "errors": [ { "message": "Insufficient Permission", "domain": "global", "reason": "insufficientPermissions" } ], "status": "PERMISSION_DENIED", "details": [ { "@type": "type.googleapis.com/google.rpc.ErrorInfo", "reason": "ACCESS_TOKEN_SCOPE_INSUFFICIENT", "domain": "googleapis.com", "metadata": { "service": "calendar-json.googleapis.com", "method": "calendar.v3.Events.Insert" } } ] } }

    0
  8. emrh Mensajes publicados 439 Estado Miembro 20
     

    He recreado una cuenta de servicio, generado una nueva clave y ya no tengo el error 403!
    No me había dado cuenta (porque es muy discreto) de que el enlace tras la inserción mostraba:
    No se puede encontrar el evento solicitado

    También probé inserciones sin las Timezone America/Los_Angeles y las DateTime,
    tengo esto como lectura:
    Upcoming events: ETIENNE (2023-01-01) ETIENNE (2023-01-01T16:00:00Z) ETIENNE (2023-01-02) ETIENNE (2023-01-02T16:00:00Z)

    0
  9. emrh Mensajes publicados 439 Estado Miembro 20
     

    Gran Gran avance:
     

    Cuando creé en console.cloud.google.com una cuenta de servicio, y luego para esa cuenta creé una clave y obtuve un archivo JSON + una dirección de correo de tipo nomdemonprojet@nomdemonprojet-785123.iam.gserviceaccount.com

    1. Fui a mi Google Calendar, en la agenda GESTION creada para recibir los eventos de mi código PHP para añadir esta dirección de correo en "compartir con personas en particular"

    2. Recuperé el ID de esta Agenda GESTION para asignarlo a la variable $calendarId.

    Volví a cargar mi página quickstart.php y TAADAAAAA :

    <?php require __DIR__ . '/vendor/autoload.php'; /* if (php_sapi_name() != 'cli') { throw new Exception('This application must be run on the command line.'); } */ use Google\Client; use Google\Service\Calendar; /** * Returns an authorized API client. * @return Client the authorized client object */ function getClient() { $client = new Client(); $client->setApplicationName('Google Calendar API PHP Quickstart'); $client->setScopes('https://www.googleapis.com/auth/calendar');//.events.readonly');<= MODIFIER ICI $client->setAuthConfig('credentials.json');//<= Le fichier d'autentification $client->setAccessType('offline'); $client->setPrompt('select_account consent'); // Load previously authorized token from a file, if it exists. // 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. $tokenPath = 'token.json'; if (file_exists($tokenPath)) { $accessToken = json_decode(file_get_contents($tokenPath), true); $client->setAccessToken($accessToken); } // If there is no previous token or it's expired. if ($client->isAccessTokenExpired()) { // Refresh the token if possible, else fetch a new one. if ($client->getRefreshToken()) { $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken()); } else { // Request authorization from the user. $authUrl = $client->createAuthUrl(); printf("Open the following link in your browser:\n%s\n", $authUrl); print 'Enter verification code: '; $authCode = trim(fgets(STDIN)); // Exchange authorization code for an access token. $accessToken = $client->fetchAccessTokenWithAuthCode($authCode); $client->setAccessToken($accessToken); // Check to see if there was an error. if (array_key_exists('error', $accessToken)) { throw new Exception(join(', ', $accessToken)); } } // Save the token to a file. if (!file_exists(dirname($tokenPath))) { mkdir(dirname($tokenPath), 0700, true); } file_put_contents($tokenPath, json_encode($client->getAccessToken())); } return $client; } // Get the API client and construct the service object. $client = getClient(); $service = new Calendar($client); // LIRE DANS L'AGENDA /*try{ $calendarId = 'primary'; $optParams = array( 'maxResults' => 10, 'orderBy' => 'startTime', 'singleEvents' => true, 'timeMin' => date('c'), ); $results = $service->events->listEvents($calendarId, $optParams); $events = $results->getItems(); if (empty($events)) { print "No upcoming events found.\n"; } else { print "Upcoming events:\n"; foreach ($events as $event) { $start = $event->start->dateTime; if (empty($start)) { $start = $event->start->date; } printf("%s (%s)\n", $event->getSummary(), $start); } } } catch(Exception $e) { // TODO(developer) - handle error appropriately echo 'Message: ' .$e->getMessage(); }*/ // AJOUT À L'AGENDA : try{ $event = new Google_Service_Calendar_Event(array( 'summary' => 'VIVA', 'location' => '800 Howard St., San Francisco, CA 94103', 'description' => 'A chance to hear more about Google\'s developer products.', 'start' => array( 'date' => '2023-01-30', ), 'end' => array( 'date' => '2023-02-01', ), 'recurrence' => array(), 'attendees' => array(), 'reminders' =&; array(), )); $calendarId = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXX@group.calendar.google.com'; $event = $service->events->insert($calendarId, $event); printf('Event created: %s\n', $event->htmlLink); } catch(Exception $e) { // TODO(developer) - handle error appropriately echo 'Message: ' .$e->getMessage(); } ?>
    0
    1. emrh Mensajes publicados 439 Estado Miembro 20
       

      He dicho un gran avance, pero no todo está resuelto, porque si miras el código se ve:

      Fecha de inicio: 2023-01-30
      Fecha de finalización: 2023-02-01

      Y si miro en mi agenda veo que me han quitado 1 día!

      0