How to duplicate a worksheet using Google API? - c#

I'm trying to create a worksheet in a spreadsheet which is a copy of the existing one. Via Google Docs user interface it is done by 'Duplicate' function of the context menu of a worksheet. Is it possible to copy the whole sheet at once and insert it to the other one?
This code:
public void CopyLastTab(SpreadsheetEntry spreadsheet, string newTabName)
{
WorksheetEntry tabToCopy = GetLastTab(spreadsheet);
tabToCopy.Title.Text = newTabName;
newTab = service.Insert(GetAllWorksheets(spreadsheet), tabToCopy);
}
adds only a new empty worksheet.
Copying cell by cell is too long and the matter is I need conditional formatting used on the previous sheet too. Please help.

Old question but just spent several hours trying to find an answer. The following works for C# .net 6:
Note this assumes you have an instance of Google SheetsService
(Google.APIs.Sheets.v4) that has already been authenticated. I'll post some authentication code below.
public void Duplicate(int SourceSheetId, string NewSheetName) {
var batch = new BatchUpdateSpreadsheetRequest();
batch.Requests = new List<Request>();
batch.Requests.Add(new Request() {
DuplicateSheet = new DuplicateSheetRequest() {
NewSheetName = NewSheetName,
SourceSheetId = SourceSheetId
},
});
var req = Service.Spreadsheets.BatchUpdate(batch, SheetID); //public SheetsService Service; property of parent class
var response = req.Execute();
}
private void _authenticate()
{
UserCredential credential;
using (var stream = new FileStream("credentials.json", FileMode.Open, FileAccess.ReadWrite))
{
string credPath = "token.json";
var cancelToken = new CancellationToken();
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
_scopes,
YOUR-EMAIL-HERE,
cancelToken,
new FileDataStore(credPath, true)).Result;
//credential.RevokeTokenAsync(cancelToken); //UNCOMMENT TO LOG OUT
}
Service = new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "",
});
}

Related

I can't read my inbox emails with Google Api

I tried read my emails content. I need the complete text email. I read a lot of Stack Overflow questions but no working. My message.Payload.Body.Data is a lot of times null. I need a think like message.Snippet but with the complete message.
My code is :
//Login
using (var stream = new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
// The file token.json stores the user's access and refresh tokens, and is created
// automatically when the authorization flow completes for the first time.
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"admin",
CancellationToken.None,
new FileDataStore(credPath, true)
).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Gmail API service.
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
// Define parameters of request.
UsersResource.LabelsResource.ListRequest request = service.Users.Labels.List("me");
var inboxlistRequest = service.Users.Messages.List("me");
inboxlistRequest.LabelIds = "INBOX";
inboxlistRequest.IncludeSpamTrash = false;
var emailListResponse = inboxlistRequest.Execute();
foreach (var mail in emailListResponse.Messages)
{
var mailId = mail.Id;
var threadId = mail.ThreadId;
Message message = service.Users.Messages.Get("me", mailId).Execute();
Console.WriteLine(message.Payload.Body.Data);
}
I try too thinks like :
foreach (var part in message.Payload.Parts)
{
byte[] data = Convert.FromBase64String(part.Body.Data);
string decodedString = Encoding.UTF8.GetString(data);
Console.WriteLine(decodedString);
}
But no work because i don't find content in Payload.

Send Google Mail in C# failed because of 403 Insufficient permissions

