Google Drive API - File have childrens or not - google-app-engine

I get files from google drive, like that. The result of Folders. ok,
I have List result, so I want to find if result(i) have children with application/vnd.google-apps.folder mime type or not.
in the other words, method which checks: if current folder contains children folder returns true. owherwise returns false;
I use it in google App engine.
how can I do that?
public void getAllFiles(String id, Drive service) throws IOException{
String query="'"+id + "'"+ " in parents and trashed=false and mimeType=application/vnd.google-apps.folder'";
FileList files = service.files().list().setQ(query).execute();
List<File> result = new ArrayList<File>();
Files.List request = service.files().list();
do {
result.addAll(files.getItems());
request.setPageToken(files.getNextPageToken());
} while (request.getPageToken() != null && request.getPageToken().length() > 0);
}
I do not want to create additional requests (new children request to each node) to see if it have children or not. something like that:
for (File file : result) {
query = "'" + file.getId() + "'" + " in parents and trashed=false and mimeType='application/vnd.google-apps.folder'";
FileList fileChild = service.files().list().setQ(query).execute();
List<File> res = new ArrayList<File>();
Files.List req = service.files().list();
do {
res.addAll(fileChild.getItems());
req.setPageToken(fileChild.getNextPageToken());
} while (req.getPageToken() != null && req.getPageToken().length() > 0);
RemoteFolder remFolder = new RemoteFolder();
remFolder.setFile(file);
if(res.size()>0){
remFolder.setChildrenable(true);
log.info("folder named "+file.getTitle() + " have children folders count: "+ res.size());
}
folderList.add(remFolder);
}
I want to optimize my code.

You have to make another request for each node. If you want to avoid too many calls use memcached.

Related

Cannot update request parameters in custom Search Component

I have written Solr Custom Search Component as described here
My goal is to update the query parameters, specifically to remove Unicode Quotes as early as possible in the pipeline.
However, after intercepting the request and editing the parameters, the request does not seem to update.
public void updateSolrRequest(SolrQueryRequest req) {
SolrParams params = req.getParams();
System.out.println( "params = " + req.getParamString());
String newQuery = params.get(CommonParams.Q);
newQuery = newQuery.toString().replaceAll("[A]","XXX");
ModifiableSolrParams newParams = new ModifiableSolrParams(params);
newParams.remove(CommonParams.Q);
newParams.add(CommonParams.Q, newQuery);
// all good to here, the next line should
// overwrite the old params with the new ones
// but it does not
req.setParams(newParams);
System.out.println("newQuery = " + newQuery);
System.out.println("newParams = " + newParams.get(CommonParams.Q));
System.out.println("updated req = " + req.getParamString());
}
Output
params = q=“A+Game+of+Thrones“&defType=dismax&q.alt=thrones&fq=Game&_=1548262845155
newQuery = “XXX Game of Thrones“
newParams = “XXX Game of Thrones“
updated req = q=“A+Game+of+Thrones“&defType=dismax&q.alt=thrones&fq=Game&_=1548262845155
The problem here is, that
public String getParamString() {
return origParams.toString();
}
is actually returning original params, which aren't affected by setParams called
/** Change the parameters for this request. This does not affect
* the original parameters returned by getOriginalParams()
*/
void setParams(SolrParams params);
You should use org.apache.solr.request.SolrQueryRequest#getParams to check your updated parameters.

Salesforce APEX method not bulkified

