Google Calendar Server to Server - fullcalendar

I use to make appointments a calendar based on FULLCALENDAR with backup of the rdv in a database mysql on my own local server. So far, so good. I wish I could synchronize the rdvs thus taken, on the google calendar and inversely be able to import into my database mysql the rdvs taken on the account of google on line.
I tried to understand and read the API doc of google calendar here and here
I only get error messages.
I tried to do it directly in fullcalendar but the calendar must be declared in public, something I can not do.
The ideal would be to be able to make server calls in php (login and password of google clandier backup in local mysql database), for which I create my API key and a service account, but again I do not get only error messages.
Would there be a link or a really functional tutorial that I could use to learn
I tried with this link but never succeeded
thanks in advance.
EDIT : I try this.
quickstart.php
<?php
require_once __DIR__ . '/vendor/autoload.php';
define('APPLICATION_NAME', 'Google Calendar API PHP Quickstart');
define('CREDENTIALS_PATH', '~/.credentials/calendar-php-quickstart.json');
define('CLIENT_SECRET_PATH', __DIR__ . '/client_id.json');
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/calendar-php-quickstart.json
define('SCOPES', implode(' ', array(
Google_Service_Calendar::CALENDAR_READONLY)
));
if (php_sapi_name() != 'cli') {
throw new Exception('This application must be run on the command line.');
}
/**
* Returns an authorized API client.
* #return Google_Client the authorized client object
*/
function getClient() {
$client = new Google_Client();
$client->setApplicationName(APPLICATION_NAME);
$client->setScopes(SCOPES);
$client->setAuthConfig(CLIENT_SECRET_PATH);
$client->setAccessType('offline');
// Load previously authorized credentials from a file.
$credentialsPath = expandHomeDirectory(CREDENTIALS_PATH);
if (file_exists($credentialsPath)) {
$accessToken = json_decode(file_get_contents($credentialsPath), true);
} 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);
// Store the credentials to disk.
if(!file_exists(dirname($credentialsPath))) {
mkdir(dirname($credentialsPath), 0700, true);
}
file_put_contents($credentialsPath, json_encode($accessToken));
printf("Credentials saved to %s\n", $credentialsPath);
}
$client->setAccessToken($accessToken);
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
return $client;
}
/**
* Expands the home directory alias '~' to the full path.
* #param string $path the path to expand.
* #return string the expanded path.
*/
function expandHomeDirectory($path) {
$homeDirectory = getenv('HOME');
if (empty($homeDirectory)) {
$homeDirectory = getenv('HOMEDRIVE') . getenv('HOMEPATH');
}
return str_replace('~', realpath($homeDirectory), $path);
}
// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Calendar($client);
// Print the next 10 events on the user's calendar.
$calendarId = 'primary';
$optParams = array(
'maxResults' => 10,
'orderBy' => 'startTime',
'singleEvents' => TRUE,
'timeMin' => date('c'),
);
$results = $service->events->listEvents($calendarId, $optParams);
if (count($results->getItems()) == 0) {
print "No upcoming events found.\n";
} else {
print "Upcoming events:\n";
foreach ($results->getItems() as $event) {
$start = $event->start->dateTime;
if (empty($start)) {
$start = $event->start->date;
}
printf("%s (%s)\n", $event->getSummary(), $start);
}
}
php quickstart.php
PHP Fatal error: Uncaught InvalidArgumentException: missing the required redirect URI in /Users/krislec/Desktop/vendor/google/auth/src/OAuth2.php:648
Stack trace:
#0 /Users/krislec/Desktop/vendor/google/apiclient/src/Google/Client.php(340): Google\Auth\OAuth2->buildFullAuthorizationUri(Array)
#1 /Users/krislec/Desktop/quickstart.php(36): Google_Client->createAuthUrl()
#2 /Users/krislec/Desktop/quickstart.php(75): getClient()
#3 {main}
thrown in /Users/krislec/Desktop/vendor/google/auth/src/OAuth2.php on line 648
Fatal error: Uncaught InvalidArgumentException: missing the required redirect URI in /Users/krislec/Desktop/vendor/google/auth/src/OAuth2.php:648
Stack trace:
#0 /Users/krislec/Desktop/vendor/google/apiclient/src/Google/Client.php(340): Google\Auth\OAuth2->buildFullAuthorizationUri(Array)
#1 /Users/krislec/Desktop/quickstart.php(36): Google_Client->createAuthUrl()
#2 /Users/krislec/Desktop/quickstart.php(75): getClient()
#3 {main}
thrown in /Users/krislec/Desktop/vendor/google/auth/src/OAuth2.php on line 648

Related

Required param state missing from persistent data

