Facebook Workplace Account Management API Not Returning Photos - facebook-graph-api

I am having an issue with the Account Management API for Facebook Workplace. All I am trying to do is build a quick and easy employee directory, that grabs all of our active users and spits out their name, title, dept, and photos. The problem is, the data coming back does not seem to match the Facebook Core Schema as seen in the link above. Some of the schema data comes back, but never photos, no matter what I seem to try.
private function getEmployees()
{
$done = false;
$current_index = 1;
$current_page = 1;
$results = [];
while(!$done) {
$res = $this->client->request(
'GET',
'https://www.facebook.com/company/XXXXXXXXX/scim/Users?count=100&startIndex=' . $current_index,
[
'headers' => ['Accept' => 'application/json',
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $this->token
]
]
);
$decoded = json_decode($res->getBody());
$total = $decoded->totalResults;
$perPage = $decoded->itemsPerPage;
if (isset($decoded->Resources)) {
$results = array_merge($results, $decoded->Resources);
if (($current_page * $perPage) >= $total) {
$done = true;
} else {
$current_page++;
$current_index += $perPage;
}
} else {
$done = true;
}
}
return $results;
}
Which gives back:
object(stdClass)[392]
public 'schemas' =>
array (size=3)
0 => string 'urn:scim:schemas:core:1.0' (length=25)
1 => string 'urn:scim:schemas:extension:enterprise:1.0' (length=41)
2 => string 'urn:scim:schemas:extension:facebook:starttermdates:1.0' (length=54)
public 'id' => int 10001156699923
public 'userName' => string 'np#lt.com' (length=21)
public 'name' =>
object(stdClass)[393]
public 'formatted' => string 'Nick P' (length=11)
public 'title' => string 'Lead PHP Engineer' (length=17)
public 'active' => boolean true
public 'phoneNumbers' =>
array (size=1)
0 =>
object(stdClass)[394]
public 'primary' => boolean true
public 'type' => string 'work' (length=4)
public 'value' => string '+1631123456' (length=12)
public 'addresses' =>
array (size=1)
0 =>
object(stdClass)[395]
public 'type' => string 'attributes' (length=10)
public 'formatted' => string 'Manhattan' (length=9)
public 'primary' => boolean true
public 'urn:scim:schemas:extension:enterprise:1.0' =>
object(stdClass)[396]
public 'department' => string 'IT' (length=2)
public 'manager' =>
object(stdClass)[397]
public 'managerId' => int 100011017901494
public 'urn:scim:schemas:extension:facebook:starttermdates:1.0' =>
object(stdClass)[398]
public 'startDate' => int 0
public 'termDate' => int 0
So as you can see, it returns other fields that are part of the 'core' schema, but is missing the 'photos' array and others. I thought this might have been because a user didnt have any photos, but almost all have profile pictures, and many have more. I tried getting their user information specifically but encountered the same result, no photos.
Anybody ever try something similar? Any help much appreciated, this has been a bit of a road block for us.
Thanks

To get profile information, don't use SCIM but graph API
https://graph.facebook.com/community/members will list all members
and https://graph.facebook.com/[email] for one of your member will get all infos.
After that you have to set the params you want to get with the fields param.
In our implementation we get the whole data from this request
https://graph.facebook.com/XXXX/members?fields=email,picture.type(large),link,title,first_name,last_name,department,updated_time,managers{email}&limit=500

Related

Laravel Livewire custom validation throws unexpected error "The given data was invalid"