I have written an APEX Class that sends an email when a client is released. There is a method that I thought I had bulkified but I was told it does not. This is because this method calls another function which actually does the actual email creation and that is not bulkified. Can someone guide me as to how the SOQL queries can be taken out of the method?
global class LM_ChangeAccountRT {
private static final Profile sysAdmin = [select id from profile where name='System Administrator'];
#AuraEnabled
public static String resendEmails(List<String> accountIdList) {
String response = null;
try {
//Only send emails if user is either an ARMS Administor or System Administrator
if (System.label.ARMS_Administrator_Profile_Id == userinfo.getProfileId() ||
sysAdmin.Id == userinfo.getProfileId()) {
List<Account> accList = [SELECT Id,Client_Released__c, RecordTypeId,Client_Number__c, Client_Released__c, Email_Sent__c FROM Account WHERE Id IN:accountIdList];
for(Account acc: accList){
if (acc.Client_Number__c != null && acc.Client_Released__c && acc.Email_Sent__c == true) {
sendpdfgenerationEmails(acc); //this is the method thats not bulkified.
acc.Email_Sent__c = false;
response = 'Email Sent';
}else {
response= 'Access Denied';
}
}
update accList;
}
}catch(Exception e) {
System.debug(e.getMessage());
response = 'Error sending emails';
}
return response;
}
public static void sendpdfgenerationEmails(Account acc){
system.debug('start of confirmation card and pdf generation');
//Logic to find which VF template is used to send an email.
list<EmailTemplate> templateId = new list<EmailTemplate>();
string temppartner;
String partner_opt_in_attachment;
boolean sendFCAmail;
List<Dealership_PDF_Generation__c> custsettingdata = Dealership_PDF_Generation__c.getall().values();
System.debug('custom setting size = ' + custsettingdata.size());
// Fetch State
if(acc.Dealership_State__c!=null && acc.Dealership_Partner__c!=null)
{
for(Dealership_PDF_Generation__c tempcustsetting :custsettingdata)
{
if(acc.Dealership_Partner__c == tempcustsetting.Dealership_Partner__c && acc.Dealership_State__c==tempcustsetting.State__c && tempcustsetting.State__c=='WA' && acc.Dealership_State__c=='WA'){
//For WA State
// temppartner= '%' + tempcustsetting.TEMPLATE_Unique_name__c + '%';
temppartner= tempcustsetting.TEMPLATE_Unique_name__c;
if(acc.Dealership_Spiff_Payment__c == '% premium'){
partner_opt_in_attachment=tempcustsetting.opt_in_form_premium__c;
}else{
partner_opt_in_attachment=tempcustsetting.opt_in_form_nonpremium__c;
}
}
else if(acc.Dealership_Partner__c == tempcustsetting.Dealership_Partner__c && acc.Dealership_State__c==tempcustsetting.State__c && tempcustsetting.State__c=='TX' && acc.Dealership_State__c=='TX'){
//For TX State
//temppartner= '%' + tempcustsetting.TEMPLATE_Unique_name__c + '%';
temppartner= tempcustsetting.TEMPLATE_Unique_name__c;
if(acc.Dealership_Spiff_Payment__c == '% premium'){
partner_opt_in_attachment=tempcustsetting.opt_in_form_premium__c;
}else{
partner_opt_in_attachment=tempcustsetting.opt_in_form_nonpremium__c;
}
}
else if(acc.Dealership_Partner__c == tempcustsetting.Dealership_Partner__c && acc.Dealership_State__c!=tempcustsetting.State__c && tempcustsetting.State__c!='TX' && acc.Dealership_State__c!='TX' && acc.Dealership_State__c!='WA' &&tempcustsetting.State__c!='WA' ){
//For Non TX State
//temppartner= '%' + tempcustsetting.TEMPLATE_Unique_name__c + '%';
temppartner= tempcustsetting.TEMPLATE_Unique_name__c;
if(acc.Dealership_Spiff_Payment__c == '% premium'){
partner_opt_in_attachment=tempcustsetting.opt_in_form_premium__c;
}else{
partner_opt_in_attachment=tempcustsetting.opt_in_form_nonpremium__c;
}
system.debug('grabbed template: ' + temppartner);
}
if(acc.Dealership_Partner__c != null && temppartner!=null ){
templateId.add([Select id,DeveloperName from EmailTemplate where DeveloperName = :temppartner]); //This will probably cause governor limit issues. First problem
}
if (partner_opt_in_attachment != null) {
StaticResource sr = [Select s.Name, s.Id, s.Body From StaticResource s where s.Name =: partner_opt_in_attachment]; //'static_resource' is the name of the static resource PDF. This is another SOQL query that will cause problems
Blob tempBlob = sr.Body;
Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
efa.setBody(tempBlob);
efa.setFileName('Opt-in.pdf');
List<Messaging.EmailFileAttachment> attachments = new List<Messaging.EmailFileAttachment>();
attachments.add(efa);
// add attachment to each email
for (Messaging.SingleEmailMessage email : emails) {
email.setFileAttachments(attachments);
}
}
system.debug('email sent: ' + emails.size());
Messaging.sendEmail(emails);
}
}
}
The reason why I am trying to bulkify this is because I have written a APEX scheduler that calls the resendemails method everyday at 7am to check which records need to have an email sent. I am afraid that if there are more than a 100 clients then it will cause problems and not send the emails. Any suggestions on how I can optimize the sendpdfemailgeenration() method?
Thank you
Yes, you are right - your's resendEmails() method is not bulkified.
Firstly, let me explain you why is that:
SOQL to get Accounts
Loop 1 on List of Account records
Call sendpdfgenerationEmails() method
Retrieve list of Dealership_PDF_Generation__c records
Loop 2 on List of Dealership_PDF_Generation__c records
SOQL to get StaticResources - Very bad! It's inside double loop!
Call Messaging.sendEmail() method - Very bad! It's inside double loop!
Update on List of Account records
You need to remember that:
1. You should never do SOQLs in loops! - Limit 100 SOQLs per transaction
2. You should never call Messaging.sendEmail() in loops! - Limit 10 calls per transaction
Now let me guide you how to refactor this method:
#AuraEnabled
public static String resendEmails(List<String> accountIdList) {
// 1. SOQL for List of Account records
// 2. Retrieve list of Dealership_PDF_Generation__c records
// 3. SOQL for List of StaticResources for all Names from Dealership_PDF_Generation__c records
// 4. Declaration of new List variable for Messaging.SingleEmailMessage objects
// 5. Loop 1 on List of Account records
// 6. Call new "prepareEmailsForAccount()" method, which prepares and returns list of Messaging.SingleEmailMessage objects
// 7. Add returned Messaging.SingleEmailMessage objects to list from point 4
// 8. End of loop 1
// 9. Call "Messaging.sendEmail()" method with list from point 4
// 10. Update on List of Account records
}
With this you will avoid SOQLs and calling Messaging.sendEmail() method in loops.

How to check if a User Folder or any other Folder in DNN is empty?

​Hi,
Which code can I use to check if a User Folder or any other folder in DNN has no files? I have looked at: Retrieve FileID from DotNetNuke using FileName...​ but no luck.
Is this code correct to use to check if files exist? I don't want to specify a specific file name.
FolderManager.Instance.GetFiles();
What should come in the brackets for the code above? Can someone please provide an example?​
You can do this:
FolderController controller = new FolderController();
Dictionary<string, FolderInfo> list = controller.GetFolders(PortalId);
foreach (var folder in list)
{
List<IFileInfo> files = FolderManager.Instance.GetFiles(folder.Value).ToList();
Label1.Text += folder.Key + ": " + files.Count();
}
I found another way of doing this as well using System.IO.Directory.
var userfolderpath = FolderManager.Instance.GetUserFolder(UserInfo).FolderPath;
var userfolderpath_ = #"\" + userfolderpath;
var portalPath = Server.MapPath("~/Portals/" + this.PortalId);
var physicalPath = System.IO.Path.Combine(portalPath, userfolderpath);
var list = System.IO.Directory.GetFiles(physicalPath);
if (list?.Length > 0)
{
//sumbit_files.Attributes.Add("style", "display:block;");
//message_container.Attributes.Add("style", "display:block;");
if (userfolderpath != null)
{
dgrFileList.Columns[0].HeaderText = Localization.GetString("FileHeader", this.LocalResourceFile);
dgrFileList.Columns[1].HeaderText = Localization.GetString("FileWriteDate", this.LocalResourceFile);
dgrFileList.Columns[2].HeaderText = Localization.GetString("FileDownloadHeader", this.LocalResourceFile);
dgrFileList.DataSource = FileUtility.GetSafeFileList(string.Concat(portalPath, userfolderpath_), GetExcludedFiles(), GetSortOrder());
dgrFileList.DataBind();
}
}

Pagination in Google cloud endpoints + Datastore + Objectify

I want to return a List of "Posts" from an endpoint with optional pagination.
I need 100 results per query.
The Code i have written is as follows, it doesn't seem to work.
I am referring to an example at Objectify Wiki
Another option i know of is using query.offset(100);
But i read somewhere that this just loads the entire table and then ignores the first 100 entries which is not optimal.
I guess this must be a common use case and an optimal solution will be available.
public CollectionResponse<Post> getPosts(#Nullable #Named("cursor") String cursor,User auth) throws OAuthRequestException {
if (auth!=null){
Query<Post> query = ofy().load().type(Post.class).filter("isReviewed", true).order("-timeStamp").limit(100);
if (cursor!=null){
query.startAt(Cursor.fromWebSafeString(cursor));
log.info("Cursor received :" + Cursor.fromWebSafeString(cursor));
} else {
log.info("Cursor received : null");
}
QueryResultIterator<Post> iterator = query.iterator();
for (int i = 1 ; i <=100 ; i++){
if (iterator.hasNext()) iterator.next();
else break;
}
log.info("Cursor generated :" + iterator.getCursor());
return CollectionResponse.<Post>builder().setItems(query.list()).setNextPageToken(iterator.getCursor().toWebSafeString()).build();
} else throw new OAuthRequestException("Login please.");
}
This is a code using Offsets which seems to work fine.
#ApiMethod(
name = "getPosts",
httpMethod = ApiMethod.HttpMethod.GET
)
public CollectionResponse<Post> getPosts(#Nullable #Named("offset") Integer offset,User auth) throws OAuthRequestException {
if (auth!=null){
if (offset==null) offset = 0;
Query<Post> query = ofy().load().type(Post.class).filter("isReviewed", true).order("-timeStamp").offset(offset).limit(LIMIT);
log.info("Offset received :" + offset);
log.info("Offset generated :" + (LIMIT+offset));
return CollectionResponse.<Post>builder().setItems(query.list()).setNextPageToken(String.valueOf(LIMIT + offset)).build();
} else throw new OAuthRequestException("Login please.");
}
Be sure to assign the query:
query = query.startAt(cursor);
Objectify's API uses a functional style. startAt() does not mutate the object.
Try the following:
Remove your for loop -- not sure why it is there. But just iterate through your list and build out the list of items that you want to send back. You should stick to the iterator and not force it for 100 items in a loop.
Next, once you have iterated through it, use the iterator.getStartCursor() as the value of the cursor.

