• Solutions
    • FERC XBRL Reporting
    • FDTA Financial Reporting
    • SEC Compliance
    • Windows Clipboard Management
    • Legato Scripting
  • Products
    • GoFiler Suite
    • XBRLworks
    • SEC Exhibit Explorer
    • SEC Extractor
    • Clipboard Scout
    • Legato
  • Education
    • Training
    • SEC and EDGAR Compliance
    • Legato Developers
  • Blog
  • Support
  • Skip to blog entries
  • Skip to archive page
  • Skip to right sidebar

Friday, June 22. 2018

LDC #90: Emailing Collaboration Tasks

If you’re a long time reader of the developers corner, you may remember that last April I talked about using collaboration tasks in GoFiler through Legato. I shared a short script that read any tasks attached to a project upon opening a project and had Legato post the tasks in the Information View. Today I would like to present a modification to the script while introducing the email function. This script will also require a basic understanding of how HTML is formed and how CSS style data is stored in HTML.


GoFiler has the ability to send SMTP email if you have your GoFiler application preferences set up with an SMTP account. The function to do so is EmailSendMessage(). You have to give the function three strings: a ‘to’ address, a subject, and a body. The body can be just a string, but you can also send formatted HTML using the Legato HTML writer.


Let’s take a look at the script:


 


//
//
//      GoFiler Legato Script - Send an email of tasks on a project
//      -----------------------------------------------------------
//
//      Rev     06/22/2018
//
//      (c) 2018 Novaworks, LLC -- All rights reserved.
//
//      Place this into the Scripts folder of the application. GoFiler must be
//      restarted to have the menu functions added.
//
//      Notes:
//
//         -    Requires GoFiler 4.21c or later.

#define                 EMAIL_NAME                      "test@test.com"

    void                main                            ();
    int                 email_tasks                     (int f_id, string mode);
    void                set_styles                      ();

    string              css_head_1[10];                                 // Table Header
    string              css_head_2[10];                                 // Table Header
    string              css_row[10];                                    // Table Row

void setup() {

      MenuSetHook("FILE_CLOSE", GetScriptFilename(), "email_tasks");    
      set_styles();      
}      
                                                                        
void main() {                                                           
                                                                        
    setup();
    }
    
int email_tasks(int f_id, string mode) {

  if (mode != "preprocess") {
    return ERROR_NONE;
    }

    handle              edit_window;                            /* edit window handle                   */
    handle              log_window;                             /* IV                                   */
    handle              hMaster, hExt, hSegment;                // Master HTML and Extension for Email
    string              s1, s2, s3;                             // General
    dword               file_type;
    string              tasksloc[];
    string              taskprop[];
    int                 ix;
    int                 taskscount;
    int                 rc;

  edit_window = GetEditWindowHandle();                          /* get handle to edit window            */
  file_type = GetEditWindowType(edit_window);                   /* get filename of opened project       */
  if (file_type == 0) {                                         /* if failed to open                    */
    AddMessage("Failed to read opened file");
    }
  if ((file_type & EDX_TYPE_ID_MASK) != EDX_TYPE_EDGAR_VIEW) {  
    AddMessage("Not a project: %0x", file_type);
    return ERROR_NONE;
    }
  
  tasksloc = GetTaskIDs(CM_LOCATION_PROJECT);                   /* Get the ID of the tasks              */
  taskscount = GetTaskCount(CM_LOCATION_PROJECT);               /* Get the number of the tasks          */
  
  if (taskscount > 0) {
    hMaster = HTMLCreateWriterObject();
    HTMLAddHead(hMaster, "Project Tasks", "Sans-Serif", "9pt");
    HTMLSetTableStyle(hMaster, css_head_1);
    HTMLAddText(hMaster, FormatString("Number of Tasks: %d", taskscount));
    HTMLTableOpen(hMaster, "7.5in");
    
    HTMLSetTableStyle(hMaster, "font-family: Sans-Serif; font-size: 9pt");
    HTMLSetCellStyle(hMaster); 
    HTMLSetCellStyle(hMaster, css_head_2);
    HTMLRowOpen(hMaster);
    HTMLAddCell(hMaster, "Subject");
    HTMLAddCell(hMaster, "Status");
    HTMLAddCell(hMaster, "Description");
    HTMLAddCell(hMaster, "Percent Complete");
    HTMLAddCell(hMaster, "Date Due");
    HTMLAddCell(hMaster, "Notes");
    HTMLRowClose(hMaster);

    ix = 0;
    while (ix < taskscount) {
      taskprop = GetTaskProperties(tasksloc[ix]);
      HTMLSetTableStyle(hMaster, "font-family: Sans-Serif; font-size: 9pt");
      HTMLSetCellStyle(hMaster); 
      HTMLSetCellStyle(hMaster, css_row);
      HTMLRowOpen(hMaster);
      HTMLAddCell(hMaster, taskprop["Subject"]);
      HTMLAddCell(hMaster, taskprop["Status"]);
      HTMLAddCell(hMaster, taskprop["Description"]);
      HTMLAddCell(hMaster, taskprop["PercentComplete"]);
      HTMLAddCell(hMaster, taskprop["DateDue"]);
      HTMLAddCell(hMaster, taskprop["Notes"]);
      HTMLRowClose(hMaster);
      ix++;
      }
    HTMLAddFoot(hMaster);

    s1 = "Project Tasks";
    s2 = HTMLWriterToString(hMaster);
    s3 = EMAIL_NAME;
    EmailSendMessage(s3, s1, s2);
    CloseHandle(hMaster);
    
    return ERROR_NONE;
    }
  return ERROR_NONE;
}

