I have the following JS function which serves as a first prototype for a mozilla thunderbird extension.
The goal is to connect to a server and download a sample file, then unzipping it and storing the contents in the thunderbird profile folder.
Now this all works fine, except that the execution of the function stops after creating the zip file on the file system. So i have to restart the function again, in order to get the second part of the function executed which extracts the user.js file from the zip file.
Any ideas what the problem could be?
function downloadFile(httpLoc) {
// get profile directory
var file = Components.classes["#mozilla.org/file/directory_service;1"].
getService(Components.interfaces.nsIProperties).
get("ProfD", Components.interfaces.nsIFile);
var profilePath = file.path;
// change profile directory to native style
profilePath = profilePath.replace(/\\/gi , "\\\\");
profilePath = profilePath.toLowerCase();
// download the zip file
try {
//new obj_URI object
var obj_URI = Components.classes["#mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService).newURI(httpLoc, null, null);
//new file object
var obj_TargetFile = Components.classes["#mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
//set to download the zip file into the profil direct
obj_TargetFile.initWithPath(profilePath + "\/" + "test.zip");
//if file the zip file doesn't exist, create it
if(!obj_TargetFile.exists()) {
alert("zip file wird erstellt");
obj_TargetFile.create(0x00,0644);
}
//new persitence object
var obj_Persist = Components.classes["#mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Components.interfaces.nsIWebBrowserPersist);
// with persist flags if desired ??
const nsIWBP = Components.interfaces.nsIWebBrowserPersist;
const flags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
obj_Persist.persistFlags = flags | nsIWBP.PERSIST_FLAGS_FROM_CACHE;
//save file to target
obj_Persist.saveURI(obj_URI,null,null,null,null,obj_TargetFile);
} catch (e) {
alert(e);
} finally {
// unzip the user.js file to the profile direc
// creat a zipReader, open the zip file
var zipReader = Components.classes["#mozilla.org/libjar/zip-reader;1"]
.createInstance(Components.interfaces.nsIZipReader);
zipReader.open(obj_TargetFile);
//new file object, thats where the user.js will be extracted
var obj_UnzipTarget = Components.classes["#mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
//set path for the user.js
obj_UnzipTarget.initWithPath(profilePath + "\/" + "user.js");
// if user.js doesn't exist, create it
if(!obj_UnzipTarget.exists()) {
alert("user.js wird erstellt");
obj_UnzipTarget.create(0x00,0644);
}
// extract the user.js out of the zip file, to the specified path
zipReader.extract("user.js", obj_UnzipTarget);
zipReader.close();
}
}
var hello = {
click: function() {
downloadFile("http://pse2.iam.unibe.ch/profiles/profile.zip");
},
};
saveURI is asynchronous, so you need to set the progress listener on the persist object to know when it has finished. Here's an example of setting a progress listener and later on there's a check to see whether the transfer has finished.
Related
I'm horrible at coding so I'm sure this will need some work.
My Problem: My company does work for a lot of other companies (example Drive hierarchy photo attached). Each company we work with gets their own folder that is nested under the folder 'Shirts for other companies". We put all their assets into these folders (logos, mocks, quotes).
We want to build a script that will look into the individual company folders and take any file that starts with the word Mock and automatically copy it and put it into the database folder found in the picture below.
Here is the script have so far. but I'm having trouble getting into the subfolders (ford tshirts and designs). Not only that, but if it runs everyday the script will keep duplicating the files it has duplicated in the past which I want to avoid.
Script:
Function getTheFiles() {
var dApp = DriveApp;
var folderIter = dApp.getFolderByName("Shirts for other companies");
var folder = folderIter.next();
var filesIter = folder.getFiles();
var dataBase = folder.getFoldersByName("database1").next();
var i = 1;
while(filesIter.hasNext()) {
var file = filesIter.next();
var filename = file.getName();
if(filename = "mocking") {
file.makeCopy(dataBase);
}
logger.log(filename);
i++;
}
If I understood you correctly, you want to:
Copy all files from the different subfolders inside a folder called "Shirts for other companies", that start with the word mock, to the Database folder (which is also inside the main folder).
Avoid files getting copied many times.
If that's the case, you could do the following:
Search for all files in each subfolder of the main folder that start with mock, excluding the files inside Database folder. For this, you iterate through all files in each subfolder (after checking the subfolder is not named Database folder. For each file, you check that the name start with mock, using the method substring.
To keep track of which files are copied, and so avoid making duplicates, you can use PropertiesService, which can store key-value pairs. The id of every copied file is copied to the script property, and then, the next time the script runs, it checks whether the id is in the property. If that's the case, the file doesn't get copied again. One thing to notice is that script properties can only store strings, so that arrays have to be converted to a string every time we want to store a new id (via toString, and back to an array, via split.
The function below does all these things (check inline comments for more details):
function copyFiles() {
var mainFolder = DriveApp.getFoldersByName("Shirts for other companies").next();
var folders = mainFolder.getFolders(); // Get folder iterator from main folder
var databaseFolderName = "Database folder"; // You database folder name
var databaseFolder = mainFolder.getFoldersByName(databaseFolderName).next(); // Get databse folder
var idsArray = []; // Array to store the ids of the copied files
while (folders.hasNext()) { // Iterate through each folder in the main folder
var folder = folders.next();
if (folder.getName() !== databaseFolderName) { // Check current folder is not the database folder
var files = folder.getFiles();
while (files.hasNext()) { // Iterate through each file in each subfolder
var file = files.next();
if (file.getName().substring(0, 4).toLowerCase() === "mock") { // Check that file name starts with "mock"
// Get ids of the files that were copied in previous executions:
var key = "copied-ids";
var scriptProperties = PropertiesService.getScriptProperties();
var ids = scriptProperties.getProperty(key);
if (ids) idsArray = ids.split(",");
else ids = "";
// Get current file id:
var id = file.getId();
// Check that current file id is not in properties (not copied before):
if (idsArray.indexOf(id) === -1) {
file.makeCopy(databaseFolder); // Copy file to database folder
idsArray.push(id); // Add file id to the array of copied files
}
ids = idsArray.toString();
scriptProperties.setProperty(key, ids);
}
}
}
}
}
Reference:
PropertiesService
String.prototype.substring()
Array.prototype.toString()
String.prototype.split()
I hope this is of any help.
This function would search your entire Google Drive for files starting the the letter Mock and put Name, url, id, type (folder or file) into the active spreadsheet and tab named MoclList;
function getAllMocks() {
var ss=SpreadsheetApp.getActive();
var sh1=ss.getSheetByName('MocksList');
sh1.clearContents();
sh1.appendRow(['Name','Url','Id','Type']);
getFnF();
SpreadsheetApp.getUi().alert('Process Complete')
}
var level=0;
function getFnF(folder) {
var folder= folder || DriveApp.getRootFolder();
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('MocksList');
var files=folder.getFiles();
while(files.hasNext()) {
var file=files.next();
if(file.getName().toLowerCase().slice(0,4)=='mock') {
var firg=sh.getRange(sh.getLastRow() + 1,level + 1);
firg.setValue(file.getName());
firg.offset(0,1).setValue(Utilities.formatString('=HYPERLINK("%s","%s")',file.getUrl(),'FILE: ' + file.getName()));
firg.offset(0,2).setValue(file.getId());
firg.offset(0,3).setValue('File');
}
}
var subfolders=folder.getFolders()
while(subfolders.hasNext()) {
var subfolder=subfolders.next();
var forg=sh.getRange(sh.getLastRow() + 1,level + 1);
forg.setValue(subfolder.getName());
forg.offset(0,1).setValue(Utilities.formatString('=HYPERLINK("%s","%s")',subfolder.getUrl(),'FOLDER: ' + subfolder.getName()));
forg.offset(0,2).setValue(subfolder.getId());
forg.offsert(0,3).setValue('Folder');
//level++;
getFnF(subfolder);
}
//level--;
}
I am trying to build an application in Electron which has a html form with image Upload button. So my purpose is to ask the user to upload an image and i want to save the image file somewhere in the local folder within the app and retrieve the image whenever i need.How would i achieve this ?
If I understand you correctly, you intend to store the image on the user's computer so there's no need to do a remote upload. You simply have to copy the file from its original location to the application local data path.
To achieve this, you could add to your form a button which would first trigger a dialog to let the user browse for the file.
Then you would copy the chosen file to your application local data path.
After that, the idea would be to store some information about the image file so that you can retrieve it for later use.
const { app, dialog } = require('electron');
const fs = require('fs');
const path = require("path");
// The function triggered by your button
function storeImageFile() {
// Open a dialog to ask for the file path
const filePath = dialog.showOpenDialog({ properties: ['openFile'] })[0];
const fileName = path.basename(filePath);
// Copy the chosen file to the application's data path
fs.copyFile(filePath, (app.getPath('userData') + fileName), (err) => {
if (err) throw err;
console.log('Image ' + fileName + ' stored.');
// At that point, store some information like the file name for later use
});
}
Updated answer:
The dialog.showOpenDialog() returns a promise
const electron = require('electron');
const { dialog } = electron; // electron.remote; (if in renderer process)
const fs = require('fs'); // module that interacts with the file system
const path = require("path"); // utilities for working with directory paths
function uploadImageFile() {
// opens a window to choose file
dialog.showOpenDialog({properties: ['openFile']}).then(result => {
// checks if window was closed
if (result.canceled) {
console.log("No file selected!")
} else {
// get first element in array which is path to file selected
const filePath = result.filePaths[0];
// get file name
const fileName = path.basename(filePath);
// path to app data + fileName = "C:\Users\John\AppData\Roaming\app_name\picture.png"
imgFolderPath = path.join(app.getPath('userData'), fileName);
// copy file from original location to app data folder
fs.copyFile(filePath, imgFolderPath, (err) => {
if (err) throw err;
console.log(fileName + ' uploaded.');
});
}
});
}
// click event to trigger upload function
// In html: <input type="button" class="upload-image" value="Upload Image">
$(".upload-image").on("click", () => {
uploadImageFile()
});
I have a javascript I found but it starts with having the user choose a folder where it will grab files. I want to create a watch folder so I want to tell the javascript the folder to grab the files from, not let the user choose. I can't for the life of me figure out how to do this. I know applescript but cannot grasp javascript. Thank you!
Here is what I believe the area I need to change:
function main() {
// user settings
var prefs = new Object();
prefs.sourceFolder = '/Volumes/SERVER_RAID/•Current/MPC'; // default browse location (default: '~')
prefs.removeFileExtensions = true; // remove filename extensions for imported layers (default: true)
prefs.savePrompt = true; // display save prompt after import is complete (default: false)
prefs.closeAfterSave = true; // close import document after saving (default: false)
// prompt for source folder
var sourceFolder = Folder.selectDialog('Where are the Front and Back files?', Folder(prefs.sourceFolder));
// ensure the source folder is valid
if (!sourceFolder) {
return;
}
else if (!sourceFolder.exists) {
alert('Source folder not found.', 'Script Stopped', true);
return;
}
// add source folder to user settings
prefs.sourceFolder = sourceFolder;
// get a list of files
var fileArray = getFiles(prefs.sourceFolder);
// if files were found, proceed with import
if (fileArray.length) {
importFolderAsLayers(fileArray, prefs);
}
// otherwise, diplay message
else {
alert("The selected folder doesn't contain any recognized images.", 'No Files Found', false);
}
}
///////////////////////////////////////////////////////////////////////////////
// getFiles - get all files within the specified source
///////////////////////////////////////////////////////////////////////////////
function getFiles(sourceFolder) {
// declare local variables
var fileArray = new Array();
var extRE = /\.(?:png)$/i;
// get all files in source folder
var docs = sourceFolder.getFiles();
var len = docs.length;
for (var i = 0; i < len; i++) {
var doc = docs[i];
// only match files (not folders)
if (doc instanceof File) {
// store all recognized files into an array
var docName = doc.name;
if (docName.match(extRE)) {
fileArray.push(doc);
}
}
}
// return file array
return fileArray;
}
///////////////////////////////////////////////////////////////////////////////
To achieve this you'll need to specify the path to your desired folder as String.
If you take a look at the updated code sample below you'll notice that line 4 of your original code which read:
prefs.sourceFolder = '/Volumes/SERVER_RAID/•Current/MPC';
has been changed to:
prefs.sourceFolder = Folder('~/Desktop/targetFolder');
This now assumes the target folder is named targetFolder and it resides in your Desktop folder. You'll need to change the '~/Desktop/targetFolder' part as necessary to point to the folder you actually want. It also assumes you're running this on macOS as the shortcut to the Desktop folder (i.e. the ~/ part) will not be recognized on Windows.
What are the other ways I can specify the path?
You can specify path name using absolute paths such as:
prefs.sourceFolder = Folder('/Users/JohnDoe/Desktop/targetFolder');
Note: This example actually points to the same folder as the first example. Assuming that the user is called John Doe of course!
More info about setting file paths can be found here.
What other changes were made to your code example:
Lines 9 to 22 in your example code which read:
// prompt for source folder
var sourceFolder = Folder.selectDialog('Where are the Front and Back files?', Folder(prefs.sourceFolder));
// ensure the source folder is valid
if (!sourceFolder) {
return;
}
else if (!sourceFolder.exists) {
alert('Source folder not found.', 'Script Stopped', true);
return;
}
// add source folder to user settings
prefs.sourceFolder = sourceFolder;
are now redundant. Instead, they have been replaced with the following snippet which will alert you if the folder you specified cannot be found:
// ensure the source folder exists.
if (!prefs.sourceFolder.exists) {
alert('Source folder not found.\n' + prefs.sourceFolder, 'Script Stopped', true);
return;
}
I added main() on line 30 below to invoke the main function. However, if you have that elsewhere in your code you can delete it.
Updated code sample:
function main() {
// User settings
var prefs = new Object();
prefs.sourceFolder = Folder('~/Desktop/targetFolder');
prefs.removeFileExtensions = true;
prefs.savePrompt = true;
prefs.closeAfterSave = true;
// ensure the source folder exists.
if (!prefs.sourceFolder.exists) {
alert('Source folder not found.\n' + prefs.sourceFolder, 'Script Stopped', true);
return;
}
// Get a list of files
var fileArray = getFiles(prefs.sourceFolder);
// If files were found, proceed with your tasks.
if (fileArray.length) {
alert('I found image(s) in the specified folder\n' +
'Now you need to write code to perform out a task :)');
// <-- Continiue your code here
}
// otherwise, diplay message
else {
alert('The selected folder doesn\'t contain any recognized images.', 'No Files Found', false);
}
}
main(); // <-- Invokes the `main` function
/**
* getFiles - get all files within the specified source
* #param {String} sourceFolder - the path to the source folder.
*/
function getFiles(sourceFolder) {
// declare local variables
var fileArray = new Array();
var extRE = /\.(?:png)$/i;
// get all files in source folder
var docs = sourceFolder.getFiles();
var len = docs.length;
for (var i = 0; i < len; i++) {
var doc = docs[i];
// only match files (not folders)
if (doc instanceof File) {
// store all recognized files into an array
var docName = doc.name;
if (docName.match(extRE)) {
fileArray.push(doc);
}
}
}
// return file array
return fileArray;
}
I have have one page where I want to accept one file and 3-4 user inputs , I was able to achieve this using connect-multiparty middle-ware but the name of uploaded file is something gibberish with correct extension and uploaded files contents are too correct.
I want to achieve below things
Set name of file being uploaded
Create copy of file with different name if the file with same name exists in target directory
Set max limit on size and restrict type of file.
I searched on net but could not find any working example. My complete code is as below
var express = require('express');
var router = express.Router();
var fs = require('fs');
var multiparty = require('connect-multiparty');
var multipartyMiddleware = multiparty({
uploadDir : '../public/uploads'
});
router.post('/api/user/uploads', multipartyMiddleware, function(req, res) {
var file = req.files.file;
console.log(file.name);
console.log(file.type);
console.log(file);
console.log(req.body.test);
console.log("The file was saved!");
res.json({
success : 1
});
return;
});
module.exports = router;
You will have to rename the file after being copied using fs.rename(), or modify the source code of multiparty inside node_modules. Inside their code they have a function that does the renaming:
function uploadPath(baseDir, filename) {
var ext = path.extname(filename).replace(FILE_EXT_RE, '$1');
var name = randoString(18) + ext;
return path.join(baseDir, name);
}
I have done some modifications to their code so I could use it a little bit like multer:
https://gist.github.com/Edudjr/999c80df952458cc583272a5161b4d08
You would use it like so:
var EXT_RE = /(\.[_\-a-zA-Z0-9]{0,16}).*/g;
var options = {
uploadDir : path.join(__dirname,'../public/images'),
filename: function(filename, callback){
var name = filename.replace(EXT_RE, "");
callback(name+'-YEAH.png');
}
}
var form = new multiparty.Form(options);
They strongly advise you to save the files in the temp folder to prevent DoS on your server.
https://github.com/pillarjs/multiparty/issues/64
You can access it easily, I used this to get file name.
console.log(req.files.uploads.path.split('\\')[1]);
I am using uploads from Angular.
I'm trying to save a file in Illustrator using Javascript but I keep getting an error.
Here is what works, but is not what I want:
// save as
var dest = "~/testme.pdf";
saveFileToPDF(dest);
function saveFileToPDF (dest) {
var doc = app.activeDocument;
if ( app.documents.length > 0 ) {
var saveName = new File ( dest );
saveOpts = new PDFSaveOptions();
saveOpts.compatibility = PDFCompatibility.ACROBAT5;
saveOpts.generateThumbnails = true;
saveOpts.preserveEditability = true;
alert(saveName);
doc.saveAs( saveName, saveOpts );
}
}
The var "dest" saves the file to the root of my Mac user account. I simply want to save the file relative to the source document in a subfolder, so I tried this:
var dest = "exports/testme.pdf";
This brings up a dialogue with ".pdf" highlighted, properly awaiting input inside the "exports" folder that I already created. I can type something and it will save, but it ignores the file name "testme.pdf" that was specified in the code. I can type "cheese" over the highlighted ".pdf" it knows I want, and it will save "cheese.pdf" in the folder "exports".
I also tried these with no luck:
var dest = "exports/testme";
var dest = "/exports/testme.pdf";
var dest = "testme.pdf";
etc., etc.
What am I missing?
To use saveAs without a dialog popping up, you need to use the global property userInteractionLevel:
var originalInteractionLevel = userInteractionLevel;
userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS;
...
userInteractionLevel = originalInteractionLevel;
Since you want to save relative to your document, so first find the path for your current document as follows
var path = app.activeDocument.path;
var dest = path + "/exports/testme.pdf";
You can also check whether exports folder exists or not if not you can create with script as follows
var path = app.activeDocument.path;
var exportFolder = Folder(path + "/exports");
if(!exportFolder.exists){
exportFolder.create();
}
var dest = exportFolder + "/testme.pdf";