I've an issue with php-graph-sdk, I've those functions
protected function getFacebook()
{
static $facebook = null;
if($facebook == null){
$facebook = new Facebook\Facebook([
'app_id' => $this->getAppId(),
'app_secret' => $this->getAppSecret(),
'default_graph_version' => 'v2.10'
]);
}
return $facebook;
}
public function getLoginUrl($url)
{
$fb = $this->getFacebook();
$helper = $fb->getRedirectLoginHelper();
$autorisations = ['email'];
return $helper->getLoginUrl($url , $autorisations);
}
public function callback(&$error = null)
{
$fb = $this->getFacebook();
$helper = $fb->getRedirectLoginHelper();
try {
$accessToken = $helper->getAccessToken();
} catch(Facebook\Exception\ResponseException $e) {
// When Graph returns an error
$error = 'Graph returned an error: ' . $e->getMessage();
return false;
} catch(Facebook\Exception\SDKException $e) {
// When validation fails or other local issues
$error = 'Facebook SDK returned an error: ' . $e->getMessage();
return false;
}
....
}
And I do
$url = $Facebook->getLoginUrl(URL);
And in the callback file
$token = $Facebook->callback($error);
When I click on the link, the callback file is executed and $helper->getAccessToken(); causes this error:
Uncaught Facebook\Exceptions\FacebookSDKException: Cross-site request forgery validation failed. Required param "state" missing from persistent data.
I've seen posts about that and no fix works for me
EDIT:
What I've found currently is that: Facebook SDK error: Cross-site request forgery validation failed. Required param "state" missing from persistent data
Cross-site request forgery validation failed required param state missing from persistent data
and
https://github.com/facebookarchive/php-graph-sdk/issues/1123
https://github.com/facebookarchive/php-graph-sdk/issues/1134
Finally I've solved my issue by switching samesite to Lax by adding that in config.php
ini_set('session.cookie_samesite','Lax');

samlspbundle integration with fosuserbundle

I try to integrate the bundle samlspbundle on a project running with fosuserbundle.
I actually received information from my idp which send me the saml with the email address of the user.
What i'm trying to do is load the user from my table fosuser and then authenticate it.
this is the method i am in my model SamlToUser :
private function loadUserByTargetedID($targetedID)
{
$repository = $this->container->get('doctrine')->getManager()->getRepository('MCCAppBDDBundle:User');
$user = $repository->findOneBy(
array('email' => $targetedID)
);
if ($user) {
$userManager = $this->container->get('fos_user.user_manager');
$url = $this->container->get('router')->generate('homepage');
$response = new RedirectResponse($url);
$this->container->get('fos_user.security.login_manager')->loginUser(
$this->container->getParameter('fos_user.firewall_name'),
$user,
null
);
$userManager->updateUser($user);
return $user;
}
throw new \Symfony\Component\Security\Core\Exception\UsernameNotFoundException();
}
After that i have this error : PHP Warning: session_regenerate_id(): Cannot regenerate session id - headers already sent
I'm not sure is the right thing to do.
If you need other detail, i can give you.
Thanks to help.

Symfony2 Doctrine - Flushing in kernel.response listener flushs bad data

In order to do some logging for my Symfony2 app, I created a service that logs any connection, here is the method called on kernel.response :
public function log(FilterResponseEvent $event)
{
$log = new Log();
$request = $event->getRequest();
$response = $event->getResponse();
//fill the Log entity with stuff from request & response data
$manager = $this->container->get('doctrine.orm.entity_manager');
$manager->persist($log);
$manager->flush();
}
All of this seems fine, however when I execute a test like this one (patch with empty data to trigger a failure):
$this->client->request(
'PATCH',
'/users/testificate',
array(
'firstName' => '',
)
);
Which calls this action :
protected function processForm($item, $method = 'PATCH')
{
$form = $this->createForm(new $this->form(), $item, array('method' => $method));
$form->handleRequest($this->getRequest());
if ($form->isValid()) {
$response = new Response();
// Set the `Location` header only when creating new resources
if ($method == 'POST') {
$response->setStatusCode(201);
$response->headers->set('Location',
$this->generateUrl(
'get_' . strtolower($class), array('slug' => $item->getId()),
true // absolute
)
);
}
else {
$response->setStatusCode(204);
}
$this->em->flush();
return $response;
}
$this->em->detach($item);
return RestView::create($form, 400);
}
Although the test fails, the entity is patched, and of course it must not.
After some search what I've learnt is:
The parameters enter the form validator
The validation fails, thus returning a 400 http code without flushing the entity
However during the validation process, the entity gets hydrated with the invalid data
When the service is called on kernel.response, the $manager->flush(); flush all the data... including the bad data provided by the PATCH test.
What I've tried thus far:
1) Do a $manager->clear(); before $manager->persist(); ... doesn't change anything
2) Do a $manager->detach($item); if the form validation failed... doesn't change anything
Thanks !
I recently stumbled across problems with flushing in kernel.response when upgrading from Doctrine 2.3.4 to the latest 2.4 branch. Try flusing the log entities from kernel.terminate. Leave any modifications to the Response in kernel.response.

Symfony2 - Redirect response from request EventListener in dev mode while ignoring built in request events

