Google script listing folders, subfolders and files - directory

I have a google script, listing me FolderName, FolderID, Filename and FileID of a Google Drive Folder including subfolders.
However, in the first row I would need the complete Full Path to the file instead only the foldername
eg a file named abc.pdf is in the folder /documents/files/new/abc.pdf
My script is showing me the foldername new instead the full folder path /documents/files/new/
`function listFolderContents() {
var ss = SpreadsheetApp.getActive();
var sheet = SpreadsheetApp.getActiveSheet();
sheet.clearContents();
sheet.appendRow(["Foldername","FolderID","Filename","FileID"]);
var topFolderID = DriveApp.getFolderById('FOLDER_ID_HERE');
var foldername = topFolderID.getName();
var folders = DriveApp.getFoldersByName(foldername)
var folder = folders.next();
traverseFolder(folder, sheet);
sortByFoldername();
};
function traverseFolder(folder, sheet) {
listFilesInFolder(folder, sheet);
var subFolders = folder.getFolders();
while (subFolders.hasNext()) {
traverseFolder(subFolders.next(), sheet);
}
}
function listFilesInFolder(folder, sheet) {
var folderID = folder.getId();
var foldername = folder.getName();
var contents = folder.getFiles();
while(contents.hasNext()) {
var file = contents.next();
var filename = file.getName();
var fileID = file.getId();
sheet.appendRow( [foldername,folderID,filename,fileID] );
}
}
function sortByFoldername(){
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('Sheet1');
var range = sheet.getRange("A2:D");
range.sort([{column: 1, ascending: true}]);
}`

I finally did it!!!
This script is working as intended and will create a List with FolderName, FolderID, Filename and FileID of all Folders and Files included in a Google Drive Fiolder:
var folderId = 'FOLDERIDGOESHERE'; //Replace the folder id with the folder id of the parent folder in the Google Drive, where you would like to start sorting through the drive.
// Main function 1: List all folders, & write into the current sheet.
function listFolders(){
getFolderTree(folderId, false);
};
// Main function 2: List all files & folders, & write into the current sheet.
function listAll(){
getFolderTree(folderId, true);
};
// =================
// Get Folder Tree
function getFolderTree(folderId, listAll) {
try {
// Get folder by id
var parentFolder = DriveApp.getFolderById(folderId);
// Initialise the sheet
var file, data, sheet = SpreadsheetApp.getActiveSheet();
sheet.clear();
sheet.appendRow(["Full Path", "Folder ID", "FileName"]);
// Get files and folders
getChildFolders(parentFolder.getName(), parentFolder, data, sheet, listAll);
} catch (e) {
Logger.log(e.toString());
}
};
// Get the list of files and folders and their metadata in recursive mode
function getChildFolders(parentName, parent, data, sheet, listAll) {
var childFolders = parent.getFolders();
// List folders inside the folder
while (childFolders.hasNext()) {
var childFolder = childFolders.next();
// Logger.log("Folder Name: " + childFolder.getName());
data = [
parentName + "/" + childFolder.getName(),
childFolder.getId()
];
// Write
sheet.appendRow(data);
// List files inside the folder
var files = childFolder.getFiles();
while (listAll & files.hasNext()) {
var childFile = files.next();
// Logger.log("File Name: " + childFile.getName());
data = [
parentName + "/" + childFolder.getName(),
childFolder.getId(),
childFile.getName(),
childFile.getId()
];
// Write
sheet.appendRow(data);
}
// Recursive call of the subfolder
getChildFolders(parentName + "/" + childFolder.getName(), childFolder, data, sheet, listAll);
}
};

Related

Download multiple files (50mb) blazor server-side