I have a class in which default validation works just fine, but i have additional validation needs. All of the code is working fine including the default validation rules and messages defined in rules and messages function. for the sake of simplicity i'm providing the relevant code only.
The Problem:
In the store method i have a custom validator which should validate the uniquness of custom permission name. The validation rules returns this message "The given data was invalid."
I have tried different scenarios, for example: using different supposed name i.e. "permission_name", I have also tried rules in string instead of array.
$rules = ['permission_name' => 'unique:permissions,name'];
This does'nt work. Can anyone please point me in the right direct what is wrong here. Any help is appreciated in advance.
class CreatePermissionComponent extends Component
{
public $resource_name, $permission_type;
protected $validationAttributes = [
'resource_name' => 'resource name',
'permission_type' => 'permission type',
];
public function store()
{
$this->validate($this->rules(), $this->messages());
DB::beginTransaction();
try
{
// The problem
$input = ['name' => $this->resource_name . '.' . $this->permission_type];
$rules = ['name' => Rule::unique('permissions', 'name')];
$messages = ['name.unique' => 'The permission name ' . $this->resource_name . '.' . $this->permission_type . 'already exists.'];
$validatedData = Validator::make($input, $rules, $messages)->validate();
DB::commit();
ToasterHelperLivewire::toasterSuccess($this, $this->notifyMessage . ' Created Successfully.');
}
catch (\Exception $exception)
{
DB::rollback();
ToasterHelperLivewire::toasterErrorShort($this, $exception->getMessage());
}
}
public function updated($key, $value)
{
$this->validateOnly($key, $this->rules(), $this->messages());
}
protected function rules()
{
$rules = [
'resource_name' => ['required', 'alpha', 'min:3', 'max:50'],
];
if($this->permission_mode == 'single')
{
$rules['permission_type'] = ['required'];
}
else
{
$rules['permission_resource'] = ['min:1', 'array'];
}
return $rules;
}
protected function messages()
{
return [
'resource_name.alpha' => ':attribute may only contain alphabet and must be in this format. ex: users',
'permission_resource.min' => 'Please select at-least on checkbox from :attribute.',
];
}
}

Fail to mock object (Cakephp 3.0.3)

I am using Cakephp 3.0.3 and I have following method in my User Entity,
public function sendRecovery()
{
$email = new Email('default');
$email->viewVars([
'userId' => $this->id,
'token' => $this->token
]);
$email->template('GintonicCMS.forgot_password')
->emailFormat('html')
->to($this->email)
->from([Configure::read('admin_mail') => Configure::read('site_name')])
->subject('Forgot Password');
return $email->send();
}
i am writing testCase for it.
here is my testCase Method.
public function testSendRecovery()
{
$entity = new User([
'id' => 1,
'email' => 'hitesh#securemetasys.com',
'token' => 'jhfkjd456d4sgdsg'
]);
$email = $this->getMock('Cake\Network\Email\Email', ['sendRecovery']);
$email->expects($this->once())
->method('sendRecovery')
->with($this->equalTo('hitesh#securemetasys.com'));
$entity->sendRecovery();
}
when i run phpunit then i got following error,
There was 1 error:
1) GintonicCMS\Test\TestCase\Model\Entity\UserTest::testSendRecovery
InvalidArgumentException: Unknown email configuration "default".
E:\xampp\htdocs\Cake3\Proball-Market\plugins\GintonicCMS\vendor\cakephp\cakephp\src\Network\Email\Email.php:1382
E:\xampp\htdocs\Cake3\Proball-Market\plugins\GintonicCMS\vendor\cakephp\cakephp\src\Network\Email\Email.php:1269
E:\xampp\htdocs\Cake3\Proball-Market\plugins\GintonicCMS\vendor\cakephp\cakephp\src\Network\Email\Email.php:383
E:\xampp\htdocs\Cake3\Proball-Market\plugins\GintonicCMS\src\Model\Entity\User.php:90
E:\xampp\htdocs\Cake3\Proball-Market\plugins\GintonicCMS\tests\TestCase\Model\Entity\UserTest.php:73
can any one help me Please?

Doctrine - How to extract results and their relationships as array

