Why does Graph API return a "not found" error when querying for user attributes? - graph

I am relatively new to Microsoft Graph API. I am trying to extract a list of user profile information. When I run either of the following requests, I get a valid response:
Get displayname and birthday for single user:
GET https://graph.microsoft.com/v1.0/users/___userID___?$select=displayName,birthday
Get displayname for all users:
GET https://graph.microsoft.com/v1.0/users/?$select=displayName
However, when I try to run the following query, I receive an error:
Get displayname and birthday for all users:
GET https://graph.microsoft.com/v1.0/users/?$select=displayName,birthday
The error I receive is as follows:
{
"error": {
"code": "UnknownError",
"message": "",
"innerError": {
"date": "2023-02-02T05:57:08",
"request-id": "e8ae37af-3478-4446-a328-9d79f7aac0fc",
"client-request-id": "a667c3f1-0183-3382-c601-2197456a758d"
}
}
}
This error seems to occur with only some attribute types, forexample hiredate and birthday. If I query for displayname and userprincipalname, I do get the same error.
I would appreciate any suggestions.

For anyone reading this in the future, I was able to achieve my desired outcome using the following script.
Thanks to user2250152's answer, I realized I could not query for the necessary properties in bulk. So I used PowerShell to first pull a list of all users, and then loop through each of them to query the required properties.
# Report on User Profiles in SPO
# Define attributes to query
$attributes = #("displayname","aboutMe","skills","interests","birthday","hireDate")
# Connect to Graph
Connect-MgGraph -Scopes "User.Read.All"
Select-MgProfile -Name beta
# Get list of active users
$users = Get-MgUser -All | Where-Object {($_.AccountEnabled -eq $true) -and ($_.OnPremisesSyncEnabled -eq $true) -and ($_.UserType -eq "Member")}
# Loop through all users and query for SPO profile attributes
$results = #()
foreach ($user in $users) {
$query = Get-MgUser -UserID $user.Id -Select $attributes | Select-Object $attributes
$results += $query
}
# Display Results
$results | Out-GridView

According to the documentation, properties aboutMe, birthday, hireDate, interests, mySite, pastProjects, preferredName, responsibilities, schools, skills, mailboxSettings cannot be returned within a user collection.
They are only supported when retrieving a single user.

Related

Getting An Error when trying to create a subcollection in Firestore

I am trying to create a node in Google Firebase, and use its unique id to create a Document in Google Firestore of the same name.
I'm using Google's PHP Firestore Client: https://github.com/GoogleCloudPlatform/google-cloud-php-firestore
And I've read through their documentation: http://googlecloudplatform.github.io/google-cloud-php/#/docs/cloud-firestore/v0.5.1/firestore/writebatch
Here is my code:
<?php
use \Google\Cloud\Firestore\FirestoreClient;
use \Google\Cloud\Core\Timestamp;
use \Google\Cloud\Firestore\Transaction as FirestoreTransaction;
use \grptx\Firebase as FirebaseClient;
class FirestoreTest
{
public function create()
{
$client = new FirebaseClient();
$database = $client->getDatabase();
$org = array(
"acl" => array(),
"people" => array()
);
$ref = $database->getReference("/clients/")->push($org);
$key = $ref->getKey();
$config = array(
"projectId" => "xxx",
"keyFile" => json_decode(file_get_contents("/xxx/firebase_auth.json"), true)
);
$firestore = new FirestoreClient($config);
$batch = $firestore->batch();
$collection = $firestore->collection("clients")->document("-LXXXXXX")->collection("trips");
}
}
And I get this error:
Exception 'Google\Cloud\Core\Exception\BadRequestException' with message '{
"message": "Document name \"projects\/xxx-test\/databases\/(default)\/documents\/clients\/\" has invalid trailing \"\/\".",
"code": 3,
"status": "INVALID_ARGUMENT",
"details": []
}'
Any help is appreciated.
Basically this will happen if you try to put blank as document name.
This is the error that occurs if you try to get a collection as a document. It's kind of tricky because this can also happen if you try to get a document with the name of empty string in a collection.
I don't know PHP, but I would guess that either in your $database->getReference("/clients/")->push($org); call, you were supposed to name a document to push your information to, or in your $firestore->collection("clients")->document("-LXXXXXX")->collection("trips"); call that the document you are trying to get ("-LXXXXXX") has the name empty string. (Of course, this is assuming your document isn't actually named "-LXXXXXX", and you are using that as a substitute for some variable that happens to be equal to "").
For instance, in python this call randomly failed me earlier:
db.collection(u'data').document(current_id)
with the same error: 'Document name ".../documents/data/" has invalid trailing "/". and will exit.' I scratched my head for a while but that's because the variable current_id is the empty string.
Basically, internally Firebase converts it into a long pathname and then tries to get a document or a collection at that pathname depending on what your last call was. This causes an issue if you try to get a document that is named "".