void set_styles() {                                                     // Set Up Styles
                                                                        //////////////////////////////////////////

    css_head_1["color"] = "#F0F0F0";
    css_head_1["font-size"] = "140%";
    css_head_1["font-weight"] = "bold";
    css_head_1["background-color"] = "black";
    css_head_1["text-align"] = "center";
    css_head_1["border-bottom-color"] = "#808080";
    css_head_1["border-bottom-width"] = "1pt";
    css_head_1["border-bottom-style"] = "solid";

    css_head_2["color"] = "#F0F0F0";
    css_head_2["font-size"] = "90%";
    css_head_2["font-weight"] = "bold";
    css_head_2["background-color"] = "black";

    css_row["text-align"] = "left";
    css_row["border-bottom-color"] = "#808080";
    css_row["border-bottom-width"] = "1pt";
    css_row["border-bottom-style"] = "solid";
    }

Well that seems complicated, but we’re going to break it down to show that this is actually pretty simple. Let’s start at the top, with the declarations of global variables.


#define                 EMAIL_NAME                      "test@test.com"

    void                main                            ();
    int                 email_tasks                     (int f_id, string mode);
    void                set_styles                      ();

    string              css_head_1[10];                                 // Table Header
    string              css_head_2[10];                                 // Table Header
    string              css_row[10];                                    // Table Row

Here we’ve got three functions: main, email_tasks, and set_styles. We’ve got three string arrays that we will use for CSS storage: head_1, head_2, and row. Finally there is a define that sets where the email will be sent. If you are going to run this script, you will need to change this to an email that will receive email, otherwise the email will be sent to a location you (more than likely) don’t have access to.


void setup() {

      MenuSetHook("FILE_CLOSE", GetScriptFilename(), "email_tasks");    
      set_styles();      
}      
                                                                        
void main() {                                                           
                                                                        
    setup();
    }

Our main function runs setup, which sets our hook to closing a file. In order for the script to work, the script will have to be saved before the hook will function properly.