Composite C1 blog - not using media folder

I have a Composite C1 4.04 site.
The user needs a blog - and they can upload images.
However, the images go into some weird virtual 'media' folder that apparently doesn't exist - and they aren't stored like normal images.
I would like them instead to just go into a regular folder - as I need to manipulate them later - to re-compress them (for example).
How can I do this?
thx
The media files are plugable in Composite C1, in the default implementation media files are represented as
A record in a database, that contains file's meta data (mime type, etc)
A physical file with the content, located under "\App_Data\Media" f.e.
\App_Data\Media\0b11c288-5432-4482-a776-3eb0ac9ad437
This has certain advantages - having a database record allows to keep additional meta data relevant to serving http requests (such as MimeType), apply security to those files, etc.
; also file names don't follow file system restrictions (such as path length and certain reserved names/forbidden characters) - so when you upload a file,
you don't have to care if website folder path + media folder path + file name would exceed 255 characters.
There are also other media archive plug-ings, when f.e. files are kept in a SQL data base or files are fetched from a Facebook album.
If you want to compress the image files, you can iterate over files in \App_Data\Media\ folder. You can get the list of media files by calling Get() on a DataConnection instance.
If you want to export media to a different solution, you can use the following code that copies a Composite C1 media folder to a physical folder:
private int MediaToFiles(string mediaFolder, string physicalFolder)
{
if (!mediaFolder.StartsWith("/"))
{
mediaFolder = "/" + mediaFolder;
}
string mediaFolderPrefix = mediaFolder == "/" ? "/" : mediaFolder + "/";
using (var conn = new DataConnection())
{
var mediaFiles = conn.Get<IMediaFile>().Where(f => string.Equals(f.FolderPath, mediaFolder, StringComparison.OrdinalIgnoreCase)
|| f.FolderPath.StartsWith(mediaFolderPrefix, StringComparison.OrdinalIgnoreCase))
.ToList();
if(mediaFiles.Count == 0) return 0;
Directory.CreateDirectory(physicalFolder);
int newFiles = 0;
foreach (var file in mediaFiles)
{
string targetFolder = file.FolderPath.Length <= mediaFolderPrefix.Length ?
physicalFolder : Path.Combine(physicalFolder, file.FolderPath.Substring(mediaFolderPrefix.Length));
Directory.CreateDirectory(targetFolder);
string targetFilePath = Path.Combine(targetFolder, file.FileName);
if(File.Exists(targetFilePath) && File.GetLastWriteTime(targetFilePath) == file.LastWriteTime) continue;
using (var stream = file.GetReadStream())
{
using (var outputStream = File.Create(targetFilePath, 8192))
{
stream.CopyTo(outputStream);
outputStream.Close();
}
}
File.SetLastWriteTime(targetFilePath, file.LastWriteTime.Value);
newFiles++;
}
return newFiles;
}
}
// Example of usage:
int newFiles = MediaToFiles("/", #"c:\Temp\C1media"); // Copying all the media files
OutPut("New files: " + newFiles);
int newFiles2 = MediaToFiles("/Office", #"c:\Temp\C1media\Office pictures"); // Copying only "Office" media folder
OutPut("New files: " + newFiles2);

Resources