I have an entity, call it Stones and Stones has a ManyToMany relationship with Attributes.
So I query the entity to get the Stones and then I hydrate this to convert it into an array.
$result = $this->stoneRepository->find($stone_id);
if ( ! $result )
{
return false;
}
$resultArray = $this->doctrineHydrator->extract($result);
This works fine for the Stone entity however I noticed that the join (Attributes) remain as objects.
array (size=12)
'id' => int 1
'name' => string 'Agate' (length=5)
'title' => string 'Title' (length=5)
'attribute' =>
array (size=5)
0 =>
object(Stone\Entity\StAttribute)[1935]
private 'id' => int 2
private 'name' => string 'Hay fevor' (length=9)
private 'state' => boolean true
private 'created' => null
private 'modified' => null
1 =>
object(Stone\Entity\StAttribute)[1936]
private 'id' => int 15
private 'name' => string 'Libra' (length=5)
private 'state' => boolean true
private 'created' => null
private 'modified' => null
2 =>
etc.
What is the process to hydrate the Attribute objects?
Hydration is populating an object (entity) using an array which is opposite of the extraction.
Since you want the resultset in array format, you should prevent unnecessary hydration and extraction process which already occurs in the ORM level under the hood.
Try to use Query Builder Api instead of built-in find() method of the entity repository. This is not a single-line but really straightforward and faster solution, it should work:
$qb = $this->stoneRepository->createQueryBuilder('S');
$query = $qb->addSelect('A')
->leftJoin('S.attribute', 'A')
->where('S.id = :sid')
->setParameter('sid', (int) $stone_id)
->getQuery();
$resultArray = $query->getOneOrNullResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
This way, you will also prevent running additional SQL queries against database to fetch associated entities. (StAttribute in your case)
I thought I would follow up on this to show how this can be resolved using a CustomStrategy.
By far the easiest and fastest method was suggested by foozy. What I like about the solution is that when I use hydration in ApiGility for instance I can build custom queries which will produce the desired result in a very few lines of code.
The other solution I was working on was to add a custom strategy:
<?php
namespace Api\V1\Rest\Stone;
use DoctrineModule\Stdlib\Hydrator\Strategy\AbstractCollectionStrategy;
use Zend\Stdlib\Hydrator\Strategy\StrategyInterface;
class CustomStrategy extends AbstractCollectionStrategy
{
public function __construct($hydrator)
{
$this->hydrator = $hydrator;
}
/**
* #param mixed $values
* #return array|mixed
*/
public function extract($values)
{
$returnArray = [];
foreach ($values AS $value)
{
$returnArray[] = $this->hydrator->extract($value);
}
return $returnArray;
}
/**
* #param mixed $values
* #return mixed
*/
public function hydrate($values)
{
$returnArray = [];
foreach ($values AS $value )
{
$returnArray[] = $this->hydrator->hydrate($value);
}
return $returnArray;
}
}
Then from the service side I add various strategies to the hydrator like so:
$result = $this->stoneRepository->find($stone_id);
$this->doctrineHydrator->addStrategy("product", new CustomStrategy( $this->doctrineHydrator ) );
$this->doctrineHydrator->addStrategy("attribute", new CustomStrategy( $this->doctrineHydrator ) );
$this->doctrineHydrator->addStrategy("image", new CustomStrategy( $this->doctrineHydrator ) );
$this->doctrineHydrator->addStrategy("related", new CustomStrategy( $this->doctrineHydrator ) );
$resultArray = $this->doctrineHydrator->extract($result);
After which I created a custom entity:
<?php
namespace Api\V1\Rest\Stone;
class StoneEntity
{
public $id;
public $name;
public $description;
public $code;
public $attribute;
public $product;
public $image;
public function getArrayCopy()
{
return array(
'id' => $this->id,
'name' => $this->name,
'description' => $this->description,
'code' => $this->code,
'attribute' => $this->attribute,
'product' => $this->product,
'image' => $this->image
);
}
public function exchangeArray(array $array)
{
$this->id = $array['id'];
$this->name = $array['name'];
$this->description = $array['description'];
$this->code = $array['code'];
$this->attribute = $array['attribute'];
$this->product = $array['product'];
$this->image = $array['image'];
}
}
And the final part is to exchange the returned data with the custom entity:
$entity = new StoneEntity();
$entity->exchangeArray($resultArray);
And finally to return the result:
return $entity;
To be honest, the above is just too long winded and my final solution as per the suggestion by foozy was this:
public function fetchOne($stone_id)
{
$qb = $this->stoneRepository->createQueryBuilder('S');
$query = $qb->addSelect('A','P','I','C')
->leftJoin('S.attribute', 'A')
->innerJoin('A.category', 'C')
->innerJoin('S.product' , 'P')
->innerJoin('S.image' , 'I')
->where('S.id = :sid')
->setParameter('sid', (int) $stone_id)
->getQuery();
$resultArray = $query->getOneOrNullResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
if ( ! $resultArray )
{
return false;
}
return $resultArray;
}

Cakephp mock Email Utility