int email_tasks(int f_id, string mode) {

  if (mode != "preprocess") {
    return ERROR_NONE;
    }

    handle              edit_window;                            /* edit window handle                   */
    handle              log_window;                             /* IV                                   */
    handle              hMaster, hExt, hSegment;                // Master HTML and Extension for Email
    string              s1, s2, s3;                             // General
    dword               file_type;
    string              tasksloc[];
    string              taskprop[];
    int                 ix;
    int                 taskscount;
    int                 rc;

  edit_window = GetEditWindowHandle();                          /* get handle to edit window            */
  file_type = GetEditWindowType(edit_window);                   /* get filename of opened project       */
  if (file_type == 0) {                                         /* if failed to open                    */
    AddMessage("Failed to read opened file");
    }
  if ((file_type & EDX_TYPE_ID_MASK) != EDX_TYPE_EDGAR_VIEW) {  
    AddMessage("Not a project: %0x", file_type);
    return ERROR_NONE;
    }

The first thing we do is to check to see if our hook is being run preprocess. While it would be better if we could run this afterwards (in case the close is cancelled for some reason), we don’t have an easy way to get the project tasks if the project is no longer open. We then get the current active edit window and the type of the opened window. If this filetype is not an EDGAR project, we return out of the hook. This means that only EDGAR projects will have tasks emailed.


  tasksloc = GetTaskIDs(CM_LOCATION_PROJECT);                   /* Get the ID of the tasks              */
  taskscount = GetTaskCount(CM_LOCATION_PROJECT);               /* Get the number of the tasks          */
  
  if (taskscount > 0) {
    hMaster = HTMLCreateWriterObject();
    HTMLAddHead(hMaster, "Project Tasks", "Sans-Serif", "9pt");
    HTMLSetTableStyle(hMaster, css_head_1);
    HTMLAddText(hMaster, FormatString("Number of Tasks: %d", taskscount));
    HTMLTableOpen(hMaster, "7.5in");
    
    HTMLSetTableStyle(hMaster, "font-family: Sans-Serif; font-size: 9pt");
    HTMLSetCellStyle(hMaster); 
    HTMLSetCellStyle(hMaster, css_head_2);
    HTMLRowOpen(hMaster);
    HTMLAddCell(hMaster, "Subject");
    HTMLAddCell(hMaster, "Status");
    HTMLAddCell(hMaster, "Description");
    HTMLAddCell(hMaster, "Percent Complete");
    HTMLAddCell(hMaster, "Date Due");
    HTMLAddCell(hMaster, "Notes");
    HTMLRowClose(hMaster);

Once we determine that the currently open project is an EDGAR project, we get the tasks that are attached to the project as project tasks. If the number of tasks is greater than zero, we create an HTML writer object, and we create the beginning of our tasks table. We add an HTML head object for a title, and then we create a header line that has the number of tasks in the project. We then create a table and make the first line be the information headers for what we are going to take from the task itself.


    ix = 0;
    while (ix < taskscount) {
      taskprop = GetTaskProperties(tasksloc[ix]);
      HTMLSetTableStyle(hMaster, "font-family: Sans-Serif; font-size: 9pt");
      HTMLSetCellStyle(hMaster, css_row);
      HTMLRowOpen(hMaster);
      HTMLAddCell(hMaster, taskprop["Subject"]);
      HTMLAddCell(hMaster, taskprop["Status"]);
      HTMLAddCell(hMaster, taskprop["Description"]);
      HTMLAddCell(hMaster, taskprop["PercentComplete"]);
      HTMLAddCell(hMaster, taskprop["DateDue"]);
      HTMLAddCell(hMaster, taskprop["Notes"]);
      HTMLRowClose(hMaster);
      ix++;
      }
    HTMLTableClose(hMaster);
    HTMLAddFoot(hMaster);

Next we start a counter to go through the tasks that we have. For each task, we get the properties of the task and then add them to our HTML writer in cells of a new row. After we have gone through all of the tasks in the project we close the table and add a footer to the HTML file that we’re writing.


    s1 = "Project Tasks";
    s2 = HTMLWriterToString(hMaster);
    s3 = EMAIL_NAME;
    EmailSendMessage(s3, s1, s2);
    CloseHandle(hMaster);
    
    return ERROR_NONE;
    }
  return ERROR_NONE;
}

Finally we give the email a subject, write our HTML to a string, set where we’re sending the email, and then finally send the email! Finally we close the HTML writer object and return successfully.


The last thing to talk about is that function at the bottom:


void set_styles() {                                                     // Set Up Styles
                                                                        //////////////////////////////////////////

    css_head_1["color"] = "#F0F0F0";
    css_head_1["font-size"] = "140%";
    css_head_1["font-weight"] = "bold";
    css_head_1["background-color"] = "black";
    css_head_1["text-align"] = "center";
    css_head_1["border-bottom-color"] = "#808080";
    css_head_1["border-bottom-width"] = "1pt";
    css_head_1["border-bottom-style"] = "solid";

    css_head_2["color"] = "#F0F0F0";
    css_head_2["font-size"] = "90%";
    css_head_2["font-weight"] = "bold";
    css_head_2["background-color"] = "black";

    css_row["text-align"] = "left";
    css_row["border-bottom-color"] = "#808080";
    css_row["border-bottom-width"] = "1pt";
    css_row["border-bottom-style"] = "solid";
    }

This function sets up the global styles that we use in our HTML writer. This gets run when we initially set up the script, which means it gets run when you run the script through the IDE or when GoFiler starts if it’s put in your scripts folder. We use these arrays for CSS styles that are passed at different points to the HTML writer.


There is one big issue that needs to be discussed with this script. The FILE_CLOSE function only runs if you use the right click menu or the close button on the File ribbon. If you click the ‘X’ in the top right-hand corner of the IDE FILE_CLOSE will not run. This means there’s no foolproof way of guaranteeing that our script gets run every single time that a project gets closed. So this script is an example of a script that would potentially require additional training of a user to make sure that the script does its job properly.


So today we discussed getting project tasks and automatically creating and sending an email to someone with the tasks in it. While seemingly long and wordy, it’s constructed this way to give you the power to create HTML through Legato and make it look however you would like. It takes a few more lines to create than just adding information to strings, but in the end gives us a formatted table in email sent directly to you (or a manager). And this is just the baseline of what you can do! You can easily extend or modify this script in any way you’d like to make it show just the information that you want and in the exact format that you want.


 


Joshua Kwiatkowski is a developer at Novaworks, primarily working on Novaworks’ cloud-based solution, GoFiler Online. He is a graduate of the Rochester Institute of Technology with a Bachelor of Science degree in Game Design and Development. He has been with the company since 2013.

Additional Resources

Novaworks’ Legato Resources

Legato Script Developers LinkedIn Group

Primer: An Introduction to Legato 

Posted by
Joshua Kwiatkowski
in Development at 12:58
Trackbacks
Trackback specific URI for this entry

No Trackbacks

Comments
Display comments as (Linear | Threaded)
No comments
Add Comment
Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.
E-Mail addresses will not be displayed and will only be used for E-Mail notifications.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

 
   
 

Quicksearch

Categories

  • XML Accounting
  • XML AICPA News
  • XML FASB News
  • XML GASB News
  • XML IASB News
  • XML Development
  • XML Events
  • XML FERC
  • XML eForms News
  • XML FERC Filing Help
  • XML Filing Technology
  • XML Information Technology
  • XML Investor Education
  • XML MSRB
  • XML EMMA News
  • XML FDTA
  • XML MSRB Filing Help
  • XML Novaworks News
  • XML GoFiler Online Updates
  • XML GoFiler Updates
  • XML XBRLworks Updates
  • XML SEC
  • XML Corporation Finance
  • XML DERA
  • XML EDGAR News
  • XML Investment Management
  • XML SEC Filing Help
  • XML XBRL
  • XML Data Quality Committee
  • XML GRIP Taxonomy
  • XML IFRS Taxonomy
  • XML US GAAP Taxonomy

Calendar

Back May '25 Forward
Mo Tu We Th Fr Sa Su
Sunday, May 18. 2025
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Feeds

  • XML
Sign Up Now
Get SEC news articles and blog posts delivered monthly to your inbox!
Based on the s9y Bulletproof template framework

Compliance

  • FERC
  • EDGAR
  • EMMA

Software

  • GoFiler Suite
  • SEC Exhibit Explorer
  • SEC Extractor
  • XBRLworks
  • Legato Scripting

Company

  • About Novaworks
  • News
  • Site Map
  • Support

Follow Us:

  • LinkedIn
  • YouTube
  • RSS
  • Newsletter
  • © 2024 Novaworks, LLC
  • Privacy
  • Terms of Use
  • Trademarks and Patents
  • Contact Us