Get all clientID from MCC adwords account by adwordsAPI - google-ads-api

I want to retrieve all clientID from my MCC account. I'm using this code
AdWordsUser user = new AdWordsUser(adwordsPropertyService.getEmail(), adwordsPropertyService.getPassword(),
null, adwordsPropertyService.getUseragent(), adwordsPropertyService.getDeveloperToken(),
adwordsPropertyService.getUseSandbox());
InfoServiceInterface infoService = user.getService(AdWordsService.V201109.INFO_SERVICE);
InfoSelector selector = new InfoSelector();
selector.setApiUsageType(ApiUsageType.UNIT_COUNT_FOR_CLIENTS);
String today = new SimpleDateFormat("yyyyMMdd").format(new Date());
selector.setDateRange(new DateRange(today, today));
selector.setIncludeSubAccounts(true);
ApiUsageInfo apiUsageInfo = infoService.get(selector);
for (ApiUsageRecord record : apiUsageInfo.getApiUsageRecords()) {
......
But apiUsageInfo.getApiUsageRecords return my only some clientId.
Have you any suggests?

My Answer will be helpful for PHP Developers
I am using v201502(php), You will get all account details from ManagedCustomerService api. Please refer the following URL https://developers.google.com/adwords/api/docs/reference/v201502/ManagedCustomerService
This is the sample code i used,
function DisplayAccountTree($account, $link, $accounts, $links, $depth) {
print str_repeat('-', $depth * 2);
printf("%s, %s\n", $account->customerId, $account->name);
if (array_key_exists($account->customerId, $links)) {
foreach ($links[$account->customerId] as $childLink) {
$childAccount = $accounts[$childLink->clientCustomerId];
DisplayAccountTree($childAccount, $childLink, $accounts, $links,
$depth +1);
}
}
}
function GetAccountHierarchyExample(AdWordsUser $user) {
// Get the service, which loads the required classes.
$user->SetClientCustomerId('xxx-xxx-xxxx');
$managedCustomerService =
$user->GetService('ManagedCustomerService');
// Create selector.
$selector = new Selector();
// Specify the fields to retrieve.
$selector->fields = array('CustomerId', 'Name');
// Make the get request.
$graph = $managedCustomerService->get($selector);
// Display serviced account graph.
if (isset($graph->entries)) {
// Create map from customerId to parent and child links.
$childLinks = array();
$parentLinks = array();
if (isset($graph->links)) {
foreach ($graph->links as $link) {
$childLinks[$link->managerCustomerId][] = $link;
$parentLinks[$link->clientCustomerId][] = $link;
}
}
// Create map from customerID to account, and find root account.
$accounts = array();
$rootAccount = NULL;
foreach ($graph->entries as $account) {
$accounts[$account->customerId] = $account;
if (!array_key_exists($account->customerId, $parentLinks)) {
$rootAccount = $account;
}
}
// The root account may not be returned in the sandbox.
if (!isset($rootAccount)) {
$rootAccount = new Account();
$rootAccount->customerId = 0;
}
// Display account tree.
print "(Customer Id, Account Name)\n";
DisplayAccountTree($rootAccount, NULL, $accounts, $childLinks, 0);
} else {
print "No serviced accounts were found.\n";
}
}
GetAccountHierarchyExample($user);
SetClientCustomerId will be the parent ID of your all accounts, It will be appeared near the Sign Out button of you google AdWords account, Please see the attached image
I hope this answer will be helpful, Please add your comments below if you want any further help

If you need just the list of clientCustomerIds, try ServicedAccountService.
Here is a code example that shows how this may be done.
Next time, you might also want to consider asking the question on the official forum for AdWords API: https://groups.google.com/forum/?fromgroups#!forum/adwords-api

Related

Create team in GraphAPI returns always null

I am using GraphAPI SDK to create a new Team in Microsoft Teams:
var newTeam = new Team()
{
DisplayName = teamName,
Description = teamName,
AdditionalData = new Dictionary<string, object>()
{
{"template#odata.bind", "https://graph.microsoft.com/v1.0/teamsTemplates('standard')"}
},
Members = new TeamMembersCollectionPage()
{
new AadUserConversationMember
{
Roles = new List<String>()
{
"owner"
},
AdditionalData = new Dictionary<string, object>()
{
{"user#odata.bind", $"https://graph.microsoft.com/v1.0/users/{userId}"}
}
}
}
};
var team = await this.graphStableClient.Teams
.Request()
.AddAsync(newTeam);
The problem is that I get always null. According documentation this method returns a 202 response (teamsAsyncOperation), but the AddAsync method from SDK returns a Team object. Is there any way to get the tracking url to check if the team creation has been finished with the SDK?
Documentation and working SDK works different... As they wrote in microsoft-graph-docs/issues/10840, we can only get the teamsAsyncOperation header values if we use HttpRequestMessage as in contoso-airlines-teams-sample. They wrote to the people who asks this problem, look to the joined teams :)) :)
var newTeam = new Team()
{
DisplayName = model.DisplayName,
Description = model.Description,
AdditionalData = new Dictionary<string, object>
{
["template#odata.bind"] = $"{graph.BaseUrl}/teamsTemplates('standard')",
["members"] = owners.ToArray()
}
};
// we cannot use 'await client.Teams.Request().AddAsync(newTeam)'
// as we do NOT get the team ID back (object is always null) :(
BaseRequest request = (BaseRequest)graph.Teams.Request();
request.ContentType = "application/json";
request.Method = "POST";
string location;
using (HttpResponseMessage response = await request.SendRequestAsync(newTeam, CancellationToken.None))
location = response.Headers.Location.ToString();
// looks like: /teams('7070b1fd-1f14-4a06-8617-254724d63cde')/operations('c7c34e52-7ebf-4038-b306-f5af2d9891ac')
// but is documented as: /teams/7070b1fd-1f14-4a06-8617-254724d63cde/operations/c7c34e52-7ebf-4038-b306-f5af2d9891ac
// -> this split supports both of them
string[] locationParts = location.Split(new[] { '\'', '/', '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
string teamId = locationParts[1];
string operationId = locationParts[3];
// before querying the first time we must wait some secs, else we get a 404
int delayInMilliseconds = 5_000;
while (true)
{
await Task.Delay(delayInMilliseconds);
// lets see how far the teams creation process is
TeamsAsyncOperation operation = await graph.Teams[teamId].Operations[operationId].Request().GetAsync();
if (operation.Status == TeamsAsyncOperationStatus.Succeeded)
break;
if (operation.Status == TeamsAsyncOperationStatus.Failed)
throw new Exception($"Failed to create team '{newTeam.DisplayName}': {operation.Error.Message} ({operation.Error.Code})");
// according to the docs, we should wait > 30 secs between calls
// https://learn.microsoft.com/en-us/graph/api/resources/teamsasyncoperation?view=graph-rest-1.0
delayInMilliseconds = 30_000;
}
// finally, do something with your team...
I found a solution from another question... Tried and saw that it's working...

How to create one Adgroup in multiple campaigns using Google Adwords API?

I am playing with Google Adwords API. I am using the PHP client library.I am intended to create one ad group for multiple campaigns.
I am doing this in a loop and ad group is created for first iteration successfully but then throws an error given below
Help would be appreciated.
If someone wants code I'll provide it as well.
Thanks
I have solved this issue. Actually, I was using the same instance of service for each iteration that was wrong.
$adGroupService = $adWordsServices->get($session,
AdGroupService::class);
$fields =['Id','Name','Status','ServingStatus','AdvertisingChannelType','AdvertisingChannelSubType'];
$campaignService = $adWordsServices->get($session, CampaignService::class);
$adGroupId = 0;
for ($i=0; $i <count($campaignNameArr) ; $i++) {
$operations =[];
$adGroupService = $adWordsServices->get($session, AdGroupService::class); // HERE IS THE LINE OF CODE.
$_collection = self::fetchCampaigns(
$request,
$campaignService,
$fields,
$entriesPerPage,
$pageNo,
$campaignNameArr[$i]
);
if(count($_collection) >0)
{
$flag= true;
foreach ($_collection as $key => $campaign) {
$campaignId = $campaign->getID();
}
}
else
{
echo "No Campaign with name of :". $campaignNameArr[$i];
echo "<br/>";
continue;
}
$msg = 'Created';
echo $campaignId."<br/>";
// Create an ad group with required and optional settings.
$adGroup = new AdGroup();
$adGroup->setCampaignId($campaignId);
// $adGroup->setName($productTitle.' #' . uniqid());
$adGroup->setName($productTitle);
// Set bids (required).
$bid = new CpcBid();
$money = new Money();
$money->setMicroAmount(10000);
$bid->setBid($money);
$biddingStrategyConfiguration = new BiddingStrategyConfiguration();
$biddingStrategyConfiguration->setBids([$bid]);
$adGroup->setBiddingStrategyConfiguration($biddingStrategyConfiguration);
// Set additional settings (optional).
$adGroup->setStatus(AdGroupStatus::ENABLED);
// Targeting restriction settings. Depending on the criterionTypeGroup
// value, most TargetingSettingDetail only affect Display campaigns.
// However, the USER_INTEREST_AND_LIST value works for RLSA campaigns -
// Search campaigns targeting using a remarketing list.
$targetingSetting = new TargetingSetting();
$details = [];
// Restricting to serve ads that match your ad group placements.
// This is equivalent to choosing "Target and bid" in the UI.
$details[] = new TargetingSettingDetail(CriterionTypeGroup::PLACEMENT, false);
// Using your ad group verticals only for bidding. This is equivalent
// to choosing "Bid only" in the UI.
$details[] = new TargetingSettingDetail(CriterionTypeGroup::VERTICAL, true);
$targetingSetting->setDetails($details);
$adGroup->setSettings([$targetingSetting]);
// Set the rotation mode.
$rotationMode = new AdGroupAdRotationMode(AdRotationMode::OPTIMIZE);
$adGroup->setAdGroupAdRotationMode($rotationMode);
// Create an ad group operation and add it to the operations list.
$operation = new AdGroupOperation();
$operation->setOperand($adGroup);
$operation->setOperator(Operator::ADD);
$operations[] = $operation;
// Create the ad groups on the server and print out some information for
// each created ad group.
$result = $adGroupService->mutate($operations);
$adGroupId = $adGroup->getId();
foreach ($result->getValue() as $adGroup) {
printf(
"Ad group with name '%s' and ID %d was added.\n",
$adGroup->getName(),
$adGroup->getId()
);
}
}

Google Cloud Firestore: FirebaseError: [code=permission-denied]: Missing or insufficient permissions

It seems you can only make Firestore rules work, calling .add from client code, if you use the completely open/allow-all rule.
This is a VueJS app. In my main.js...
// You MUST import these 2 lines exactly so
// to get firebase/firestore loaded and working
import firebase from 'firebase';
import 'firebase/firestore';
import config from '../config/firebase.config.json';
firebase.initializeApp(config);
Vue.config.productionTip = false;
// Define some globals: Available to ALL page vues
Vue.prototype.$http = require('axios');
Vue.prototype.$firebase = firebase;
In my Login.vue I have...
methods: {
loadFirebaseUIAuth() {
const firebaseUIConfig = {
'signInSuccessUrl': '/',
'signInOptions': [
// Leave the lines as is for the providers you want to offer your users.
this.$firebase.auth.GoogleAuthProvider.PROVIDER_ID,
this.$firebase.auth.FacebookAuthProvider.PROVIDER_ID,
this.$firebase.auth.TwitterAuthProvider.PROVIDER_ID,
this.$firebase.auth.GithubAuthProvider.PROVIDER_ID
// firebase.auth.EmailAuthProvider.PROVIDER_ID
],
// Terms of service url.
'tosUrl': '/tos'
};
// Initialize the FirebaseUI Widget using Firebase.
const firebaseUI = new firebaseui.auth.AuthUI(this.$firebase.auth());
// The start method will wait until the DOM is loaded.
firebaseUI.start('#firebaseui-auth-container', firebaseUIConfig);
},
initFirebaseAuthHandler() {
this.$firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
userData.displayName = user.displayName;
userData.email = user.email;
userData.emailVerified = user.emailVerified;
userData.photoURL = user.photoURL;
userData.uid = user.uid;
userData.phoneNumber = user.phoneNumber;
userData.providerData = user.providerData;
user.getIdToken().then((accessToken) => {
console.log('Login.vue: FirebaseAuthHandler: sign-in-status:', 'Signed in!');
userData.accessToken = accessToken;
// Store User info, mainly to pass accessToken in request headers
localStorage.clear('userData');
localStorage.setItem('userData', JSON.stringify(userData));
});
console.log('Login.vue: userData: ', userData);
} else {
// User is signed out.
console.log('Login.vue: FirebaseAuthHandler: sign-in-status: ', 'Signed out');
}
}, function(error) {
console.error('Login.vue: FirebaseAuthHandler: ', error);
});
}
}
I'm not (not that I can see) doing anything to connect the user login info to the Firestore collection.add(...).then(...) call. Am I missing this connect-user-info-to-firestore step? Is this a manual or automatic thing?
My client Base.data-context.js create method looks like...
create(collection, model, doneSuccess, doneError) {
const doneCreate = (doc) => {
model.attribs = doc;
return doneSuccess(model);
};
delete model.attribs.id; // Do not allow id when creating
model.attribs.createdby = 'WebUI';
model.attribs.createdon = new Date();
model.attribs.modifiedby = 'WebUI';
model.attribs.modifiedon = new Date();
model.attribs.modifiedlastip = '';
collection.add(model.attribs).then(doneCreate).catch(doneError);
}
It's very generic. Calling .add on the player collection.
In my Firestore rules, I have...
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
// Any user can read or write this data
allow read: if true;
allow write: if true;
}
//match /{article=**} {
// // Only signed in users can write this data
// allow read: if true;
// allow write: if request.auth.uid != null;
//}
//match /{player=**} {
// // Only signed in users can read or write this data
// allow read: if request.auth.uid != null;
// allow write: if request.auth.uid != null;
//}
//match /{character=**} {
// // Only signed in users can read or write this data
// allow read: if request.auth.uid != null;
// allow write: if request.auth.uid != null;
//}
}
}
If I flip the comments to eliminate the first allow-all block, and enable the individual documents that should only allow request.auth.uid != null, you can no longer write. You get the permissions error in post title. So this tells me the rules are being processed because the comments flip enables/disables writing to the player collection.
Ok, so not too many firebase/firestore users on SO in Oct2017 :-) I finally found the answer. 99.9% of the code above is fine. You need 1 more line inside the this.$firebase.auth().onAuthStateChanged(function(user) {... auth event handler then inside user.getIdToken().then((accessToken) => {: You need to tell firebase what the user accessToken is: this.$firebase.auth(accessToken);. After this, all my Firestore rules worked as expected.
Make sure you store your firebase ref in Vue.prototype.$firebase in your main.js. This will give you access to firebase in all your components.
Hope this helps someone later :-)

Update Contact using Microsoft Graph Client Library

How do you update a Contact using the Microsoft Graph Client Library (v1.5)? I cannot find any documentation on the project page or via Google.
In the sample code below I want to set the SpouseName for all Contacts to "Single". I have no idea how to commit the change.
_graphClient = new GraphServiceClient(_Authenticator);
var request = _graphClient.Me.Contacts.Request();
var contacts = await request.GetAsync();
while (contacts.Count > 0)
{
foreach (var ct in contacts)
{
ct.SpouseName = "Single";
//
// how do you commit this change?
//
}
if (contacts.NextPageRequest != null)
{
contacts = await contacts.NextPageRequest.GetAsync();
}
else
{
break;
}
}
You use the UpdateAsync() method:
await graphClient.Me.Contacts["id"].Request().UpdateAsync(new Contact()
{
SpouseName = "Single"
});
Note that you only pass in the property you want to change. Do not pass the entire Contact object you previously retrieved.

Google Ad-Words API - ad extention link for mobile

During adding site links to campaign feed, I would like to set device preference for mobile to be checked.
How can I do it with ad words API ?
platformOperand.stringValue = "Mobile";//it also can be set for "Desktop"
I tried to do it like this:
ConstantOperand platformOperand = new ConstantOperand();
platformOperand.stringValue = "Mobile";//it also can be set for "Desktop"
platformOperand.type = ConstantOperandConstantType.STRING;
Function platformFunction = new Function();
platformFunction.lhsOperand = new FunctionArgumentOperand[] {
platformRequestContextOperand };
platformFunction.#operator = FunctionOperator.EQUALS;
platformFunction.rhsOperand = new FunctionArgumentOperand[] {
platformOperand };
and then it combined in function with links ids from google service and mutated for campaign feed service.
No exception and link added but when I enter to link edit, "Mobile" option remain unmarked.
Please advise.
I found the answer:
you shuld set devicePreference when you set propertes for FeedItem:
// Create the feed item and operation.
var item = new FeedItem();
item.feedId = siteLinksData.SiteLinksFeedId;
item.attributeValues = new FeedItemAttributeValue[]
{linkTextAttributeValue, linkUrlAttributeValue };
if (value.DeviceType == Device.Mobile)
{
item.devicePreference = new FeedItemDevicePreference();
item.devicePreference.devicePreference = 30001L;
item.devicePreference.devicePreferenceSpecified = true;
}
and this is most important part:
item.devicePreference = new FeedItemDevicePreference();
item.devicePreference.devicePreference = 30001L;
item.devicePreference.devicePreferenceSpecified = true;
if you wondering what the meaning of 30001L, it's device criteria IDs according to adwords API
See https://developers.google.com/adwords/api/docs/appendix/platforms

Resources