How can I tell if a webproperty is deleted using Google AnalyticsService? - c#

I am using the Google Analytics Api to get web property information from my Analytics account.
When I log into analaytics though, I only have one website, but through the api I get several (old and deleted sites)
My code is like this:
var provider = new WebServerClient(GoogleAuthenticationServer.Description)
{
ClientIdentifier = _appId,
ClientSecret = _appSecret
};
var auth = new OAuth2Authenticator<WebServerClient>(provider, x => new AuthorizationState { AccessToken = token });
var analyticsService = new AnalyticsService(auth);
var accounts = analyticsService.Management.Accounts.List().Fetch();
foreach (var account in accounts.Items)
{
var webProperties = analyticsService.Management.Webproperties.List(account.Id).Fetch();
// todo: determine if web property is still in use?
}
From code how can I tell which ones are still active?

So after a bit more digging.
It seems there is no flag or anything like that indicating it has been removed, but if you keep digging into the result set you will notice that at the profile level, a profile that doesn't have child items seems to be a deleted one.
Which makes sense I guess there wouldn't be a profile associated with those that have been removed.
var provider = new WebServerClient(GoogleAuthenticationServer.Description)
{
ClientIdentifier = _appId,
ClientSecret = _appSecret
};
var auth = new OAuth2Authenticator<WebServerClient>(provider, x => new AuthorizationState { AccessToken = token });
var analyticsService = new AnalyticsService(auth);
var accounts = analyticsService.Management.Accounts.List().Fetch();
var result = new List<Profile>();
foreach (var account in accounts.Items)
{
var webProperties = analyticsService.Management.Webproperties.List(account.Id).Fetch();
foreach (var webProperty in webProperties.Items)
{
var profiles = analyticsService.Management.Profiles.List(account.Id, webProperty.Id).Fetch();
if (profiles.Items != null && profiles.Items.Any())
{
// these are the ones we want
result.AddRange(profiles.Items);
}
}
}
}

Related

AndroidPublisherService - Play Developer API Client - Upload aab failes due to bad credentials

