Sync Token Exception google-api-client-service php people Service - php

I have a problem with the Google API. I need to get all the contacts of a user in my application, however I don't want to load all the data each time, because I store the data in my database.
It's why I want to use the Sync Token functionality which let's us get only data who has been changed since our last query.
For this i Use the Google APIs PHP client library.
I wrote my code and it throws an exception (Google_Service_Exception) which explains that my Sync Token is not valid anymore, so I decided to use a try/catch system to reset syncToken if it is not valid.
My problem is each time i made the request I go in the catch (the google_service_exception) is raised even if my token is valid.
I store the token in my database so I tested it in the API explorer here: https://developers.google.com/people/api/rest/v1/people.connections/list and it work fine, so I don't understand why my application doesn't work properly.
Here's my code:
$personFields = 'metadata,names,addresses,biographies,birthdays,emailAddresses,genders,memberships,organizations,phoneNumbers';
$user = $this->get('security.token_storage')->getToken()->getUser();
$syncToken = $user->getContactSyncToken();
$nextPagetoken = '';
$contactData = array();
$people_service = new \Google_Service_PeopleService($client);
do {
try {
$data = $people_service->people_connections->listPeopleConnections(
'people/me',
array(
'personFields' => $personFields,
'requestSyncToken' => true,
'syncToken' => $syncToken,
'pageToken' => $nextPagetoken,
)
);
}catch (\Google_Service_Exception $e){
$data = $people_service->people_connections->listPeopleConnections(
'people/me',
array(
'personFields' => $personFields,
'requestSyncToken' => true,
'syncToken' => '',
'pageToken' => $nextPagetoken,
)
);
}finally{
$syncToken = $data->getNextSyncToken();
$nextPagetoken = $data->getNextPageToken();
if (count($data->getConnections()) != 0) {
$contactData[] = $data->getConnections();
}
}
}while ($nextPagetoken !== null);
$user->setContactSyncToken($syncToken);
$this->getDoctrine()->getManager()->flush();
return $contactData;
Thank you for your help and sorry for my english i'm not a native and not very good at it.

Sorry i found the problem, in my User class i had:
public function getContactSyncToken()
{
if($token = $this->contactSyncToken !== null){
return $token;
}else{
return '';
}
}
And it always return ' ', now it works with:
public function getContactSyncToken()
{
$token = $this->contactSyncToken;
if($token !== null){
return $token;
}else{
return '';
}
}

Related

Check if update happened in put request

I am new at PHP. We are creating REST API in Phalcon and I've created a put request. It already works, but I would like to check if update has really happened before sending a success response. So I've created a conditional for that ( if (!$product->update()) ), but it always returns 'true'. How can I check if any field has changed in a record?
public function put()
{
$id = $this->getParam('id');
$input = $this->getRawData();
$product = Product::findFirst([
'conditions' => 'id = :id:',
'bind' => ['id' => $id]
]);
if ($product === null){
throw new NotFoundException();
}
$product->assign($input);
$product->update();
if (!$product->update()) {
$this->errorResponse($product->getMessages());
} else {
$this->successResponse($product->toArray($product->update()));
}
}
You can use Model Events, i.e. afterUpdate and notSaved, like:
use Phalcon\Mvc\Model;
use Phalcon\Http\Response;
class ModelBase extends Model
{
public function afterUpdate()
{
$response = new Response();
$response->setJsonContent([
'success' => true,
'message' => "Record updated"
])->send();
}
public function notSaved()
{
$response = new Response();
$response->setJsonContent([
'success' => false,
'message' => 'Record not saved'
])->send();
}
}
The Product and all other models will extend ModelBase. Then your code could be:
public function put()
{
$id = $this->getParam('id');
$input = $this->getRawData();
$product = Product::findFirst([
'conditions' => 'id = :id:',
'bind' => ['id' => $id]
]);
if ($product === null){
throw new NotFoundException();
}
$product->assign($input);
$product->update();
}
And Phalcon event will respond if the model was updated or not. If you prefer, you can also use custom http response codes for update or notSaved. More information about Model Events in the documentation
You are calling $product->update() three times. You do it once after the assign, then again for your if test, which is why it's always returning TRUE there I believe, and once inside the toArray() which may not actually return anything since the second and third updates don't have any data to update (not sure about that though).
I would code this as follows:
$product->assign($input);
$results = $product->update();
if (!results) {
$this->errorResponse($product->getMessages());
} else {
$this->successResponse($results->toArray());
}
I am assuming that the $product->assign($input); statement is working as expected to update the $product data for you. I don't use that. I prefer to do direct assignments for updates so nothing is left to chance, ie. $product->whatever = $input['whatever'];.
Give this a try and hopefully it will work as expected for you.