google calendar api Error 400 - Invalid resource id value

I want to insert events in Google calendar through the API using a Symfony command (batch).
When I insert an event with an ID like "event01487", it throws me the following errors : "code": 400, "message": "Invalid resource id value."
This id is unique as no events have been inserted - it didn't even insert it once. The id seems to fit the Google requirements...
Do you have any idea why I got this ?
foreach($bookingsToSync as $booking){
$event = new Google_Service_Calendar_Event();
$event->setId($booking['id']);
$event->setSummary($booking['title']);
$event->setDescription($booking['description']);
$start = new \Google_Service_Calendar_EventDateTime();
$start->setDateTime($booking['startDate']->format(DateTime::ATOM));
$event->setStart($start);
$end = new \Google_Service_Calendar_EventDateTime();
$end->setDateTime($booking['endDate']->format(DateTime::ATOM));
$event->setEnd($end);
$output->writeln($event->getId());
$service->events->insert($calendarId, $event);
}
You have to follow the guidelines defined here : https://developers.google.com/google-apps/calendar/v3/reference/events/insert
Basically, the id has to be between 5 and 1024 characters and be composed from characters in this alphabet : 0123456789abcdefghijklmnopqrstuv
You should encode your id as base32
$encoded = bin2hex( $booking['id'] );
To Decode
$decoded = hex2bin( $encoded );

WooCommerce REST Client API - Programmatically get consumer key and secret

