How to control or rename uploaded files in a [file] column

(*NOTE:  Only applicable for Google users (GSheet/GDrive))

As you all know, when a file column is used in your apps and your users upload a file, Appsheet does not retain the same filename as the user uploaded it.

The default filename saved to Google Drive is
[KEY_COLUMN].[COLUMN_NAME].[UTC-TIMESTAMP].[FILE EXTENSION]

No issues as the files can easily be accessible via the app.  But what if the backend users would want to identify the files easily when browsing through them via Google Drive interface?

This was not possible before, but luckily, Appsheet announced the new feature Use return values from Apps Script tasks which allows us to take advantage of this power script.

In a nutshell, here are the things you will need.

1. Setup the Image/Folder path of your [FILE] column.

JPAlpano_0-1661238234459.png
In the example above, all files will be saved in a root folder named URC Bank Docsunder a subfolder named after the [MERCHANT] column ("/URC Bank Docs/COMPANY ABC/the file here.ext")

 

2. Decide which columns in your table will be used as components of the file name you want to set to.
For example, in an app tracking received checks from merchants, the following columns are available:

  • CHEQUE_NO  :: Text (Key)
  • MERCHANT  :: Text
  • AMOUNT :: Decimal

And let's say you want your file names to be saved as
[MERCHANT] & "-Check No " & [CHEQUE NO] & "-" & [AMOUNT]
(ie.  COMPANY ABC-Check No 123456-1000)

 