Laravel decrypt hashed security answer for customer to see on front-end API

I'm building a feature in my Laravel 8 API to allow customers to set a Security Question & Security Answer. A customer can set their question via a HTML <select> and set their answer via a standard HTML5 input.
When their answer is saved, I'm hashing it, for security purposes in case data is exposed, however, in my API, I need to somehow decrypt the hashed value for the logged in user so that they can see their answer, and make amendments to it, or change it.
Right now I'm saving the data via a method:
/**
* Update user's security questions
*
* #return Response
*/
public function updateSecurityQuestions(Request $request)
{
// get request data
$request_data = $request->only(['security_question', 'security_answer']);
// validation
$validator = Validator::make($request_data, [
'security_question' => 'nullable|in:1,2,3,4,5,6,7,8',
'security_answer' => 'nullable|max:128'
]);
// if validation fails
if ($validator->fails()) {
$this->error_response['errors'] = $validator->messages();
return response()->json(['success' => false, 'message' => 'It looks like you missed something', $this->error_response], 400);
}
// attempt to save the user
try {
$question = (isset($request_data['security_question']) && !empty($request_data['security_question'])) ? htmlspecialchars($request_data['security_question']) : null;
$answer = (isset($request_data['security_answer']) && !empty($request_data['security_answer'])) ? htmlspecialchars($request_data['security_answer']) : null;
$id = Auth::user();
$user = User::findOrFail($id['id']);
$user->security_question = !$answer ? null : $question;
$user->security_answer = !$question ? null : Hash::make($answer);
$user->save();
if ($user->security_question == null && $user->security_answer == null) {
return response()->json(['success' => true, 'type' => 'warning', 'message' => 'Your security question settings are incomplete'], 200);
}
// everything went okay!
return response()->json(['success' => true, 'type' => 'success', 'message' => 'Your security question and answer has been updated'], 200);
} catch (Exception $e) {
// catch the error
return response()->json(['success' => false, 'message' => 'We was unable to update your security question and answer, please try again later'], 422);
}
}
You can see I'm hashing it, but this value is returned to the front-end via an API in JSON amongst other user data:
{
"security_answer": "$2y$10$gGa6OC34UBzQzMNtVoo.EOj8W9WD5THY68bQME0y6AnRJjYFWWcqO"
}
This is no good because the user sees that value in the input, which obviously isn't good.
Could I not just do something like?
if (Hash::check($user->security_answer, $user->security_answer)) {
// return the answer?
}
What do I do here?
Why you execute save before the if? You need to make it after check if everything's okay
$user->save();

Passing Multiple Value For PHP API Function

I am new in PHP and working to modify one API. Its built with Laravel Framework. I have API function like below in my controller.
public function DeleteOneMail(Request $request)
{
$uid = $request->uid;
if (\Request::is('api/*')) {
if ($request->has('key')) {
if (in_array($request->input('key'), explode(',', env('API_KEY')))) {
if ($uid == '') {
return response()->make('Please Enter UID', 401);
} else {
$client = Client::account('default');
$client->connect();
$inbox = $client->getFolder('INBOX');
$message = $inbox->getMessage($uid);
if ($message) {
return response(['success' => 1], 200);
} else {
return response(['success' => 0, 'message' => 'No Data Found'], 200);
}
}
} else {
return response()->make('Unauthorized Access. Please enter correct API Key', 401);
}
} else {
return response()->make('Unauthorized Access. Please enter correct API Key', 401);
}
}
}
I am calling API like below
https://example.com/api/delete-one-mail?key=2221212&uid=214
Its working fine without any issue. Now I want pass multiple uid with request and so I can process that uid one by one with my api function. I am not getting idea how I can pass arrary and process it. Let me know if any expert can help me for solve my puzzle. Thanks!
Your can pass an array like this
https://example.com/api/delete-one-mail?key=2221212&uid[]=214&uid[]=111&uid[]=222
$request->uid should be an array but you can make sure (if anyone use the old url with ony one uid) by doing
$uids = Arr::wrap($request->uid);
If you want to send an array by GET request just use []
https://example.com/api/delete-one-mail?key=2221212&uid[]=1&uid[]=2
In your controller you will get an array
$uid = $request->uid;
dd($uid);
As a result you will get
[1, 2]