I am building my own user management system in Symfony2 (not using FOSUserBundle) and want to be able to force users to change their password.
I have setup an EventListener to listen to the kernal.request event, then I perform some logic in the listener to determine if the user needs to change their password; if they do, then they are redirected to a "Change Password" route.
I add the service to my config.yml to listen on the kernal.request:
password_change_listener:
class: Acme\AdminBundle\EventListener\PasswordChangeListener
arguments: [ #service_container ]
tags:
- { name: kernel.event_listener, event: kernel.request, method: onMustChangepasswordEvent }
And then the listener:
public function onMustChangepasswordEvent(GetResponseEvent $event) {
$securityContext = $this->container->get('security.context');
// if not logged in, no need to change password
if ( !$securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED') )
return;
// If already on the change_password page, no need to change password
$changePasswordRoute = 'change_password';
$_route = $event->getRequest()->get('_route');
if ($changePasswordRoute == $_route)
return;
// Check the user object to see if user needs to change password
$user = $this->getUser();
if (!$user->getMustChangePassword())
return;
// If still here, redirect to the change password page
$url = $this->container->get('router')->generate($changePasswordRoute);
$response = new RedirectResponse($url);
$event->setResponse($response);
}
The problem I am having is that in dev mode, my listener is also redirecting the profiler bar and assetic request events. It works when I dump assets and clear cache and view the site in production mode.
Is there a way I can ignore the events from assetic/profiler bar/any other internal controllers? Or a better way to redirect a user to the change_password page (not only on login success)?
Going crazy thinking up wild hack solutions, but surely there is a way to handle this elegantly in Symfony2?
This is the very hack solution I am using for now:
Determine if in dev environment
If so, get an array of all the routes
Filter the route array so that only the routes I have added remain
Compare the current route to the array of routes
If a match is found, this means that the event is not an in-built controller, but must be one that I have added, so perform the redirect.
And this is the madness that makes that work:
// determine if in dev environment
if (($this->container->getParameter('kernel.environment') == 'dev'))
{
// Get array of all routes that are not built in
// (i.e You have added them yourself in a routing.yml file).
// Then get the current route, and check if it exists in the array
$myAppName = 'Acme';
$routes = $this->getAllNonInternalRoutes($myAppName);
$currentRoute = $event->getRequest()->get('_route');
if(!in_array($currentRoute, $routes))
return;
}
// If still here, success, you have ignored the assetic and
// web profiler actions, and any other actions that you did not add
// yourself in a routing.yml file! Go ahead and redirect!
$url = $this->container->get('router')->generate('change_password_route');
$response = new RedirectResponse($url);
$event->setResponse($response);
And the crazy hack function getAllNonInternalRoutes() that makes it work (which is a modification of code I found here by Qoop:
private function getAllNonInternalRoutes($app_name) {
$router = $this->container->get('router');
$collection = $router->getRouteCollection();
$allRoutes = $collection->all();
$routes = array();
foreach ($allRoutes as $route => $params)
{
$defaults = $params->getDefaults();
if (isset($defaults['_controller']))
{
$controllerAction = explode(':', $defaults['_controller']);
$controller = $controllerAction[0];
if ((strpos($controller, $app_name) === 0))
$routes[]= $route;
}
}
return $routes;
}

Google Calendar API. Service Account. Access Token Expired. Refresh AT without RT

I'm trying to get events from my Google Calendar using Service Account. I received Access Token:
{"access_token":"ya29.AHES6ZR9o2-cut-Gg","expires_in":3600,"created":1366631471}
Now this token is expired and when I trying to get events, I get an error:
The OAuth 2.0 access token has expired, and a refresh token is not available. Refresh tokens are not returned for responses that were auto-approved.
I tried to find way to get a new access token in API documentation, but did not find anything suitable. And now I have a question: How I must refresh my access token?
Code that I use to access the calendar:
session_start();
require_once '../../src/Google_Client.php';
require_once '../../src/contrib/Google_CalendarService.php';
define('SERVICE_ACCOUNT_NAME', 'numbers-and-letters#developer.gserviceaccount.com');
define('CLIENT_ID', 'numbers-and-letters.apps.googleusercontent.com');
define('KEY_FILE', '../../key.p12');
$client = new Google_Client();
$client->setApplicationName("app name");
$client->setUseObjects(true);
$client->setClientID(CLIENT_ID);
$key = file_get_contents(KEY_FILE);
if (isset($_SESSION['token']))
{
$client->setAccessToken($_SESSION['token']);
$client->setaccessType('offline');
}
else
{
$client->setAssertionCredentials(new Google_AssertionCredentials(
SERVICE_ACCOUNT_NAME,
array('https://www.googleapis.com/auth/calendar.readonly'),
$key
));
}
try
{
$cal = new Google_CalendarService($client);
$events = $cal->events->listEvents('numbers-and-letters#group.calendar.google.com');
print_r($events);
} catch (Exception $e) echo $e->getMessage();
if ($client->getAccessToken()) {
$_SESSION['token'] = $client->getAccessToken();
}
I solved! To refresh Access Token without Refresh Token you want to call Google_Client class's method revokeToken()
The recommended way to refresh token is:
if ($client->isAccessTokenExpired())
{
$client->getAuth()->refreshTokenWithAssertion();
}

Resources