Trying to make use of the AndroidPublisherService from Play Developer API Client.
I can list active tracks and the releases in those tracks, but when I try to upload a new build there seems to be no way of attaching the authentication already made previously to read data.
I've authenticated using var googleCredentials = GoogleCredential.FromStream(keyDataStream) .CreateWithUser(serviceUsername); where serviceUsername is the email for my service account.
private static void Execute(string packageName, string aabfile, string credfile, string serviceUsername)
{
var credentialsFilename = credfile;
if (string.IsNullOrWhiteSpace(credentialsFilename))
{
// Check env. var
credentialsFilename =
Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS",
EnvironmentVariableTarget.Process);
}
Console.WriteLine($"Using credentials {credfile} with package {packageName} for aab file {aabfile}");
var keyDataStream = File.OpenRead(credentialsFilename);
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername);
var credentials = googleCredentials.UnderlyingCredential as ServiceAccountCredential;
var service = new AndroidPublisherService();
var edit = service.Edits.Insert(new AppEdit { ExpiryTimeSeconds = "3600" }, packageName);
edit.Credential = credentials;
var activeEditSession = edit.Execute();
Console.WriteLine($"Edits started with id {activeEditSession.Id}");
var tracksList = service.Edits.Tracks.List(packageName, activeEditSession.Id);
tracksList.Credential = credentials;
var tracksResponse = tracksList.Execute();
foreach (var track in tracksResponse.Tracks)
{
Console.WriteLine($"Track: {track.TrackValue}");
Console.WriteLine("Releases: ");
foreach (var rel in track.Releases)
Console.WriteLine($"{rel.Name} version: {rel.VersionCodes.FirstOrDefault()} - Status: {rel.Status}");
}
using var fileStream = File.OpenRead(aabfile);
var upload = service.Edits.Bundles.Upload(packageName, activeEditSession.Id, fileStream, "application/octet-stream");
var uploadProgress = upload.Upload();
if (uploadProgress == null || uploadProgress.Exception != null)
{
Console.WriteLine($"Failed to upload. Error: {uploadProgress?.Exception}");
return;
}
Console.WriteLine($"Upload {uploadProgress.Status}");
var tracksUpdate = service.Edits.Tracks.Update(new Track
{
Releases = new List<TrackRelease>(new[]
{
new TrackRelease
{
Name = "Roswell - Grenis Dev Test",
Status = "completed",
VersionCodes = new List<long?>(new[] {(long?) upload?.ResponseBody?.VersionCode})
}
})
}, packageName, activeEditSession.Id, "internal");
tracksUpdate.Credential = credentials;
var trackResult = tracksUpdate.Execute();
Console.WriteLine($"Track {trackResult?.TrackValue}");
var commitResult = service.Edits.Commit(packageName, activeEditSession.Id);
Console.WriteLine($"{commitResult.EditId} has been committed");
}
And as the code points out, all action objects such as tracksList.Credential = credentials; can be given the credentials generated from the service account.
BUT the actual upload action var upload = service.Edits.Bundles.Upload(packageName, activeEditSession.Id, fileStream, "application/octet-stream"); does not expose a .Credential object, and it always fails with:
The service androidpublisher has thrown an exception: Google.GoogleApiException: Google.Apis.Requests.RequestError
Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project. [401]
Errors [
Message[Login Required.] Location[Authorization - header] Reason[required] Domain[global]
]
at Google.Apis.Upload.ResumableUpload`1.InitiateSessionAsync(CancellationToken cancellationToken)
at Google.Apis.Upload.ResumableUpload.UploadAsync(CancellationToken cancellationToken)
So, how would I go about providing the actual Upload action with the given credentials here?
Managed to figure this out during the day, I was missing one call to CreateScoped() when creating the GoogleCredential object as well as a call to InitiateSession() on the upload object.
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername)
.CreateScoped(AndroidPublisherService.Scope.Androidpublisher);
Once that was done I could then get a valid oauth token by calling
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername)
.CreateScoped(AndroidPublisherService.Scope.Androidpublisher);
var credentials = googleCredentials.UnderlyingCredential as ServiceAccountCredential;
var oauthToken = credentials?.GetAccessTokenForRequestAsync(AndroidPublisherService.Scope.Androidpublisher).Result;
And I can now use that oauth token in the upload request:
upload.OauthToken = oauthToken;
_ = await upload.InitiateSessionAsync();
var uploadProgress = await upload.UploadAsync();
if (uploadProgress == null || uploadProgress.Exception != null)
{
Console.WriteLine($"Failed to upload. Error: {uploadProgress?.Exception}");
return;
}
The full code example for successfully uploading a new aab file to google play store internal test track thus looks something like this:
private async Task UploadGooglePlayRelease(string fileToUpload, string changeLogFile, string serviceUsername, string packageName)
{
var serviceAccountFile = ResolveServiceAccountCertificateInfoFile();
if (!serviceAccountFile.Exists)
throw new ApplicationException($"Failed to find the service account certificate file. {serviceAccountFile.FullName}");
var keyDataStream = File.OpenRead(serviceAccountFile.FullName);
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername)
.CreateScoped(AndroidPublisherService.Scope.Androidpublisher);
var credentials = googleCredentials.UnderlyingCredential as ServiceAccountCredential;
var oauthToken = credentials?.GetAccessTokenForRequestAsync(AndroidPublisherService.Scope.Androidpublisher).Result;
var service = new AndroidPublisherService();
var edit = service.Edits.Insert(new AppEdit { ExpiryTimeSeconds = "3600" }, packageName);
edit.Credential = credentials;
var activeEditSession = await edit.ExecuteAsync();
_logger.LogInformation($"Edits started with id {activeEditSession.Id}");
var tracksList = service.Edits.Tracks.List(packageName, activeEditSession.Id);
tracksList.Credential = credentials;
var tracksResponse = await tracksList.ExecuteAsync();
foreach (var track in tracksResponse.Tracks)
{
_logger.LogInformation($"Track: {track.TrackValue}");
_logger.LogInformation("Releases: ");
foreach (var rel in track.Releases)
_logger.LogInformation($"{rel.Name} version: {rel.VersionCodes.FirstOrDefault()} - Status: {rel.Status}");
}
var fileStream = File.OpenRead(fileToUpload);
var upload = service.Edits.Bundles.Upload(packageName, activeEditSession.Id, fileStream, "application/octet-stream");
upload.OauthToken = oauthToken;
_ = await upload.InitiateSessionAsync();
var uploadProgress = await upload.UploadAsync();
if (uploadProgress == null || uploadProgress.Exception != null)
{
Console.WriteLine($"Failed to upload. Error: {uploadProgress?.Exception}");
return;
}
_logger.LogInformation($"Upload {uploadProgress.Status}");
var releaseNotes = await File.ReadAllTextAsync(changeLogFile);
var tracksUpdate = service.Edits.Tracks.Update(new Track
{
Releases = new List<TrackRelease>(new[]
{
new TrackRelease
{
Name = $"{upload?.ResponseBody?.VersionCode}",
Status = "completed",
InAppUpdatePriority = 5,
CountryTargeting = new CountryTargeting { IncludeRestOfWorld = true },
ReleaseNotes = new List<LocalizedText>(new []{ new LocalizedText { Language = "en-US", Text = releaseNotes } }),
VersionCodes = new List<long?>(new[] {(long?) upload?.ResponseBody?.VersionCode})
}
})
}, packageName, activeEditSession.Id, "internal");
tracksUpdate.Credential = credentials;
var trackResult = await tracksUpdate.ExecuteAsync();
_logger.LogInformation($"Track {trackResult?.TrackValue}");
var commitResult = service.Edits.Commit(packageName, activeEditSession.Id);
commitResult.Credential = credentials;
await commitResult.ExecuteAsync();
_logger.LogInformation($"{commitResult.EditId} has been committed");
}

Alexa.NET cannot create a reminder : Invalid Bearer Token

I want to create push notifications to my Alexa Devide. Due the push notification program is closed I am trying to create reminders. The final idea is to create an Azure Function with this code and being called when a TFS Build faild.
I'm using Alexa.NET and Alexa.NET.Reminders from a console application, already have and Alexa Skill with all the permissions granted, in the Alexa portal and in the mobile app.
Everything seems to work nice until I try to read the reminders in my account, when get an exception "Invalid Bearer Token"
this is the code:
[Fact]
public async Task SendNotificationTest()
{
var clientId = "xxxx";
var clientSecret = "yyyy";
var alexaClient = clientId;
var alexaSecret = clientSecret;
var accessToken = new Alexa.NET.AccessTokenClient(Alexa.NET.AccessTokenClient.ApiDomainBaseAddress);
var token = await accessToken.Send(alexaClient, alexaSecret);
var reminder = new Reminder
{
RequestTime = DateTime.UtcNow,
Trigger = new RelativeTrigger(12 * 60 * 60),
AlertInformation = new AlertInformation(new[] { new SpokenContent("test", "en-GB") }),
PushNotification = PushNotification.Disabled
};
var total = JsonConvert.SerializeObject(reminder);
var client = new RemindersClient("https://api.eu.amazonalexa.com", token.Token);
var alertList = await client.Get();
foreach (var alertInformation in alertList.Alerts)
{
Console.WriteLine(alertInformation.ToString());
}
try
{
var response = await client.Create(reminder);
}
catch (Exception ex)
{
var x = ex.Message;
}
}
Are there any examples to get the access token?
Am I missing a step in the process?
Thanks in advance.
N.B. The reminders client requires that you have a skill with reminders persmission enabled, and the user must have given your skill reminders permission (even if its your development account)
Creating a reminder
using Alexa.NET.Response
using Alexa.NET.Reminders
....
var reminder = new Reminder
{
RequestTime = DateTime.UtcNow,
Trigger = new RelativeTrigger(12 * 60 * 60),
AlertInformation = new AlertInformation(new[] { new SpokenContent("it's a test", "en-GB") }),
PushNotification = PushNotification.Disabled
};
var client = new RemindersClient(skillRequest);
var alertDetail = await client.Create(reminder);
Console.WriteLine(alertDetail.AlertToken);
Retrieving Current Reminders
// Single reminders can be retrieved with client.Get(alertToken)
var alertList = await client.Get();
foreach(var alertInformation in alertList.Alerts)
{
//Your logic here
}
Deleting a Reminder
await client.Delete(alertToken);

remote object server is never synchronized

hi i cannot seem to get realm synced with the realm object server i am working xamarin and it's working great localing i just can't seem to sync to the cloud , not even the schema
my code is:
var credentials = Credentials.UsernamePassword(usernameField.Text.ToLower(), passField.Text, createUser: true);
var authURL = new System.Uri("https://game-object.us1.cloud.realm.io/");
var user = await User.LoginAsync(credentials, authURL);
var serverURL = new System.Uri("realm://game-object.us1.cloud.realm.io/~/default");
var configuration = new SyncConfiguration(user, serverURL);
var permission= await user.GetGrantedPermissionsAsync(Recipient.CurrentUser,millisecondTimeout:2111);
var realm = Realm.GetInstance(configuration);
bool m;
if (realm.Config == configuration)
m=true;
var realmSession= realm.GetSession();
var state = realmSession.State;
var permissionCondition = PermissionCondition.UserId(user.Identity);
/* await user.ApplyPermissionsAsync(permissionCondition, "realm://game-object.us1.cloud.realm.io/~/default", AccessLevel.Write);
permission = await user.GetGrantedPermissionsAsync(Recipient.CurrentUser, millisecondTimeout: 2111);
*/
var players = realm.All<Player>();
realm.Write(() =>
{
realm.Add(new Player { Health = 1, name = "apex" });
});
var count = players.Count();
i feel embraced, but the reason i wasn't getting updates is because the client object browser doesn't auto update

How to authorize console application c# for Google Contacts API

I have an issue with the authorization in Google Contacts.
Until June my console C# application worked.
I have made steps to get contacts https://developers.google.com/google-apps/contacts/v3/?hl=en.
I cannot get the contacts; I have only access to serviceAccountEmail (xxxxxxxxxxxxxxxxxxx#developer.gserviceaccount.com).
I have 2 contacts stored there and I have access only to them.
I want to have access to my 7000 Gmail contacts.
Is there any tutorial for this in C#?
I found ones for analytics and for calendar but not for contacts.
Below is my code:
const string serviceAccountEmail = "xxxxxxxxxxxxxxxxxxx#developer.gserviceaccount.com";
var certificate = new X509Certificate2("grdom-all-xxxxxxxxxxxx.p12", "notasecret",
X509KeyStorageFlags.Exportable);
ServiceAccountCredential.Initializer serviceAccountCredentialInitializer =
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { "https://www.google.com/m8/feeds/" },
}.FromCertificate(certificate);
var credential = new ServiceAccountCredential(serviceAccountCredentialInitializer);
if (!credential.RequestAccessTokenAsync(CancellationToken.None).Result)
throw new InvalidOperationException("Access token request failed.");
var oauthParameters = new OAuth2Parameters()
{
AccessToken = credential.Token.AccessToken,
AccessType = "offline",
ApprovalPrompt = "force",
};
var settings = new RequestSettings("grdom-all", oauthParameters)
{
AutoPaging = true,
UseSSL = true,
};
ContactsRequest cr = new ContactsRequest(settings);
var query = new ContactsQuery(ContactsQuery.CreateContactsUri("default"));
Feed<Contact> f = cr.GetContacts();
foreach (Contact entry in f.Entries)
{
//do something
};

How to use Google Contacts API via Oauth2 authentication

I have this below code to get calendar entries using the google Calendar API (https://developers.google.com/google-apps/calendar/) which uses OAuth2.
It works well.
private IList<string> scopes = new List<string>();
private CalendarService calendarService;
private void InitializeCalendarService()
{
// Add the calendar specific scope to the scopes list
scopes.Add(CalendarService.Scopes.Calendar.GetStringValue());
// Display the header and initialize the sample
CommandLine.EnableExceptionHandling();
CommandLine.DisplayGoogleSampleHeader("Google.Api.Calendar.v3 Sample");
// Create the authenticator
//FullClientCredentials credentials = PromptingClientCredentials.EnsureFullClientCredentials();
var provider = new NativeApplicationClient(GoogleAuthenticationServer.Description);
FullClientCredentials credentials = new FullClientCredentials();
credentials.ClientId = "XYZ.apps.googleusercontent.com";
credentials.ClientSecret = "XYZ";
credentials.ApiKey = "XYZ";
provider.ClientIdentifier = credentials.ClientId;
provider.ClientSecret = credentials.ClientSecret;
OAuth2Authenticator<NativeApplicationClient> auth = new OAuth2Authenticator<NativeApplicationClient>(provider, GetAuthorization);
// Create the calendar service using an initializer instance
BaseClientService.Initializer initializer = new BaseClientService.Initializer();
initializer.Authenticator = auth;
calendarService = new CalendarService(initializer);
CalendarList list = calendarService.CalendarList.List().Execute();
// do something with the list .. the list is all good
}
public IAuthorizationState GetAuthorization(NativeApplicationClient client)
{
// You should use a more secure way of storing the key here as
// .NET applications can be disassembled using a reflection tool.
const string STORAGE = "google.samples.dotnet.calendar";
const string KEY = "s0mekey";
// Check if there is a cached refresh token available.
IAuthorizationState state = AuthorizationMgr.GetCachedRefreshToken(STORAGE, KEY);
if ((state != null))
{
try
{
client.RefreshToken(state);
return state;
// we are done
}
catch (DotNetOpenAuth.Messaging.ProtocolException ex)
{
CommandLine.WriteError("Using an existing refresh token failed: " + ex.Message);
CommandLine.WriteLine();
}
}
// Retrieve the authorization from the user
string[] array = new string[scopes.Count];
scopes.CopyTo(array,0);
state = AuthorizationMgr.RequestNativeAuthorization(client, array);
AuthorizationMgr.SetCachedRefreshToken(STORAGE, KEY, state);
return state;
}
How can I use the similar OAuth2Authenticator to fetch Contacts?
I am able to fetch contacts using the below code, but its not password-less, I need to get it working using Oath2. The example below uses Gdata contacts api v2. I can see that i can pass through OAuth2Authenticator but im not exactly sure how to do it correctly (i cant see any valid examples in C# on the google site) and fetch the access code based on what the user is selecting.
I cant see how to use OAuth2Authenticator with the contacts api v3 (https://developers.google.com/google-apps/contacts/v3/)
RequestSettings rsLoginInfo = new RequestSettings("", email,pwd);
rsLoginInfo.AutoPaging = true;
ContactsRequest cRequest = new ContactsRequest(rsLoginInfo);
// fetch contacts list
Feed<Contact> feedContacts = cRequest.GetContacts();
foreach (Contact gmailAddresses in feedContacts.Entries)
{
// Looping to read email addresses
foreach (EMail emailId in gmailAddresses.Emails)
{
lstContacts.Add(emailId.Address);
}
}
I ended up doing this by fetching the access code by having a browser control read the Document title value when the user selects the google account and grants access.
eg:
To Generate URL
RedirectURI = "urn:ietf:wg:oauth:2.0:oob"
OAuth2Parameters parameters = new OAuth2Parameters()
{
ClientId = clientId,
ClientSecret = clientSecret,
RedirectUri = redirectUri,
Scope = requiredScope
};
// Request authorization from the user (by opening a browser window):
string url = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);
var loginUri = new Uri(url);
// This form has browser control
GoogleLoginForm form = new GoogleLoginForm(loginUri, redirectUri);
var dr = form.ShowDialog();
if (dr == System.Windows.Forms.DialogResult.OK)
{
parameters.AccessCode = form.OAuthVerifierToken;
}
Then In GoogleLoginForm :
We have a browser control and registered browserControl_Navigated event and the do the below. The DocumentTitle contains the AccessCode which is used to generate the token.
private void GoogleLoginForm_Load(object sender, EventArgs e)
{
wbGoogleLogin.Url = _loginUri;
}
private void wbGoogleLogin_Navigated(object sender, WebBrowserNavigatedEventArgs e)
{
string fullPath = e.Url.ToString();
WebBrowser control = sender as WebBrowser;
if (control != null && !string.IsNullOrEmpty(control.DocumentTitle) && control.DocumentTitle.Contains("Success code"))
{
_OAuthVerifierToken = control.DocumentTitle.Replace("Success code=","");
DialogResult = DialogResult.OK;
}
}
This way it can be done in the same piece of code, without having to write a complicated callback service of some sort to read the access token back into our system.
Not exactly sure why the calendar api has this built in, and the contacts API doesn't.
Firstly, the quick answer to your question. I believe that the IAuthorizationState has similar properties to OAuth2Parameters. Thus, you should be able to do this (combining it with the code you have for the calender):
OAuth2Authenticator<NativeApplicationClient> auth = new OAuth2Authenticator<NativeApplicationClient>(provider, GetAuthorization);
//This will call your GetAuthorization method
auth.LoadAccessToken()
RequestSettings settings = new RequestSettings("appName", auth.State.AccessToken);
ContactsRequest cRequest = new ContactsRequest(settings);
// fetch contacts list
Feed<Contact> feedContacts = cRequest.GetContacts();
foreach (Contact gmailAddresses in feedContacts.Entries)
{
// Looping to read email addresses
foreach (EMail emailId in gmailAddresses.Emails)
{
lstContacts.Add(emailId.Address);
}
}
This should work as the RequestSettings allows you to specify an access token. That being said, I myself prefer to use :
var parameters = new OAuth2Parameters()
{
//Client
ClientId = CLIENT_ID,
ClientSecret = CLIENT_SECRET,
RedirectUri = redirectUri,
Scope = "https://www.google.com/m8/feeds",
ResponseType = "code"
};
//User clicks this auth url and will then be sent to your redirect url with a code parameter
var authorizationUrl = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);
.
.
.
//using the code parameter
parameters.AccessCode = code;
OAuthUtil.GetAccessToken(parameters);
var settings = new RequestSettings(applicationName, parameters);
var cr = new ContactsRequest(settings);
//Now you can use contacts as you would have before
Although, Ive only tested this with Web Server Apps, so maybe the authenticator is needed for your situation? I found these source codes handy:
OAuth2Demo
IAuthorizationState
OAuth2Authenticator

Categories