i can't really find a way to download a 100mb zip file from the server to the client and also show the progress while downloading. So how will this look for a normal api controller i can add to my server-side project? if lets say i have 3 files i want to download at 50mb each.
i have tried using JSInterop like this, but this is not showing the progress of the file download, and how will i do if i want to download 3 seperate files at the same time?
try
{
//converting file into bytes array
var dataBytes = System.IO.File.ReadAllBytes(file);
await JSRuntime.InvokeVoidAsync(
"downloadFromByteArray",
new
{
ByteArray = dataBytes,
FileName = "download.zip",
ContentType = "application/force-download"
});
}
catch (Exception)
{
//throw;
}
JS:
function downloadFromByteArray(options: {
byteArray: string,
fileName: string,
contentType: string
}): void {
// Convert base64 string to numbers array.
const numArray = atob(options.byteArray).split('').map(c => c.charCodeAt(0));
// Convert numbers array to Uint8Array object.
const uint8Array = new Uint8Array(numArray);
// Wrap it by Blob object.
const blob = new Blob([uint8Array], { type: options.contentType });
// Create "object URL" that is linked to the Blob object.
const url = URL.createObjectURL(blob);
// Invoke download helper function that implemented in
// the earlier section of this article.
downloadFromUrl({ url: url, fileName: options.fileName });
// At last, release unused resources.
URL.revokeObjectURL(url);
}
UPDATE:
if im using this code, it will show me the progress of the file. But how can i trigger it from my code? This way does not do it. But typing the url does.
await Http.GetAsync($"Download/Model/{JobId}");
Controller
[HttpGet("download/model/{JobId}")]
public IActionResult DownloadFile([FromRoute] string JobId)
{
if (JobId == null)
{
return BadRequest();
}
var FolderPath = $"xxxx";
var FileName = $"Model_{JobId}.zip";
var filePath = Path.Combine(environment.WebRootPath, FolderPath, FileName);
byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
return File(fileBytes, "application/force-download", FileName);
}
UPDATE 2!
i have got it download with progress and click with using JSInterop.
public async void DownloadFiles()
{
//download all selectedFiles
foreach (var file in selectedFiles)
{
//download these files
await JSRuntime.InvokeAsync<object>("open", $"Download/Model/{JobId}/{file.Name}", "_blank");
}
}
Now the only problem left is.. it only downloads the first file out of 3.

How do I iterate over all the rows in my sheet to find match?

I am creating a script with google appscript to
read files in a folder
parse the name of the file in the folder
check if that name already exists in the sheet
if not add that to the list
if it does exist then check another column to see if an email is sent
if yes do nothing if no send the email.
I have tried
index of
,for loop to iterate over range.getValues()
None of them work properly as expected.
The data is of length 3.
function myFunction() {
getFileNameFromFolders('1TcR5oUKwH9hUG9xHBA6HuXQOr40etS5z');
}
function getFileNameFromFolders(folderID) {
var folder = DriveApp.getFolderById(folderID);
var files = folder.getFiles();
while (files.hasNext()) {
var file = files.next();
var fileName = file.getName();
var agentDetails = fileName.split("-");
var agentID = agentDetails[0];
var fileType = agentDetails[1];
var fileUrl = file.getUrl();
var fileDate = agentDetails[2];
locateAgent(agentID, fileType, fileDate, fileUrl, fileName);
}
}
function locateAgent(agentID, fileType, fileDate, url, uniqueKey) {
Logger.log('locating ' + uniqueKey);
var spreadSheet = SpreadsheetApp.openByUrl(SpreadsheetApp.getActiveSpreadsheet().getUrl());
var sheet = spreadSheet.getSheets()[0];
var range = sheet.getRange(2, 1, sheet.getLastRow() - 1, 6)
var data = range.getValues();
for (var i in data) {
if (data[i][5] == uniqueKey) {
Logger.log('yes');
break;
}
else { Logger.log('no');
var newRange = sheet.appendRow([agentID,fileType, fileDate, url, 'r', uniqueKey]);}
}
}
function sendEmails(email, fileUrl) {
var asPDF = DriveApp.getFileById(getIdFromUrl(fileUrl));
MailApp.sendEmail(email, 'test-email-with-agent-stuff-thing-i-dont-know-the-name', 'you should recieve a file named AID-2 as you are registered as 2', {
name: 'Automatic Emailer Script from DOER',
attachments: asPDF.getAs(MimeType.PDF)
});
}
function getIdFromUrl(url) {
return url.match(/[-\w]{25,}$/);
}
The loop adds to the list even though it exists. I may be getting the concept. If you have any other way I can do this, I would highly appreciate it.
You can implement a boolean variable which will be set to true if uniqueKey exists alredy
Modify your code as following:
function locateAgent(agentID, fileType, fileDate, url, uniqueKey) {
Logger.log('locating ' + uniqueKey);
var spreadSheet = SpreadsheetApp.openByUrl(SpreadsheetApp.getActiveSpreadsheet().getUrl());
var sheet = spreadSheet.getSheets()[0];
var range = sheet.getRange(2, 1, sheet.getLastRow()-1, 6)
var data = range.getValues();
var exists=false;
for (var i in data) {
if (data[i][5] == uniqueKey){
exists=true;
var row=i;
break;
}
}
if(exists==false){
Logger.log('it does not exist yet');
var insertRange = sheet.getRange(sheet.getLastRow()+1, 1, 1, 6);
//adapt according to your needs:
insertRange.setValues([[agentID],[fileType],[fileDate],[url],[],[uniqueKey]]);
}else{
//implement here your statement to check status column, e.g.:
if(data[row][status column]!="Sent"){
sendEmails(...);
}
}
}

