How can I get available license via Google Workspace Admin SDK? - google-admin-sdk

On Google Admin screen, I can get numbers of available licenses and used licenses shown below:
How can I get these numbers via API?
Note: I read this question and tried, but not worked well.
-- EDIT: 2021/07/15 --
My request:
https://developers.google.com/admin-sdk/reports/reference/rest/v1/customerUsageReports/get
date: (few days before now)
parameters: accounts:gsuite_unlimited_total_licenses (comes from Account Parameters)
Response from API:
{
"kind": "admin#reports#usageReports",
"etag": "\"occ7bTD-Q2yefKPIae3LMOtCT9xQVZYBzlAbHU5b86Q/gt9BLwRjoWowpJCRESV3vBMjYMc\""
}
Expectation: I want to get the data same as 2 available, 1132 assigned as the GUI shows.
To be honestly, I'm not satisfying even if I can get info via this API, because it seems not responding real-time data like GUI.

I think there are 2 ways this information can be obtain, but I can confirm for only one of them.
1. Using the Report API that you mentioned.
NOTE : The report is not live data, so you must run the API call with a "date" parameter set at least 2 days before the execution date
Given that, you would have to run this GET method with the proper date in the {date} param
GET https://admin.googleapis.com/admin/reports/v1/usage/dates/{date}
Then you would need to parse through the parameters to find the desired license you are looking for.
reference - https://developers.google.com/admin-sdk/reports/reference/rest/v1/customerUsageReports#UsageReports
Here is how it look like after parsing
[
{
"BoolValue": null,
"DatetimeValueRaw": null,
"DatetimeValue": null,
"IntValue": 12065,
"MsgValue": null,
"Name": "accounts:gsuite_enterprise_total_licenses",
"StringValue": null
},
{
"BoolValue": null,
"DatetimeValueRaw": null,
"DatetimeValue": null,
"IntValue": 12030,
"MsgValue": null,
"Name": "accounts:gsuite_enterprise_used_licenses",
"StringValue": null
}
]
Important : The repot will always date 2 day back, so you can get the total number of licenses gsuite_enterprise_total_licenses in my example, and then use the Enterprise License Manager API to retrieve all currently assigned licenses
reference https://developers.google.com/admin-sdk/licensing/reference/rest
2. Using the Reseller API
Retrieving the information from the reseller point of view you would need to use the subscriptions.get method, providing your customerId and subscriptionId , calling the following GET request:
GET https://reseller.googleapis.com/apps/reseller/v1/customers/{customerId}/subscriptions/{subscriptionId}
The response of that would be a subscriptions resource, that contains various information about the license and the Seats object , which if you expand looks like this :
{
"numberOfSeats": integer,
"maximumNumberOfSeats": integer,
"licensedNumberOfSeats": integer,
"kind": string
}
numberOfSeats should be the total amount of licenses and licensedNumberOfSeats should be the number of users having that license assigned to them.
NOTE : in order to use this API , the given tenant should have a "fully executed and signed reseller contract" - https://developers.google.com/admin-sdk/reseller/v1/how-tos/prerequisites
Reference - https://developers.google.com/admin-sdk/reseller/reference/rest/v1/subscriptions

Answer:
You can only get the number of assigned licenses using the API, the number available isn't exposed and so does not get returned.
More Information:
Given that you have licenses assigned for your domain, and the user that is querying the API has access to this information, you can retrieve the data with the following request:
curl \
'https://admin.googleapis.com/admin/reports/v1/usage/dates/2021-07-10?parameters=accounts%3Agsuite_unlimited_total_licenses&fields=*&key=[YOUR_API_KEY]' \
--header 'Authorization: Bearer [YOUR_ACCESS_TOKEN]' \
--header 'Accept: application/json' \
--compressed
While not necessary, I added the parameter field=* in order to make sure all data is returned.
This gave me a response as such:
{
"kind": "admin#reports#usageReports",
"etag": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"usageReports": [
{
"kind": "admin#reports#usageReport",
"date": "2021-07-10",
"etag": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"entity": {
"type": "CUSTOMER",
"customerId": "C0136mgul"
},
"parameters": [
{
"name": "accounts:gsuite_unlimited_total_licenses",
"intValue": "233"
}
]
}
]
}
Here you can see that the intValue for accounts:gsuite_unlimited_total_licenses is 233 - which is reflected in the UI:
Feature Request:
You can however let Google know that this is a feature that is important for access to their APIs, and that you would like to request they implement it.
Google's Issue Tracker is a place for developers to report issues and make feature requests for their development services, I'd urge you to make a feature request there. The best component to file this under would be the Google Admin SDK component, with the Feature Request template.