I created a console application which sends an email to an address, it shows like:
private static string[] Scopes = { GmailService.Scope.GmailCompose, GmailService.Scope.GmailSend };
private static string ApplicationName = "Gmail API Quickstart";
private const string SUBJECT = "Some simple subject";
private static string[] emails = new string[] { "teodorescumihail2008#live.com" };
static void Main(string[] args)
{
UserCredential credential;
using (var stream =
new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
string credPath = Environment.GetFolderPath(
Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, ".credentials/gmail-dotnet-quickstart.json");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Gmail API service.
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
var msg = new AE.Net.Mail.MailMessage
{
Subject = SUBJECT,
Body = "Test body",
From = new MailAddress("teodorescumihail2008#gmail.com")
};
msg.To.Add(new MailAddress("teodorescumihail2008#live.com"));
StringWriter sw = new StringWriter();
msg.Save(sw);
var result = service.Users.Messages.Send(new Message
{
Raw = Base64UrlEncode(sw.ToString())
}, "me").Execute();
Console.Read();
}
private static string Base64UrlEncode(string input)
{
var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
// Special "url-safe" base64 encode.
return Convert.ToBase64String(inputBytes)
.Replace('+', '-')
.Replace('/', '_')
.Replace("=", "");
}
When execute sending email, I received:
Where is my mistake ?
I assumed you changed your scope in the code without reauthorize/getting a new credential file from Gmail. The problem is GmailAPI does not know that your scope is updated. You have to reauthorize your app in GmailAPI by deleting your app permission and regenerate your credentials.json so that your scope is updated on GmailAPI.
To delete your app permission: click here

How To create an instance of Google BaseClientService.Initializer

I want to know how to create an instance of Google BaseClientService.Initializer. I need to use the BaseClientService.Initializer to create the GmailService instance, and then use this GmailService instance to create an UsersResource instance.
Google.Apis.Services.BaseClientService.Initializer initializer = new BaseClientService.Initializer();
initializer.ApiKey = "MyApiKey";
initializer.ApplicationName = "MyProject";
initializer.DefaultExponentialBackOffPolicy = Google.Apis.Http.ExponentialBackOffPolicy.None;
Google.Apis.Gmail.v1.GmailService gmailService = new GmailService(initializer);
Google.Apis.Gmail.v1.UsersResource usersResource = new UsersResource(gmailService);
UsersResource.MessagesResource messagesResource = usersResource.Messages;
First go to the link bellow and open an application in your google account.
once you run the code you'll get exception for the first time, given you an address to go and enable the API in your google account.
https://console.developers.google.com/apis/dashboard?project=super-pharm-log-notifications
static string[] Scopes = { GmailService.Scope.GmailCompose, GmailService.Scope.GmailSend, GmailService.Scope.GmailInsert };
static private BaseClientService.Initializer initializeGmailAccountServices()
{
string appRoot = null;
if (System.Web.HttpContext.Current == null)
{
appRoot = Environment.CurrentDirectory;
}
else
{
appRoot = System.Web.HttpContext.Current.Server.MapPath(#"~\");
}
string path = Path.Combine(appRoot, DBConstants.GMAIL_CREDENTIALS_PATH);
UserCredential credential;
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
{
ClientSecrets secrets = GoogleClientSecrets.Load(stream).Secrets;
var t = GoogleWebAuthorizationBroker.AuthorizeAsync(secrets, Scopes, "user", CancellationToken.None);
t.Wait();
credential = t.Result;
}
return= new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "your application name",
};
}
private static string Base64UrlEncode(string input)
{
var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
// Special "url-safe" base64 encode.
return Convert.ToBase64String(inputBytes)
.Replace('+', '-')
.Replace('/', '_')
.Replace("=", "");
}

Google Drive SDK create file for user

HelloI'm am currently trying to create a file under a specific user account.The user account is located within my Google Domain.For Oauth im using a service account.
The DriveService()
private static DriveService Service()
{
var certificate = new X509Certificate2(Constants.P12, "notasecret", X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(Constants.ServiceAccountEmail)
{
Scopes = new[] {
DriveService.Scope.Drive,
}
}.FromCertificate(certificate));
// Create the service.
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "MyApplicationName",
});
return service;
}
Creating a file
private static void CreateDriveDocument(string title)
{
Console.WriteLine("Google - Create New Document:" + Environment.NewLine);
File body = new File();
body.Title = title;
body.Description = "A test document";
body.MimeType = "text/plain";
byte[] byteArray = System.IO.File.ReadAllBytes(#"C:\myDoc.txt");
System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
//Callin the service at "Service()"
FilesResource.InsertMediaUpload request = Service().Files.Insert(body, stream, "text/plain");
request.Upload();
File file = request.ResponseBody;
}
So here I create a File, since I authenticated with the ServiceAccount, thats where the File is uploaded.
The Question
I need to be able to Create/Copy this file to a specific user withing
my domain. And make that user owner of the file.
All help is appreciated.
Old post Reference
TransferOwnership Using Google SDK
I'll go with Marcel Balk anwser.
This way we will use impersonation!
we can use the service account to authenticate, then use any email account in our domain and upload files.
The uploaded files will be visible in the users Drive under My Files (not Shared with me!)
Files also are owned by the impersonated account.
Tested in a little console app:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Drive.v2;
using Google.Apis.Drive.v2.Data;
using Google.Apis.Services;
namespace UseWebServiceMethod
{
class Program
{
// Goto https://admin.google.com/AdminHome?chromeless=1#OGX:ManageOauthClients
// Login met admin account => ****#***.***
// Add/edit Client Name (Use Client ID of service account here) => 2***8.apps.googleusercontent.com
// One or More API Scopes => https://www.googleapis.com/auth/drive
public const string ImpersonatedAccountEmail = "****#***.***";
public const string ServiceAccountEmail = "2******8#developer.gserviceaccount.com";
public const string Key = #"C:\Users\Wouter\Desktop\GoogleTester\GoogleTester\A****c.p12";
public const string FileToUpload = #"C:\Users\Wouter\Desktop\GoogleTester\GoogleTester\whakingly.txt";
public const string ApplicationName = "A***l";
static void Main()
{
var certificate = new X509Certificate2(Key, "notasecret", X509KeyStorageFlags.Exportable);
var initializer = new ServiceAccountCredential.Initializer(ServiceAccountEmail)
{
Scopes = new[] { DriveService.Scope.Drive },
User = ImpersonatedAccountEmail
};
var credential = new ServiceAccountCredential(initializer.FromCertificate(certificate));
var driveService = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName
});
// Show all files
var list = driveService.Files.List().Execute();
if (list.Items != null)
foreach (var fileItem in list.Items)
{
Console.WriteLine(fileItem.Title + " - " + fileItem.Description);
}
Console.WriteLine("Press Enter to continue.");
Console.ReadLine();
// Upload a new file
File body = new File();
body.Title = "whakingly.txt";
body.Description = "A whakingly (that a new word I created just there) file thats uploaded with impersonation";
body.MimeType = "text/plain";
byte[] byteArray = System.IO.File.ReadAllBytes(FileToUpload);
var stream = new System.IO.MemoryStream(byteArray);
FilesResource.InsertMediaUpload request = driveService.Files.Insert(body, stream, "text/plain");
request.Upload();
File file = request.ResponseBody;
Console.WriteLine("Press Enter to continue.");
Console.ReadLine();
// Show all files
var list2 = driveService.Files.List().Execute();
if (list2.Items != null)
foreach (var fileItem in list2.Items)
{
Console.WriteLine(fileItem.Title + " - " + fileItem.Description);
}
Console.WriteLine("Press Enter to continue.");
Console.ReadLine();
}
}
}
You can easily do this by adding the user to the code.
See the user i added.
private static DriveService Service()
{
var certificate = new X509Certificate2(Constants.P12, "notasecret",X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(Constants.ServiceAccountEmail)
{
Scopes = new[] {DriveService.Scope.Drive},
User="someuser#somedomain.someextension" //Add this to your code!
}.FromCertificate(certificate));
// Create the service.
var service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "MyApplicationName",
});
return service;
}
Then go to admin.google.com --> Security --> Advance settings --> Manage oauth client access
Add the client id to the client name and add your scope (http://www.googleapis.com/auth/drive) to the "One or More API Scopes field"

YouTube API v3 Check Video Processing Status

Once the video is uploaded, how to check its processing status using C# .NET's API?
The answer should be in the Google.Apis.Youtube.v3.Data.VideoProcessingDetails, but how exactly should that object be instantiated? The following code throws a System.Net.Http.HttpRequestException:
video.ProcessingDetails = new VideoProcessingDetails();
The code above is being used in the following context:
UserCredential credential;
using (FileStream stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { YouTubeService.Scope.Youtube, YouTubeService.Scope.YoutubeUpload },
"user",
CancellationToken.None,
new FileDataStore("YouTube.Auth.Store")).Result;
}
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = Assembly.GetExecutingAssembly().GetName().Name
});
var video = new Video();
video.Snippet = new VideoSnippet();
video.Snippet.Title = Title;
video.Snippet.Description = Description;
video.Snippet.Tags = Tags;
video.ProcessingDetails = new VideoProcessingDetails(); // Here it throws an exception
video.Snippet.CategoryId = CategotyId;
video.Status = new VideoStatus();
video.Status.PrivacyStatus = PrivacyStatus;
var filePath = FilePath;
The idea, is once the video is uploaded, check in a loop if the video is still processing and perform other operations on it once the processing is done.
UPDATE: I figured out that if the object is instantiated after the video is uploaded (i.e. in the private static void videosInsertRequest_ResponseReceived() method, for example), the exception is gone, but once I try accessing video.ProcessingDetails.ProcessingProgress.TimeLeftMs.Value, it says that that value is null.
Thanks.
In my own work, I have found that when ProcessingDetails.ProcessingStatus equals "terminated", all of the other properties in ProcessingDetails are equal to nothing (i.e. null). I believe that this means that YouTube has finished processing the video.
I usually check a Google API v3 property to see if it is null before attempting to use it.

Categories