Is it possible to create a folder on the Alfresco site by using OpenCMIS API?

I have the Presentation Web Script (script A) and the Data Web Script (script B).
In the script A I build the dialog that interacts with the script B.
Here I am forming some path where the some file will be uploaded (group, year and number parameters define this path):
...
var submitHandler = function() {
var dataWebScriptUrl = window.location.protocol + '//' +
window.location.host + "/alfresco/s/ms-ws/script-b?guest=true";
var yearCombo = document.getElementById("year");
var year = yearCombo.options[yearCombo.selectedIndex].value;
var groupCombo = document.getElementById("group");
var group = groupCombo.options[groupCombo.selectedIndex].value;
var numberCombo = document.getElementById("number");
var number = numberCombo.value;
var uploadedFile = document.getElementById("uploadedFile");
var file = uploadedFile.files[0];
var formData = new FormData();
formData.append("year", year);
formData.append("group", group);
formData.append("number", number);
formData.append("uploadedFile", file);
var xhr = new XMLHttpRequest();
xhr.open("POST", dataWebScriptUrl);
xhr.send(formData);
};
...
In script B, I'm using the Apache Chemistry OpenCMIS API to create a path in the CMIS-compatible Alfresco repository:
public class CustomFileUploader extends DeclarativeWebScript implements OpenCmisConfig {
...
private void retrievePostRequestParams(WebScriptRequest req) {
String groupName = null, year = null, number = null;
FormData formData = (FormData) req.parseContent();
FormData.FormField[] fields = formData.getFields();
for(FormData.FormField field : fields) {
String fieldName = field.getName();
String fieldValue = field.getValue();
if(fieldName.equalsIgnoreCase("group")) {
if(fieldValue.equalsIgnoreCase("services")) {
groupName = "Услуги";
...
}
firstLevelFolderName = "/" + groupName;
secondLevelFolderName = groupName + " " + year;
thirdLevelFolderName = number;
}
...
Folder firstLevelFolder =
createFolderIfNotExists(cmisSession, docLibFolder, firstLevelFolderName);
...
private Folder createFolderIfNotExists(Session cmisSession,
Folder parentFolder, String folderName) {
Folder subFolder = null;
for(CmisObject child : parentFolder.getChildren()) {
if(folderName.equalsIgnoreCase(child.getName())) {
subFolder = (Folder) child;
}
}
if(subFolder == null) {
Map<String, Object> props = new HashMap<>();
props.put("cmis:objectTypeId", "cmis:folder");
props.put("cmis:name", folderName);
subFolder = parentFolder.createFolder(props);
}
return subFolder;
}
private Folder getDocLibFolder(Session cmisSession, String siteName) {
String path = "/Sites/" + siteName + "/documentLibrary";
return (Folder) cmisSession.getObjectByPath(path);
}
private Session getCmisSession() {
SessionFactory factory = SessionFactoryImpl.newInstance();
Map<String, String> conf = new HashMap<>();
// http://localhost:8080/alfresco/api/-default-/public/cmis/versions/1.1/atom
conf.put(SessionParameter.ATOMPUB_URL, ATOMPUB_URL);
conf.put(SessionParameter.BINDING_TYPE, BindingType.ATOMPUB.value());
conf.put(SessionParameter.USER, USER_NAME);
conf.put(SessionParameter.PASSWORD, PASSWORD);
// "org.alfresco.cmis.client.impl.AlfrescoObjectFactoryImpl"
conf.put(SessionParameter.OBJECT_FACTORY_CLASS, OBJECT_FACTORY_CLASS);
conf.put(SessionParameter.REPOSITORY_ID, "-default-");
Session session = factory.createSession(conf);
return session;
}
...
It's all works well... But I need to create the directory structure on a specific site, e.g. "contracts-site", here:
/site/contracts-site/documentlibrary
When I specifying the following:
/Sites/contracts-site/documentLibrary/Услуги
/Sites/contracts-site/Услуги
/site/contracts-site/documentlibrary/Услуги
I get the following exception (depending on the path):
org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException: Object not found: /Sites/contracts-site/Услуги
When I specifying the following:
"/Услуги"
Everything works, but the directory structure is created outside the site...
How to create a folder on the Alfresco site by using OpenCMIS API?
Arn't you missing /company_home/ ?
This would lead to
/company_home/Sites/contracts-site/documentLibrary/Услуги
Just accidentally found the solution. Works perfectly if specify the following path:
// locate the document library
String path = "/Сайты/contracts-site/documentLibrary";
Ie, "Сайты" instead of "Sites"... (Cyrillic alphabet)
I'm using ru_RU locale and UTF-8 encoding. Then this example also works.

Count Total Folder in asp.net

I need to read a folder that contains multiple inner folders, which have more than 100 xml files. I need to read all these xml files one by one. I am using asp.net c# . How can I achieve this.
For Example: A is my folder, containing 1,2,3,4,5,6...200 as sub-folders.
Now the folder 1 contains a.xml, b.xml, c.xml ... Similarly folder 2 contains 1.xml, 2.xml, 3.xml ...
Now I need to read all these xml files one by one from each folder.
you can make use of parallel linq and do as below
int count = 0;
string[] files = null;
try
{
files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine("You do not have permission to access one or more folders in this directory tree.");
return;
}
catch (FileNotFoundException)
{
Console.WriteLine("The specified directory {0} was not found.", path);
}
var fileContents = from file in files.AsParallel()
let extension = Path.GetExtension(file)
where extension == ".xml"
let text = File.ReadAllText(file)
select new FileResult { Text = text , FileName = file }; //Or ReadAllBytes, ReadAllLines, etc.
try
{
foreach (var item in fileContents)
{
Console.WriteLine(Path.GetFileName(item.FileName) + ":" + item.Text.Length);
count++;
}
}
catch (AggregateException ae)
{
ae.Handle((ex) =>
{
if (ex is UnauthorizedAccessException)
{
Console.WriteLine(ex.Message);
return true;
}
return false;
});
}
Example takem from : https://msdn.microsoft.com/en-us/library/ff462679%28v=vs.110%29.aspx

asp.net System.IO.IOException

I am trying to programatically build a list of files in a folder, with certain attributes like file size and modified date.
I can return the file name, but any other attribute throws an error: System.IO.IOException: The filename, directory name, or volume label syntax is incorrect.
What am I missing here?
private void BuildDocList()
{
var files = Directory.GetFiles(Server.MapPath(FilePath));
foreach (var f in files)
{
var file = new FileInfo(FilePath + f);
var fileItem = new ListItem();
// this line works fine
fileItem.Text = file.Name.Split('.')[0] + ", ";
// this line causes the runtime error
fileItem.Text = file.CreationTime.ToShortDateString();
FileList.Items.Add(fileItem);
}
}
You're trying to use the wrong filename for the FileInfo - you're using the unmapped path. You should use something like this:
string directory = Server.MapPath(FilePath);
string[] files = Directory.GetFiles(directory);
foreach (string f in files)
{
FileInfo file = new FileInfo(Path.Combine(directory, f));
// Now the properties should work.

Resources