Laravel- PHP request not setting database values correctly

I have a Laravel application, and on one of the pages, I want to allow the user to be able to update some values in the database, by entering/ changing data in a couple of textboxes.
The Angular function called by the (change) attribute of these HTML textboxes is:
updatePreferredAddresseeDetails($event, payer) {
console.log("updatePreferredAddresseeDetails() called ");
const contact = payer['contacts'][$event.currentTarget.selectedIndex];
payer.loading = true;
payer.originalAddresseeName = payer.addresseename;
payer.originalAddresseeNamePdf = payer.addresseenamepdf;
payer.ADDRESSEENAME = $event.contactPreferredName;
payer.ADDRESSEENAMEPDF = $event.contactPreferredAddresseeName;
this.provService.updatePreferredAddresseeDetails(payer).subscribe(
(response:any) => {
payer.addresseename = response.addresseename;
payer.addresseenamepdf = response.addresseenamepdf;
const message = new Message();
message.type = MessageType.SUCCESS;
message.message = 'Preferred Addressee details have been updated. ';
this.messagingService.emitMessage(message);
payer.loading = false;
},
(error:any) => {
//reset the names back to what they were originally because saving failed
payer.addresseename = payer.originalAddresseeName;
const message = new Message();
message.type = MessageType.ERROR;
message.message = error.message || 'There was a problem updaing the preferred addressee details. If the problem persists, please contact us.';
this.messagingService.emitMessage(message);
payer.loading = false;
}
);
}
The PHP function called by the above Angular function, which should be setting the values in the database is:
public function updatePreferredAddresseeDetails(Request $request)
{
try
{
DB::beginTransaction();
$transactionContactId = $request->input('transactionContactId');
$transactionItemId = $request->input('transactionItemId');
if ($transactionItem = transactionItem::find($transactionItemId))
{
$transaction = $transactionItem->transaction;
if (User::canAccessTransaction( auth()->user()->user, $transaction))
{
$account = Account::find($transaction->accountId);
$account->savePropertyValueByPropertyTag('ADDRESSEENAME', $request->input('contactPreferredName'));
$account->savePropertyValueByPropertyTag('ADDRESSEENAMEPDF', $request->input('contactPreferredAddresseeName'));
$account->save();
DB::commit();
return response()->json([
'success' => true,
'addresseeName' => $account->ADDRESSEENAME,
'addresseeNamePdf' => $account->ADDRESSEENAMEPDF,
]);
}
else
{
return response()->json([
'success' => false,
]);
}
dd("transactionItem: ", $transactionItem);
}
else
{
dd("transactionItem could not be found ");
}
}
catch(Exception $e)
{
$message = $e->getMessage();
if (empty($message))
{
$message = "Preferred addressee details could not be updated. ";
}
DB::rollback();
return response()->json([
'error' => true,
'message' => $message
], 500);
}
}
However, when I enter new values/ update an existing value in one of the textboxes, and then tab out of it, I can see in the browser console that the Angular function is called, and that it in turn calls the PHP function- but in the Network->Preview tab of the console, I see the output:
{success: true, addresseeName: null, addresseeNamePdf: null}
addresseeName: null
addresseeNamePdf: null
success: true
so for some reason, it seems that these values are not actually being updated in the database. Why is this? What am I doing wrong? How can I ensure that the database values are correctly updated from this function?
Edit
Looks like #Devon was possibly right with his comment about the function being used... I had a look the user.php file (which is where canAccessTransaction() is defined), and there was another function: userCanEditAccount(), which I think is probably the one I want. It's defined with:
private static function userCanEditAccount($userId, $accountId)
{
return Account::canUserEditAccount( $userId, $accountId );
}
so I changed that part inside the updatePreferredAddresseeDetails() function to:
if(User::userCanEditAccount( $request->userId, $request->accountId)
{
$account = Account::find($request->accountId);
$account->savePropertyValueByPropertyTag('ADDRESSEENAME', $request->input('contactPreferredName'));
$account->savePropertyValueByPropertyTag('ADDRESSEENAMEPDF', $request->input('contactPreferredAddresseeName'));
$account->save();
dd("request: ", $request->all());
DB::commit();
return response()->json([
'success' => true,
'addresseeName' => $account->ADDRESSEENAME,
'addresseeNamePdf' => $account->ADDRESSEENAMEPDF,
]);
}
else
{
return response()->json([
'success' => false,
]);
}
But when the page loads now, before I actually interact with it at all, I get an error in the console that says:
Parse error: syntax error, unexpected ';'
on the line
$account = Account::find($request->accountId);
but I'm pretty sure that ; should be there- what else could be causing this?

PHP YouTube Data API get channel information without oath

I want to pull channel information based on a username or channel id. This information is derived from the URL used to view that channel.
EX: https://www.youtube.com/user/csga5000, or, https://www.youtube.com/channel/some-channel-id
I have this code:
$this->load->library('APIs/YouTube');
echo "[";
echo json_encode($this->youtube->getId('channel/UCkklJA9WbtJM5-g21xHI3yA'),false);
echo "\n]";
The function called is:
public function getId($url) {
$id = explode('/', $url);
echo json_encode($id).',';
//User's channel
if ($id[0] === 'user') {
$response = $this->youtube->channels->listChannels('id,snippet',array(
'forUsername' => $id[1]
));
}
//Channel id
else {
$response = $this->youtube->channels->listChannels('id,snippet',array(
'id' => $id[1],
'maxResults' => 2
));
}
return $response;
}
Here is the construct function for the youtube class:
public function __construct()
{
$this->client = new Google_Client();
$this->client->setDeveloperKey($this->api_key);
$this->client->setClientId($this->client_id);
$this->client->setClientSecret($this->client_secret);
$this->client->setScopes(array(
Google_Service_Oauth2::PLUS_LOGIN,
Google_Service_Oauth2::PLUS_ME,
Google_Service_Oauth2::USERINFO_EMAIL,
Google_Service_Oauth2::USERINFO_PROFILE,
Google_Service_YouTube::YOUTUBE
));
$ci =& get_instance();
$this->client->setRedirectUri($ci->config->item('base_url').'auth/youtube/');
$this->oauth = new Google_Service_Oauth2($this->client);
$this->youtube = new Google_Service_YouTube($this->client);
}
Calling the function with 'user/csga5000' doesn't work either
The results printed are:
[
[
"channel",
"UCkklJA9WbtJM5-g21xHI3yA"
],
{
"etag":"\"IHLB7Mi__JPvvG2zLQWAg8l36UU\/KcPrlZVHCJ9bAKurpGOj1BBEH6g\"",
"eventId":null,
"kind":"youtube#channelListResponse",
"nextPageToken":null,
"prevPageToken":null,
"visitorId":null
}
]
I just want results like this:
https://www.googleapis.com/youtube/v3/channels?part=id%2Csnippet&id=UCkklJA9WbtJM5-g21xHI3yA&key={YOUR_API_KEY}
or
https://www.googleapis.com/youtube/v3/channels?part=id%2Csnippet&forUsername=csga5000&key={YOUR_API_KEY}
Which you can test here:
https://developers.google.com/youtube/v3/docs/channels/list#try-it
With forUsername csga5000 or id UCkklJA9WbtJM5-g21xHI3yA
All the examples I found used "mine => true" and oauth to load this data, so nothing on google, or stack overflow seemed helpful.
I was just missing something silly, I'd been super confused by the response.
I needed the line:
$response->getItems();

Categories