i'm a little stuck trying to test my users-controller in cakephp,
i have an action wich sends an email to a certain email address.
The email utility works, no problem whatsoever.
I want to mock the email utility so that when i test the action (with "testAction"),
no email will be sent.
I already searched all over stackoverflow and tried a lot of solutions, the current code is like follows:
UsersController:
/**
* Get Email Utility, use method so that unit testing is possible
* #return object
*/
public function _getEmailer()
{
return new CakeEmail();
}
public function lostPassword()
{
if($this->request->is('post'))
{
$email = $this->request->data['User']['email'];
$this->User->recursive = -1;
$user = $this->User->find('first', array('conditions' => array('email' => $email)));
if(!$user)
{
$this->Session->setFlash('Error: user not found');
return $this->render();
}
$recoverTrials = $this->User->Recover->find('count', array('conditions' => array('email' => $email)));
if($recoverTrials > 3)
{
$this->Session->setFlash(__('message.recover-too-many'));
return $this->redirect('/');
}
// Generate random key to reset password
$key = md5(microtime().rand());
$data = array('user_id' => $user['User']['id'],
'key' => $key,
'active' => 1,
'created' => date('Y-m-d H:i:s'));
if(!$this->User->Recover->save($data))
{
$this->Session->setFlash('Error while sending the recovery-mail');
return $this->redirect('/');
}
$this->Email = $this->_getEmailer();
$this->Email->emailFormat('html');
$this->Email->to($email);
$this->Email->subject('Password recover');
$this->Email->replyTo('noreply#domain.com');
$this->Email->from(array('noreply#domain.com' => 'Sender ID'));
$this->Email->template('recover');
$this->Email->viewVars(array('key' => $key)); // Set variables for template
try
{
$this->Email->send();
}
catch(Exception $e)
{
$this->Session->setFlash('Error while sending the recovery-mail');
return $this->render();
}
$this->Session->setFlash('The recovery mail with instructions to reset your password has been sent. Please note that the link will only remain active for 2 hours.');
return $this->redirect('/');
}
}
And my test class looks like (excerpt):
public function testPostLostPassword()
{
$this->Controller = $this->generate('Users', array(
'methods' => array(
'_getEmailer'
),
'components' => array('Security')
));
$emailer = $this->getMock('CakeEmail', array(
'to',
'emailFormat',
'subject',
'replyTo',
'from',
'template',
'viewVars',
'send'
));
$emailer->expects($this->any())
->method('send')
->will($this->returnValue(true));
$this->Controller->expects($this->any())
->method('_getEmailer')
->will($this->returnValue($emailer));
Correct email
$data = array('User' => array('email' => 'me#domain.com'));
$result = $this->testAction('/lostPassword', array('method' => 'post',
'data' => $data,
'return' => 'contents'));
}
What am i doing wrong? The Email utility still sends out the email to my address, even though i mocked it...
Thanks in advance!

how to test Add when saving Associates Cakephp

how to test such a method:
public function add() {
if (!empty($this->request->data)) {
$this->Contest->create();
if ($this->Contest->saveAll($this->request->data)) {
$contestStage['name'] = 'First - ' . $this->request->data['Contest']['name'];
$contestStage['contest_id'] = $this->Contest->id;
if ($this->Contest->ContestStage->save($contestStage)) {
$this->setMessage(__ADD_OK, 'Konkurs');
$this->redirect(array(
'action' => 'view',
$this->Contest->id
));
} else {
$this->setMessage(__ADD_ERROR, 'Konkurs');
}
} else {
$this->setMessage(__ADD_ERROR, 'Konkurs');
}
}
}
my test method:
public function testAdd() {
$this->generateWithAuth(self::ADMIN); // genereting controller here
$url = $this->getUrl('add');
$options2 = array(
'method' => 'post',
'data' => array(
'Contest' => array(
'id' => 3,
'owner_id' => 1,
'name' => 'Testing',
'created' => '2012-11-16 12:02:33.946',
),
),
);
$this->testAction($url, $options2);
$this->assertArrayHasKey('Location', $this->headers, 'No redirection');
$this->assertEquals($this->Contest->hasAny(array('Contest.name' => 'Testing')), true);
$messages = Set::extract('{flash}.message', CakeSession::read('Message'));
}
what i receive is
PDOEXCEPTION
SQLSTATE[23505]: Unique violation: 7 BŁĄD: double key value violates a constraint
     uniqueness "contest_stages_pkey" DETAIL: Key (id)=(1) alredy exists.
Because it's true i have a contestStage with id=1
why its not using next one ;<
Its kinda strange that Cakephp does not document how to test that well.
The problem is that your inserting the Contest id twice. You should make sure that the db that your using has a test prefix (or whatever you like) and clear the test tables.
As an alternative, you could use fixtures instead. The data produces a much better test case as it pre populates the data for you so that you know whats in the db at any time. Still make sure to use a prefix, I made the mistake once of not doing that and it blew away my entire db every time
Good luck