I used android studio to create a java app. In the project, I created the "assets" folder, and inside I put the json file that I will need to get the credentials for GmailAPI.
AssetFolder
I wish I could access the json file. I have already tried in many ways but every time it tells me that the file is missing.
This is the code:
public class GmailApi {
public Gmail initService(String userId) throws GeneralSecurityException,
IOException {
JacksonFactory jsonFactory = JacksonFactory.getDefaultInstance();
final GoogleCredentials creds = ServiceAccountCredentials.fromStream(new FileInputStream("gmailapi-android.json"))
.createScoped(GmailScopes.GMAIL_SEND);
final GoogleCredentials delegatedCreds = creds.createDelegated("xxx#xxx.com");
HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(delegatedCreds);
HttpTransport transport = new NetHttpTransport.Builder().build();
// Construct the gmail object.
Gmail service = new Gmail.Builder(transport, jsonFactory, requestInitializer)
.setApplicationName("gmailapi")
.build();
return service;
}
}
Could anyone help me? What should I put in the path to be able to access the json file?
final GoogleCredentials creds = ServiceAccountCredentials.fromStream(new FileInputStream("gmailapi-android.json"))
Did you try to open the file this way?
AssetManager assetManager = getAssets();
InputStream ims = assetManager.open("gmailapi-android.json");
Related
I'm running around trying to figure out how to use Apache Camel's google-drive drive-files component to insert some files to a nested folder in the drive. So far below code is able to insert the file to the drive's root folder.
from("timer:bkp?period={{timer.period}}")
.process(new BackupFile())
.to("google-drive://drive-files/insert")
.log("done");
And this is the Processor class
public class BackupFile implements Processor {
private static final String TEST_UPLOAD_FILE = "/path/to/file/imge.jpg";
private static final java.io.File UPLOAD_FILE = new java.io.File(TEST_UPLOAD_FILE);
#Override
public void process(Exchange exchange) throws Exception {
File fileMetadata = new File();
fileMetadata.setTitle(UPLOAD_FILE.getName());
FileContent mediaContent = new FileContent(null, UPLOAD_FILE);
final Map<String, Object> headers = new HashMap<>();
headers.put("CamelGoogleDrive.content", fileMetadata);
headers.put("CamelGoogleDrive.mediaContent", mediaContent);
exchange.getIn().setHeaders(headers);
}
}
FYI I need to define the said nested path before insert i.e do some setup like
setPath("/mydrive/path/tofile");
Any help or leads would be highly appreciated.
After looking around I came across Node.js sample that helped. The missing information all along was that the nested folder needed to exist before we can reference it.What I was expecting was a functionality to create the folder but perhaps this can be added as improvement. The folder's ID (PARENT_ID) can also be found from the url of the folder.
Below code finally worked for me.
ParentReference parRef=new ParentReference();
parRef.setId(PARENT_ID);
List<ParentReference> parents=new ArrayList<>();
parents.add(parRef);
File fileMetadata = new File();
fileMetadata.setTitle(UPLOAD_FILE.getName());
fileMetadata.setParents(parents);
FileContent mediaContent = new FileContent(null, UPLOAD_FILE);
final Map<String, Object> headers = new HashMap<>();
headers.put("CamelGoogleDrive.content", fileMetadata);
headers.put("CamelGoogleDrive.mediaContent", mediaContent);
exchange.getIn().setHeaders(headers);
public class image {
private String applicationName;
public image setApplicationName(String applicationName) {
this.applicationName = applicationName;
return this;
}
private static String CLIENT_ID = "***";
private static String CLIENT_SECRET = "***";
private static String REDIRECT_URI = "https://developers.google.com/oauthplayground";
public static void main(String[] args) throws IOException{
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET, Arrays.asList(DriveScopes.DRIVE))
.setAccessType("offline")
.setApprovalPrompt("auto").build();
String code = "4/-4JsvGiqNpZ6Ms5dLjLA2QgzgToGAxx_SZTeByBPh_Q";
GoogleTokenResponse response = flow.newTokenRequest(code).setRedirectUri(REDIRECT_URI).execute();
GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setClientSecrets(CLIENT_ID, CLIENT_SECRET)
.build()
.setFromTokenResponse(response);
Drive service = new Drive.Builder(httpTransport, jsonFactory, null)
.setHttpRequestInitializer(credential)
.setApplicationName("musik")
.build();
//Insert a file
File body = new File();
body.setTitle("My document");
body.setDescription("A test document");
body.setMimeType("text/plain");
java.io.File fileContent = new java.io.File("document.txt");
FileContent mediaContent = new FileContent("text/plain", fileContent);
File file = service.files().insert(body, mediaContent).execute();
System.out.println("File ID: " + file.getId());
}
}
I am trying to upload file on my drive using Drive Api, everything is working fine except I have to redeem the Google Authorization code every time after using it.
Is there any tweak or method for the above code to not redeem I every time by using any refresh token or access token method?
You need not redeem authorization code every time. You get the authorization code and then refresh and access token once you are authenticated. So Instead you can use refresh token to refresh the access token and then do google drive operations.
Content body should be in this format "client_id=[clientId]&client_secret=[clientSecret]&refresh_token=[RefreshToken]&grant_type=refresh_token" and do a HTTP post method to refresh the access token.
I always get this error when trying to add files under a folder in google drive, the folder is marked shared with mode "anyone in abc.com can view and edit"
com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
"error" : "invalid_grant"
}
I followed this procedure from Google Developers Guide
Delegating domain-wide authority to the service account
If your application accesses user data, the service account that you created needs to be granted access to the Google Apps domain’s user data that you want to access.
The following steps must be performed by an administrator of the Google Apps domain:
Go to your Google Apps domain’s Admin console.
Select Security from the list of controls. If you don't see Security listed, select More controls from the gray bar at the bottom of the page, then select Security from the list of controls. If you can't see the controls, make sure you're signed in as an administrator for the domain.
Select Show more and then Advanced settings from the list of options.
Select Manage API client access in the Authentication section.
In the Client Name field enter the service account's Client ID.
In the One or More API Scopes field enter the list of scopes that your application should be granted access to. For example, if your application needs domain-wide access to the Google Drive API and the Google Calendar API, enter: https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar.
Click Authorize.
Your application now has the authority to make API calls as users in your domain (to "impersonate" users). When you prepare to make authorized API calls, you specify the user to impersonate.
added the keys in application.properties
#Google Drive
google.drive.service.account=AAAAAAAAAAAA-i8jfnhhug5uoo9rm8ek2sf06b9452vb9#developer.gserviceaccount.com
google.drive.impersonate.account=my.user#abc.com
google.drive.pkey.file=abcdefgh-0aafb873fcc9.p12
google.drive.application.name=myapp-web
And then created a configuration class for drive
#Configuration
public class GoogleDriveAPIConfiguration {
#Resource
private Environment environment;
private final org.springframework.core.io.Resource pkeyFile = new ClassPathResource("abcdefgh-0aafb873fcc9.p12");
private static final String GOOGLE_RIVE_SERVICE_ACCOUNT = "google.drive.service.account";
private static final String GOOGLE_DRIVE_APPLICATION_NAME = "google.drive.application.name";
private static final String GOOGLE_DRIVE_IMPERSONATE_ACCOUNT = "google.drive.impersonate.account";
#Bean
#Autowired
public GoogleCredential googleCredential(JsonFactory jsonFactory, HttpTransport httpTransport)
throws GeneralSecurityException, IOException {
GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(jsonFactory).setServiceAccountId(environment.getProperty(GOOGLE_RIVE_SERVICE_ACCOUNT))
.setServiceAccountPrivateKeyFromP12File(getPrivateKeyFile())
.setServiceAccountScopes(Collections.singleton(DriveScopes.DRIVE))
.setServiceAccountId(environment.getProperty(GOOGLE_DRIVE_IMPERSONATE_ACCOUNT))
.build();
return credential;
}
#Bean
public JsonFactory getJsonFactory() {
JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
return JSON_FACTORY;
}
#Bean
public HttpTransport getHttpTransport() throws GeneralSecurityException, IOException {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
return httpTransport;
}
#Bean
#Autowired
public Drive getDrive(HttpTransport httpTransport, JsonFactory JSON_FACTORY, GoogleCredential credential) {
Drive drive = new Drive.Builder(httpTransport, JSON_FACTORY, credential).setApplicationName(
GOOGLE_DRIVE_APPLICATION_NAME).build();
return drive;
}
private File getPrivateKeyFile() throws IOException {
return pkeyFile.getFile();
}
}
The app starts up without any error, here's file upload code (full file in this gist)
#Autowired
public void setDrive(Drive drive) {
this.drive = drive;
}
#Async
public void uploadResume(UploadData data, byte[] uploadFile) throws GeneralSecurityException, IOException {
LOGGER.info("Uploading file type {} of size {} to Drive",data.getContentType(),uploadFile.length);
com.google.api.services.drive.model.File file = new com.google.api.services.drive.model.File();
List<ParentReference> referneces = new ArrayList<ParentReference>();
referneces.add(buildParentReference(data.getApplication().getRole()));
file.setTitle(data.getFileName());
file.setParents(referneces);
file.setCopyable(true);
file.setEditable(true);
file.setWritersCanShare(true);
file.setTitle(data.getFileName());
ByteArrayInputStream inputBytes = new ByteArrayInputStream(uploadFile);
InputStreamContent fileUpload = new InputStreamContent(data.getContentType(), new BufferedInputStream(inputBytes));
fileUpload.setLength(uploadFile.length);
Drive.Files.Insert request = drive.files().insert(file, fileUpload);
request.getMediaHttpUploader().setProgressListener(getProgressListener());
request.execute();
}
The error message really doesn't help too, any ideas where I am going wrong?
How can we setup a service account authorisation with the Google Drive API, so we can act on behalf of a other user within the domain.
The code throws a HTTP ERROR 500 on line 201, see stacktrace below:
URI is not hierarchical
Caused by:
java.lang.IllegalArgumentException: URI is not hierarchical
at java.io.File.<init>(File.java:418)
at com.caase.portal.DriveServlet.getDriveService(DriveServlet.java:201)
at com.caase.portal.DriveServlet.doGet(DriveServlet.java:67)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at com.google.api.client.extensions.servlet.auth.oauth2.AbstractAuthorizationCodeServlet.service(AbstractAuthorizationCodeServlet.java:130)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
See the code mentioned below:
/** Email of the Service Account */
private static final String SERVICE_ACCOUNT_EMAIL = "xxx#developer.gserviceaccount.com";
/** Path to the Service Account's Private Key file */
private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH = "xxx-privatekey.p12";
/**
* Build and returns a Drive service object authorized with the service accounts
* that act on behalf of the given user.
*
* #param userEmail The email of the user.
* #return Drive service object that is ready to make requests.
*/
public static Drive getDriveService(String userEmail) throws GeneralSecurityException,
IOException, URISyntaxException {
URI keyURL;
keyURL = DriveServlet.class.getResource(SERVICE_ACCOUNT_PKCS12_FILE_PATH).toURI();
HttpTransport httpTransport = new NetHttpTransport();
JacksonFactory jsonFactory = new JacksonFactory();
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(DriveScopes.all())
.setServiceAccountUser(userEmail)
.setServiceAccountPrivateKeyFromP12File(new java.io.File(keyURL))
.build();
Drive service = new Drive.Builder(httpTransport, jsonFactory, null)
.setHttpRequestInitializer(credential).build();
return service;
}
The line that throws the error is:
.setServiceAccountPrivateKeyFromP12File(new java.io.File(keyURL))
If I split up the line the error occurs in the new File creation:
new java.io.File(keyURL)
The key file is located in: src/main/resources
Any help is welcome :-)
Moved the resources folder from src/main/resources to src/resources and changed SERVICE_ACCOUNT_PKCS12_FILE_PATH to '/resources/xxx-privatekey.p12'. It works like a charm now!
Is there any way to set the Metadata Description?
https://developer.android.com/reference/com/google/android/gms/drive/Metadata.html#getDescription()
If so, what is the length limit?
I can't see anything in the api: https://developer.android.com/reference/com/google/android/gms/drive/MetadataChangeSet.Builder.html
Unfortunately not at the moment, AFAIK. What I do right now is initializing both GDAA and RESTful API (see the 'trash solution' SO 22295903) like this:
private GoogleApiClient _gac;
private com.google.api.services.drive.Drive _svc;
public GoogleApiClient init(String email){
_gac = new GoogleApiClient.Builder(UT.ACTX).addApi(com.google.android.gms.drive.Drive.API)
.addScope(com.google.android.gms.drive.Drive.SCOPE_FILE).setAccountName(email).build();
com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential crd =
GoogleAccountCredential.usingOAuth2(UT.ACTX,
Arrays.asList(com.google.api.services.drive.DriveScopes.DRIVE_FILE));
crd.setSelectedAccountName(email);
_svc = new com.google.api.services.drive.Drive.Builder(
AndroidHttp.newCompatibleTransport(), new GsonFactory(), crd).build();
return this;
}
You get the description from DGAA (GoogleApiClient _gac above), but update/write it to RESTFul like this (off UI thread):
public void oldDescUpW(String titl, String mime, String desc) {
try {
final FileList gLst = _svc.files().list()
.setQ("title = '"+titl+".jpg' and mimeType = '"+mime+"' and trashed = false")
.setFields("items(id)").execute();
if (gLst.getItems().size() == 1) {
final String sId = gLst.getItems().get(0).getId();
com.google.api.services.drive.model.File body =
new com.google.api.services.drive.model.File();
body.setDescription(desc);
_svc.files().patch(sId, body).execute();
}
} catch (Exception e) {}
}
It is also possible to use 'resource ID' from GDAA to address the file in RESTful, but it is not always immediately available (if the file is created in GDAA). See SO 22874657
DISCLAIMER:
It is a HACK and should not stay alive past GDAA delivery of an alternative.