3. Get the Google Drive folder id of the folder where files will be saved
You can get this from the folder url in Google Drive
(ie https://drive.google.com/drive/folders/1JAvB0fDTpayABCDEFG7vGBbNVOC1U794)

 

4. Create a new App Script file in Google Drive

JPAlpano_1-1661238878241.png

Rename the file however you want.

Since we want the filename to be based on three (3) columns of our table, we will have to pass those as parameters to our function  ( function name(merchant, checkNo, amount) )

For the example in this post, here is the full script:

 

 

 

 

function renameFile(merchant, checkNo, amount) {
  //Log Request
  console.log(`Received request for ${merchant} with Cheque No ${checkNo} and amount of ${amount}`);

  let folder = DriveApp.getFolderById("Your folder id from Step 3"); 
  let subfolder = folder.getFoldersByName(merchant);
  
   
  if(subfolder.hasNext()) {
    let subfolderObj = subfolder.next();
    let subfolderId = subfolderObj.getId();
    
    // Get the folder id of the subfolder created via the [FILE] column's Image/File Path
    let merchantFolder = DriveApp.getFolderById(subfolderId);
    
    // Get all the files inside the folder
    let files = merchantFolder.getFiles();
    let file;

    // Loop through each file in the folder
    while (files.hasNext()) {
      file = files.next();
      filename = file.getName();
      
      if (filename.includes( checkNo )) {

        // get the file extension of the uplaoded file
        let ext = filename.split(".").pop();

        console.log( filename );
        // Rename the file
        let newName = `${merchant}-Check No ${checkNo}-Php${amount}.${ext}`;
        
        //Rename the file in Google Drive
        file.setName(newName);
        
        let newValue = `/UCR Bank Docs/${merchant}/${newName}`;
        
        return newValue;  // Return the new value to AppSheet
      } 
            
    }  // while files.hasNext()

  } // if subfolder.hasNext()
} // end function renameFile

 

 

 

 

Save the file and run the function at least once to allow appropriate permissions.

 

5. Create a Bot that Monitors Adds and Deletes to [FILE] column of the table, then renames the newly uploaded file in GDrive

Event

Event Type: Data Change - Adds and Updates
Table:  Your AppSheet table
Condition:

 

 

 

AND(
   ISNOTBLANK([FILE]),
   [_THISROW_BEFORE].[FILE]<>[_THISROW_AFTER].[FILE]
)

 

 

 

Process
Step Name: RENAME FILE :: Run a task - Call a script
Table name: Your AppSheet table
Apps script Project:  Search for the project you created in Step 4
Function Name:  the function name in the Apps Script file (renameFile(merchant, checkNo, amount))
Function Parameters:
This is where we will pass values from our columns to the Appscript function.

JPAlpano_2-1661239965882.png

Return value:  Turned on
Specific Type: Text 

JPAlpano_3-1661240050906.png

 

6. Add another step to also update the column values in your [FILE] column to reflect the new filename
Task Name: Update File Path :: Set row values
Set these columns:
[FILE] = [RENAME FILE].[Output]

[RENAME FILE] is the step name you created calling the Appscript function.  You may change this accordingly.   .[Output] allows us to retrieve the returned values of the script and use it in our task step.


7.  TEST and watch the magic happen.

6 9 6,496
9 REPLIES 9


@JPAlpano wrote:

what if the backend users would want to identify the files easily when browsing through them via Google Drive interface?


That's a formula for disaster. Imagine your "backend users" delete something "by mistake".
I actually suggest to leave the data of your AppSheet apps, this includes the worksheet as well as all files used by the app, completely hidden from anyone but the editors of the app.

Now, I appreciate your post, it's awesome that we have people like you doing some coding in order to solve some of the most-hard-coded behaviours of the platform, even if that means that I can not use those solutions since I'm non Google user


@SkrOYC wrote:

Imagine your "backend users" delete something "by mistake".


You are correct.  Which is why these "backend users" only have read only access to the folder where the files are saved.   And they don't have any access to the Google Sheet either, just the files.

This also benefits the app developer when checking the uploaded files, so s/he would know which entry that file is for.

Thank you so much for this Tip @JPAlpano 
Until now I only knew about this cool method from @Suvrutt_Gurjar that affects the file name via the Key_Column.

I have one question: Can we get the original file name and name the uploaded file like that? So if the user uploads the file "MyDocument.pdf", the file in Google Drive will be renamed to "MyDocument.pdf". Is that possible?

BTW:


@JPAlpano wrote:

The default filename saved to Google Drive is
[KEY_COLUMN].[COLUMN_NAME].[RANDOM NUMBERS].[FILE EXTENSION]


It's not [Random Numbers] but [TimeStamp] as mentioned in the documentation.
HoursMinutesSeconds (UTC)

 


@Fabian_Weller wrote:

I have one question: Can we get the original file name and name the uploaded file like that? So if the user uploads the file "MyDocument.pdf", the file in Google Drive will be renamed to "MyDocument.pdf". Is that possible?


Unfortunately, Appscript can only know that Original Name if it ever existed in Google Drive.
The way I observed it, the original file name never reached Google Drive as AppSheet already changed the filename before it even got saved in Google drive.


@Fabian_Weller wrote:

It's not [Random Numbers] but [TimeStamp] as mentioned in the documentation.
HoursMinutesSeconds (UTC)


Got it.  I updated the post.  Thanks.

@JPAlpano ok thank you. It seems as if AppSheet never reads the file name: https://www.googlecloudcommunity.com/gc/Feature-Ideas/Bug-File-type-column-cannot-read-the-selected-...

So the only way to control the file name is to add another column of type text. Thank you for that tip.

I tried to add it to my application but I could not succeed. Is there a sample application?

Updated: 231104. Forgot to specify the folder path in "DriveLink".

I got the example to work with some adjustments and a lot of will force, but I had some more demands so I evolved it to a dynamic folder path / name change.
It then renamed the file when put in the folder specified in my script. I made a drop list refereed to values from a column in another table. So when I selected another value from the list I got the file to be put in another folder but it didn't change name. It only changed name if I chose the specific folder.

I'm a beginner and I'm not really sure what is executed by Apps script and what is executed by Appsheet and there are probably some dead code in my solution and/or could be done in a better way - BUT it's working!?

Step-by-step guide

1. Make two tables in your sheet. I'll call them "Parent" and "Child" in my example.
Sheet name: Family. 

The files will look like this in drive in my example: YYYY-DD-MM, your description of the file.pdf
and in the sheet it will be named YYYY-DD-MM, your description of the file.

Folder path will be /appsheet/data/family/ + whatever you want/files.pdf

Important: Apps script is case sensitive and you need to have unique names for tasks, bots, actions etc.

ParentTypeSettings
ID (Key)TextInitial value:    UNIQUEID()
Name (Label)NameValue from this column will be name your folder
Other column's by choice The documents will be referenced to the posts of this table. through the key & label)

 

ChildType 
Fi!LE#SFile
Image/File folder path:   "/" & [YourFolderName].[Name]
DateDate
Initial value: TODAY()
YourFolderName (Label)RefRef Droplist of the values from Parent table column Name
DescriptionNameYour description of the file
YourFileName (Key)Text
Initial value: CONCATENATE([*Date] & ", " & [Description])
DriveLinkTextConcatenate("https://drive.google.com/drive/folders/",[YourFolderName],"?usp=sharing")
*Date (Viritual Column) ListApp formula: text([Date],"YYYY-MM-DD")

2. In Appsheet. Regenerate column structure on both Parent and child tables. A virtual column will be generated in the Parent table.

Related ChildListRef Table: Child
REF_ROWS("Child", "YourFolderName")

3. Go to the spreadsheet. Menu: Additions -> Apps Script. Click on the Apps script logo. -> +New Project.
To the left in Apps script: Services -> + (Add a service) -> Drive API (I added DriveLabels too. Not sure if needed).

Remove whats in code.gs and copy/paste the code below.

Get the Google Drive folder ID of the folder where files will be saved

You can get this from the folder url in Google Drive
(ie https://drive.google.com/drive/folders/1JAvB0fDTpayABCDEFG7vGBbNVOC1U794)

Change the code with your parameters

Save. Run and grant permission.

 

function renameFile(YourFileName, YourFolderName, DriveLink) {
  
  // Create an object to store the result
  var result = {
    newValue: ''
  };
 console.log(`Received request for ${"YourFileName"} with ${"YourFolderName"} and ${"DriveLink"}`);   

    // Use the constructed folder path to find or create the folder
    let folder = DriveApp.getFolderById("THE ID OF YOUR FOLDER")
    let subfolder = folder.getFolders();

     console.log(`Received request for ${"THE ID OF YOUR FOLDER"}`);

    if (subfolder.hasNext()) {
      let subfolderObj = subfolder.next();
      let subfolderId = subfolderObj.getId();

      // Get the folder id of the subfolder created via the [FILE] column's Image/File Path
      let folder = DriveApp.getFolderById(subfolderId);
     
      // Get all the files inside the folder
      let files = folder.getFiles();
      let file;

      // Loop through each file in the folder
      while (files.hasNext()) {
        file = files.next();
        filename = file.getName();

        if (filename.includes("Fi!LE#S	")) {
          // Get the file extension of the uploaded file
          let ext = filename.split(".").pop();

          // Rename the file
          let newName = `${YourFileName}.${ext}`;

          // Rename the file in Google Drive
          file.setName(newName);
          result.newValue = `/Family/${YourFolderName}${newName}`;

        }
      }

      // Create a JSON response
      var response = ContentService.createTextOutput(JSON.stringify(result));
      response.setMimeType(ContentService.MimeType.JSON);

      return response; // Return the JSON response
    }
  }

 

Important: The script will search for all files in the selected folder including the column name Fi!LE#S. Therefore chose a really unique name for that folder and use another name in Display Name.  You do NOT want to change the script to search for ".pdf" as I accidentally tried... Thank god it was only applied for my test folder!  You will end up with 22 files named "test123.pdf" and then 22 files named "WTF123.pdf" and so on...

4.
In Appsheet. Go to behaviour. +New Action

ONE:
For a record of this table: Child
Do this: Grouped: execute a sequence of actions
Action: TWO
Action THREE

TWO:
For a record of this table: Child
Do this: Data: execute an action on a set of rows
Referenced Table: Child
Referenced Rows: LIST([_THISROW].[YourFileName])
Referenced Action: THREE

THREE:
For a record of this table: Child
Do this: Data: set the values of some columns in this row
Set these columns: Fi!LE#S
New value for column: SWITCH([Fi!LE#S],"Fi!LE#S",[YourFileName],[*Date],[YourFileName],[YourFileName])

Note: I tried with IFS in action three but I only got it to change name in Appsheet and not in the drive. I'm not 100% sure what the SWITCH parameters really means but it made it change name in drive too.

5. Automation -> Task
+New task
Name: renameTask
Enable linking

Call a script
Table name: Child

Apps Script Project: renameFile
Function Name: renameFile(YourFileName, YourFolderName, DriveLink)

Function Parameters:
YourFileName: [YourFileName]
YourFolderName: [YourFolderName].[Name]
DriveLink: [DriveLink]

Enable return value
Value type: String
Specific type: Text

6. Automation Event
+New Event
Name: renameEvent
Enable linking
Event Type: Data change
Adds and updates

Table: Child
Condition: ISNOTBLANK([DriveLink])

Bypass Security Filters? I don't know if it's needed. I checked it and don't dare to uncheck it.

7. Automation -> Bots
+ New bot
Name: renameBot
When this EVENT occurs: renameEvent

Run this PROCESS:
Name: renameProcess
Run a task: renameTask 

+Add step
Name: Change path
Run a data action: ONE

***

If anyone with knowledge want to explain what in my solution is unnecessary and what is double/dead code and have a clean up for the code I'd love to hear it. ๐Ÿ˜ƒ
I have a feeling pro's would look at this like this is somewhat like a bumblebee that doesn't know it can't fly. LOL

ndv
Bronze 1
Bronze 1

@JPAlpano Should the solution work so that the files cannot be downloaded/opened directly from the application? Have I done something wrong?

This solution does not have anything to do as to whether the fole gets opened within the app or not.

 

That is controlled separately by the settings of the filw or url column. 

Top Labels in this Space