I am currently using the client-API to implement a simple user front-end to upload products. The function client->products->create() seems to work fine, how ever I can’t get around one issue.
Every time I upload a product, the vendor is set to the admin user instead of the user that is currently logged in. Is there a way to set the vendor through the API? Has anybody get done this?
This is the function I created that is called by AJaX when the form is submitted (I left key and website fields empty here on purpose):
function addProduct()
{
$options = array(
'debug' => false,
'return_as_array' => false,
'validate_url' => false,
'timeout' => 30,
'ssl_verify' => false,
);
try {
$client = new WC_API_Client('', '', '', $options);
$productName = $_POST["productname"];
$price = $_POST["price"];
$discountPrice = $_POST["discountPrice"];
$description = $_POST["description"];
$shortDescription = $_POST["shortDescription"];
$authorId = 5;
$client->products->create(array('title' => $productName, 'type' => 'simple', 'regular_price' => $price, 'description' => $description));
} catch (WC_API_Client_Exception $e) {
echo $e->getMessage() . PHP_EOL;
echo $e->getCode() . PHP_EOL;
if ($e instanceof WC_API_Client_HTTP_Exception) {
print_r($e->get_request());
print_r($e->get_response());
}
}
echo ("Publicado" . $authorId);
// Una función AJaX en WordPress debe siempre terminarse con die().
die();
}
The problem seems to be the consumer key and consumer secret, so, is there a way to programmatically provide the clients with API keys and get these dynamically?
UPDATE: The method to obtain the consumer key described below will not work; it is no longer possible to get hold of the consumer key from the database once it has been generated. The consumer key stored in this new table is not the same consumer key that is generated in the admin screens and passed out to the end user. It appears to be an SHA256 hashed a version of this key. This is more secure (previously the consumer key and secret stored in wp_usermeta was tantamount to storing clear-text passwords, as anyone with access to that data would be able to log into the API as any of those users), but is a little less convenient. Win some, lose some, but win on security.
Your new WC_API_Client() will take three parameters before the options: $store_url, $consumer_key and $consumer_secret.
Any user on the WC shop who is to be used to access the API will need a consumer key or consumer secret. The consumer key will identify which user the API will run as, and it is that user which will be linked to any entities created through the API.
Until recently, you could get these two pieces of information for a user like this:
$consumer_key = get_user_meta($user_id, 'woocommerce_api_consumer_key', true);
$consumer_secret = get_user_meta($user_id, 'woocommerce_api_consumer_secret', true);
Where $user_id is the ID for the user that will be creating items. If you want the current logged in user to be able to create items in their name then that user would need to be given a consumer key and secret, and would need to be in an appropriate WC/WP group to give them permission to do so.
Note, that if you do this, then the user will also have access to the admin pages for WC to create these items, and not just through the API.
In later versions of WC, the user meta items have been moved to a separate table: wp_woocommerce_api_keys so you need to look in there instead of in the user meta.
This will get you the consumer key and secret for a given user ID:
global $wpdb;
$key = $wpdb->get_row( $wpdb->prepare("
SELECT consumer_key, consumer_secret, permissions
FROM {$wpdb->prefix}woocommerce_api_keys
WHERE user_id = %d
", $user_id), ARRAY_A);
the results being something like this:
array(3) {
["consumer_key"]=>
string(64) "58043812eee6aa75c80407f8eb9cec025825f138eb7d60118af66cf4b38060fa"
["consumer_secret"]=>
string(43) "cs_1da716412bb9680d8b06b09160872b7e54416799"
["permissions"]=>
string(10) "read_write"
}
I am, of course, assuming you are using the API to "loop back" to the current site and not accessing a remote site. Using the WC API to create products even on the current site can be very much more convenient than going through the PHP object API.
I have not yet found any public WC methods to get these details; they are all private and assume only WC needs to know these details.
Yes there is a fine customization that you need to do in your code that is as follows:
Background information:
Each users Consumer Key,Consumer Secret Key and read/write permissions (if WooCommerce API Keys are generated for that users) are stored in wordpress's usermeta table with a meta_keys as 'woocommerce_api_consumer_key', 'woocommerce_api_consumer_secret' and 'woocommerce_api_key_permissions' respectively.
So you just need to get the current users id first then get that user's meta value as mention above assign to some variables and send them as a parameter.
I think the problem is generate programmatically the API keys for that customer for witch you want consume the woocommerce service, because the keys ar owned for each users and there aren't be useful for other users.
My advice is looking admin source code of woocommerce.

Get the name of all the tables on my database

I need get the name of all the tables that exist on my database. I am usin Propel like my ORM. Actully i have been trying on this form.
$dbmap = \Propel::getDatabaseMap('data');
$tablastmp = $dbmap->getTables();
$tablas = array();
foreach ($tablastmp as $tablatmp) {
$tablas[] = $tablatmp->getName();
}
echo '<pre>';
print_r($tablas);
echo '</pre>';
die();
but this return an array that is empty.
array();
And I need that return something like that:
array( [0] => 'clients', [1] => 'workers' );
Please someone help. I have been trying that for a few days.
Actually, you probably wouldn't use Propel to get this information as Propel only loads the table map information when the table is actually used.
The original Schema file is used during the build phase (running 'propel_gen om' etc). The runtime part of Propel never looks at the Schema file, so there is no way to query it per se.
The answer to your question is to look at the database, e.g. the MySQL query to list the tables in a database:
SHOW [FULL] TABLES [{FROM | IN} db_name]
[LIKE 'pattern' | WHERE expr]
This might help you (hopefully)
$em = $this->getDoctrine()->getManager();
foreach ($em->getMetadataFactory()->getAllMetadata() as $md) {
var_dump($md->getName()); // dump the full class names
var_dump($md->getTableName()); // dump the table names
}

Best practice for storing simple variables like 'total rows' in Symfony2

In my symfony2 application I need to display some totals at the top of all pages, ie "Already 200,154,555 users registered".
I don't want to run the query to come up with that count on every page load. The solution I've come up with is to create a "variable" entity that would have two columns, name and value. Then I would set up a console command that runs on cron which would update these variable entities (eg "totalPeople") with a query that counted all the rows of people, etc.
This feels a little heavy handed... Is there a better solution to this problem?
You could set global parameters and add a service to rewrite them. Then call the service from your Command.
Or directly set up a service to read/write a file (as a json array for example).
Or set up a option table with a row storing the data. It's not going to be a resource intensive query that way.
Here is what I'm using to store RSS feeds (after I parsed them)
public function checkCache($data=array(), $path = '')
{
foreach ($data as $service => $feed)
{
$service = strtolower($service);
$service = str_replace(' ', '-', $service);
$path = $path.'web/bundles/citation/cache/rss/' . $service . '.cache';
if ((!file_exists($path) || time() - filemtime($path) > 900) && $cache = fopen($path, 'w'))
{
$rss_contents = $this->getFeed($feed); //fetch feed content & returns array
fwrite($cache, serialize($rss_contents));
fclose($cache);
return $rss_contents;
}
else
{
$cache = fopen($path, 'r');
return unserialize(file_get_contents($path));
fclose($cache);
}
}
}
You can implement that on your backend for example so every time an admin logs it'll check for cache and refresh only if it's too old. Although I'm quite fond of the 4AM cron job solution too.
You could use the pagination feature of doctrine (if you use doctrine). That will leverage the "limit" part of your queries (even with joins) and will give you a total count of rows (via a count query).

Resources