I was not able to use Reseller API (ran into some authorization issues) and Reports API (contained null values in all relevant attributes). The only way I was able to find how many licenses were remaining was through Enterprise License Manager API.
After getting assignments, I used sdkName to filter records based on the type of license.
Here is the complete code.
function getRemainingGoogleUserLicensesCount() {
const GOOGLE_USER_LICENSES_TOTAL = 100 // You can find this from Google Admin -> Billing -> Subscriptions
const productId = 'Google-Apps';
const customerId = 'C03az79cb'; // You can find this from this response, https://developers.google.com/admin-sdk/directory/v1/guides/manage-users#json-response
let assignments = [];
let usedLicenseCount = 0
let pageToken = null;
do {
const response = AdminLicenseManager.LicenseAssignments.listForProduct(productId, customerId, {
maxResults: 500,
pageToken: pageToken
});
assignments = assignments.concat(response.items);
pageToken = response.nextPageToken;
} while (pageToken);
for (const assignment of assignments) {
if (assignment["skuName"] == "Google Workspace Business Plus") {
usedLicenseCount += 1
}
}
return GOOGLE_USER_LICENSES_TOTAL - usedLicenseCount
}

Related

How to get list of meaningful name upon fetching minted NFTs list from Alchemy Api?

I am new to block chain and I am using Alchemy and my NFTs and NFT Meta Data is on "Pinata". When I fetch my minted NFTs from Alchemy API, in response I get list of "contract addresses" and "Token Ids". Is there any way to get list of meaningful names of my minted NFTs instead of ids (without using loops). OR is there a way to store a meaningful name upon minting . Any help will be appreciated.
response upon calling API :
{"balance": "1", "contract": {"address": "0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}, "id": {"tokenId": "0x0000000000000000000000000000000000000000000000000000000000000000"}}]```
Is there any way to get list of meaningful names of my minted NFTs instead of ids (without using loops).
Yes! As of July 12th, 2022 (current time) -- the getNFTs endpoint includes a withMetadata query param option that defaults to true (see docs).
That means that the response should include the info you might want, including:
title: name of the NFT asset
description: brief human-readable description
media.gateway: public gateway uri for the raw asset
etc.
See full documentation here: https://docs.alchemy.com/alchemy/enhanced-apis/nft-api/getnfts
An example response might look like this:
{
"ownedNfts": [
{
"contract": {
"address": "0x0beed7099af7514ccedf642cfea435731176fb02"
},
"id": {
"tokenId": "28",
"tokenMetadata": {
"tokenType": "ERC721"
}
},
"title": "DuskBreaker #28",
"description": "Breakers have the honor of serving humanity through their work on The Dusk. They are part of a select squad of 10,000 recruits who spend their days exploring a mysterious alien spaceship filled with friends, foes, and otherworldly technology.",
"tokenUri": {
"raw": "https://duskbreakers.gg/api/breakers/28",
"gateway": "https://duskbreakers.gg/api/breakers/28"
},
"media": [
{
"raw": "https://duskbreakers.gg/breaker_images/28.png",
"gateway": "https://duskbreakers.gg/breaker_images/28.png"
}
],
"metadata": {
...
}
},
...
]
...
}
You should then be able to do something like this to get your names:
const names = ownedNfts.map((nft) => nft.title};
Use the getNFTMetadata method to get information on each NFT.

AWS Kendra PreHook Lambdas for Data Enrichment

I am working on a POC using Kendra and Salesforce. The connector allows me to connect to my Salesforce Org and index knowledge articles. I have been able to set this up and it is currently working as expected.
There are a few custom fields and data points I want to bring over to help enrich the data even more. One of these is an additional answer / body that will contain key information for the searching.
This field in my data source is rich text containing HTML and is often larger than 2048 characters, a limit that seems to be imposed in a String data field within Kendra.
I came across two hooks that are built in for Pre and Post data enrichment. My thought here is that I can use the pre hook to strip HTML tags and truncate the field before it gets stored in the index.
Hook Reference: https://docs.aws.amazon.com/kendra/latest/dg/API_CustomDocumentEnrichmentConfiguration.html
Current Setup:
I have added a new field to the index called sf_answer_preview. I then mapped this field in the data source to the rich text field in the Salesforce org.
If I run this as is, it will index about 200 of the 1,000 articles and give an error that the remaining articles exceed the 2048 character limit in that field, hence why I am trying to set up the enrichment.
I set up the above enrichment on my data source. I specified a lambda to use in the pre-extraction, as well as no additional filtering, so run this on every article. I am not 100% certain what the S3 bucket is for since I am using a data source, but it appears to be needed so I have added that as well.
For my lambda, I create the following:
exports.handler = async (event) => {
// Debug
console.log(JSON.stringify(event))
// Vars
const s3Bucket = event.s3Bucket;
const s3ObjectKey = event.s3ObjectKey;
const meta = event.metadata;
// Answer
const answer = meta.attributes.find(o => o.name === 'sf_answer_preview');
// Remove HTML Tags
const removeTags = (str) => {
if ((str===null) || (str===''))
return false;
else
str = str.toString();
return str.replace( /(<([^>]+)>)/ig, '');
}
// Truncate
const truncate = (input) => input.length > 2000 ? `${input.substring(0, 2000)}...` : input;
let result = truncate(removeTags(answer.value.stringValue));
// Response
const response = {
"version" : "v0",
"s3ObjectKey": s3ObjectKey,
"metadataUpdates": [
{"name":"sf_answer_preview", "value":{"stringValue":result}}
]
}
// Debug
console.log(response)
// Response
return response
};
Based on the contract for the lambda described here, it appears pretty straight forward. I access the event, find the field in the data called sf_answer_preview (the rich text field from Salesforce) and I strip and truncate the value to 2,000 characters.
For the response, I am telling it to update that field to the new formatted answer so that it complies with the field limits.
When I log the data in the lambda, the pre-extraction event details are as follows:
{
"s3Bucket": "kendrasfdev",
"s3ObjectKey": "pre-extraction/********/22736e62-c65e-4334-af60-8c925ef62034/https://*********.my.salesforce.com/ka1d0000000wkgVAAQ",
"metadata": {
"attributes": [
{
"name": "_document_title",
"value": {
"stringValue": "What majors are under the Exploratory track of Health and Life Sciences?"
}
},
{
"name": "sf_answer_preview",
"value": {
"stringValue": "A complete list of majors affiliated with the Exploratory Health and Life Sciences track is available online. This track allows you to explore a variety of majors related to the health and life science professions. For more information, please visit the Exploratory program description. "
}
},
{
"name": "_data_source_sync_job_execution_id",
"value": {
"stringValue": "0fbfb959-7206-4151-a2b7-fce761a46241"
}
},
]
}
}
The Problem:
When this runs, I am still getting the same field limit error that the content exceeds the character limit. When I run the lambda on the raw data, it strips and truncates it as expected. I am thinking that the response in the lambda for some reason isn't setting the field value to the new content correctly and still trying to use the data directly from Salesforce, thus throwing the error.
Has anyone set up lambdas for Kendra before that might know what I am doing wrong? This seems pretty common to be able to do things like strip PII information before it gets indexed, so I must be slightly off on my setup somewhere.
Any thoughts?
since you are still passing the rich text as a metadata filed of a document, the character limit still applies so the document would fail at validation step of the API call and would not reach the enrichment step. A work around is to somehow append those rich text fields to the body of the document so that your lambda can access it there. But if those fields are auto generated for your documents from your data sources, that might not be easy.

Instagram: Graph API does not return id of user who commented

I am using Facebook Graph v7.0 to access Instagram data.
I can get comments made on instagram media using the following query:
Request:
https://graph.facebook.com/v7.0/18132613492054980?fields=id,ig_id,caption,timestamp,owner,username,media_type,permalink,children,comments.limit(100){hidden,id,like_count,media,text,timestamp,user,username},comments_count&access_token
Response:
{
"id": "18132613492054980",
"ig_id": "2263043983231761272",
"caption": "Sprite",
"timestamp": "2020-03-12T06:51:27+0000",
"owner": {
"id": "17841430463493290"
},
"username": "jobyjohn123456",
"media_type": "IMAGE",
"permalink": "https://www.instagram.com/p/B9n8oM7nTt4/",
"comments": {
"data": [
{
"hidden": false,
"id": "18132938077057326",
"like_count": 0,
"media": {
"id": "18132613492054980"
},
"text": "Nice sprite \u0040yziaf__07",
"timestamp": "2020-03-12T06:52:27+0000",
"username": "zimba_birbal"
}
]
},
"comments_count": 2
}
In the response, I do not get the User Id of user who commented. It just includes the username of the commenter.
Though, I pass user in the query, the result does not include it.
Do I need any special permission to get user id of the user who commented in the comment response?
There is Facebook API "business discovery" to get the user details of other Instagram User.
API request:
https://graph.facebook.com/178430463490?fields=business_discovery.username(user_name_you_wantto_get_its_IgUserId){followers_count,media_count,username,ig_id}
Response:
We can pass the user name in that API request, then we will get the Instagram User Id.
The documentation says it has one limitation, this will not work for "age-gated Instagram Business IG Users" but I do not exactly know what it means. When I tested for both older Instagram account and new Instagram account (just recently created account) and this API is returning data for both.
When I tested for private Instagram account, it did not work so it seems this api works only for business account.
If that api does not work, there is one workaround. The following request help to get User Id using its username but I have not found any API documentation regarding this API. It looks like this is not a standard API and moreover it does not need any token.
https://www.instagram.com/user_name_you_wantto_get_its_IgUserId/?__a=1

How to get user attributes (username, email, etc.) using cognito identity id

I have AWS Cognito Identity Pool that is configured with Cognito User Pool as an authentication provider.
Assume I have identity ID of an identity in Cognito Identity Pool (e.g. us-east-1:XXaXcXXa-XXXX-XXXX-XXX-XXXXXXXXXXXX) where this identity has a linked login to a user in Cognito User Pool.
Using identity ID, how can I get the linked user details (email, phone, username)?
The ID Token that you exchange with Cognito federated identity service to get the identity id and credentials already has all user attributes. You do not need an extra call to any service.
It is a JWT token and you can use any library on the client to decode the values. You can read this guide for more information about the tokens vended by Cognito user pools.
Alternatively, you can also use the Access Token to call GetUser API which will return all the user information.
Using REST API
AccessToken
Thought that this could be very helpful to someone as I've spent a lot of time trying to figure out how to get UserAttributes with only accessToken and region ( Similar to this but with REST API ( Without using aws-sdk )
You can get UserAttributes with accessToken using this HTTP request. ( GetUser )
Method: POST
Endpoint: https://cognito-idp.{REGION}.amazonaws.com/
Content-Type: application/x-amz-json-1.1
Content-Length: 1162 // Access Token bytes length
X-Amz-Target: AWSCognitoIdentityProviderService.GetUser
Body: {"AccessToken":"ACCESS_TOKEN"}
And if the accessToken is valid, you should receive example response like the following
{
"UserAttributes": [
{
"Name": "sub",
"Value": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx"
},
{
"Name": "email_verified",
"Value": "true"
},
{
"Name": "name",
"Value": "Jason"
},
{
"Name": "phone_number_verified",
"Value": "true"
},
{
"Name": "phone_number",
"Value": "+xxxxxxxxxxx"
},
{
"Name": "email",
"Value": "xxxx#gmail.com"
}
],
"Username": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx"
}
AWS cognito-idp list-users has a filter option that allows you to filter based on attribute. 'sub' is the attribute that matches the identity id you are describing.
e.g. at the command line:
aws cognito-idp list-users --user-pool-id us-east-1_abcdFghjI --filter "sub=\":XXaXcXXa-XXXX-XXXX-XXX-XXXXXXXXXXXX\""
This also requires the user-pool-id, which I suspect you have. Additionally, I have no idea how this is implemented or how it performances when filtering a large number of users, but I take custom attributes not being usable in filters as a hint that there is some form of indexing behind the curtain.
I faced the similar issue and after too much of scratching i was not able to find the exact way of pulling out the details. My usecase was to get the details in android APP.
After looking into their AWSMobile client API code. I found below and it is working from me.
Log.i(TAG, "User Details"+ AWSMobileClient.getInstance().getUserAttributes().toString());
Recommendation - Try use AWSMobileclient incase you are using it for Android Development as this is new library that is recommended for development.
Just struggled with this for a while, and the way I got the user name, using Java API is:
identityManager.login(this, new DefaultSignInResultHandler() {
#Override
public void onSuccess(Activity activity, IdentityProvider identityProvider) {
...
String userName = ((CognitoUserPoolsSignInProvider) identityProvider).getCognitoUserPool().getCurrentUser().getUserId();
There is a listener we can initialize that will listen to changes in our authentication state and allow us to have access to the type of authentication event that happened and update the application state based on that data.
With Amplify, the Hub module allows us to do this pretty easily:
import { Hub } from 'aws-amplify';
Hub.listen('auth', (data) => {
const {payload} = data;
if (payload.event === 'signOut') {
console.log('signOut');
} else if (payload.event === 'signIn') {
console.log('A new auth event has happened: ', data.payload.data.username + ' has ' + data.payload.event);
}
});
For those who are looking how to get the value of email parameter in Java programmatically
I assume you have already figured out how to get the needed / all users from the pool.
Say I have ListUsersResult with my all users and say I want to check the email value of the first user:
ListUsersResult allUsers = getAllUsers();
UserType userType = allUsers.getUsers().get(0);
First I can get user's all attributes:
List<AttributeType> attributes = userType.getAttributes();
Then loop through the attributes looking for the one we're interested in (our case email):
for (AttributeType att : attributes) {
if (att.getName().equals("email")) {
// do whatever you want
}
}
Remember that printing in to the console will most probably not work since it is sensitive data. But you can compare it like this:
att.getValue().equals("mymail#mail")
Use this piece of code
GetDetailsHandler detailsHandler = new GetDetailsHandler() {
#Override
public void onSuccess(CognitoUserDetails cognitoUserDetails) {
CognitoUserAttributes cognitoUserAttributes=cognitoUserDetails.getAttributes();
stringStringHashMap=new HashMap<>();
stringStringHashMap =cognitoUserAttributes.getAttributes();
userNumber=stringStringHashMap.get("phone_number");
e1.setText(userNumber);
Log.d("Response"," Inside DEATILS HANDLER");
// Store details in the AppHandler
AppHelper.setUserDetails(cognitoUserDetails);
// Trusted devices?
handleTrustedDevice();
// e1.setText(input.getText().toString());
}
#Override
public void onFailure(Exception exception) {
closeWaitDialog();
showDialogMessage("Could not fetch user details!", AppHelper.formatException(exception), true);
}
};
private void getDetails() {
AppHelper.getPool().getUser(username).getDetailsInBackground(detailsHandler);
}
console.log('username is ' + cognitoUser.getUsername());

Facebook graph api. how to list all pages that my app is subscribed to?

So I am aware of how to check each page to get a list of all subscribed apps.
But I would like to get a list of all pages my app has real time update subscriptions for?
so i have tried this
https://graph.facebook.com/v2.5/$app_id/subscriptions?access_token=$app_token
but this just brings back basic info on the app.
I would like a list of pages that it has subscriptions to already?
Can anyone help?
This doesn't look to be possible.
Endpoint you're using - https://developers.facebook.com/docs/graph-api/reference/v2.8/app/subscriptions - is to get list of application webhooks (callback_url and type of changes), which are called subscriptions for some reason. It's not about pages that subscribed to this webhook (or this app in general).
Overall, even in https://developers.facebook.com/apps/ for your app, under e.g. Messenger tab, you will only see subset of all pages that subscribed to this app. The visible subset is limited by your facebook user account permissions, presumably only show pages that you're either Admin or Editor.
Therefore, if such call would be possible, it would be somehow tied to User Access Token as well, not only app token.
You can do this here: https://developers.facebook.com/tools/explorer
Once logged, you can click on right button and select "Get User Access Token". You will need at least manage_pages or pages_show_list permission to accomplish this.
Now, all you have to do is call this endpoint: /me/accounts.
It should list all subscribed pages on your app.
Hope it helps.
As per
https://developers.facebook.com/docs/facebook-login/access-tokens/#apptokens
it is possible (graph api):
GET /oauth/access_token
?client_id={app-id}
&client_secret={app-secret}
&grant_type=client_credentials
And then /<app_id>/subscriptions
which returns something like:
{
"data": [
{
"object": "application",
"callback_url": "https:...",
"active": true,
"fields": [
{
"name": "ads_rules_engine",
"version": "v2.9"
}
]
},
{
"object": "page",
"callback_url": "https://...",
"active": true,
"fields": [
{
"name": "leadgen",
"version": "v2.5"
}
]
}
]
}