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.
Friday, June 22. 2018
LDC #90: Emailing Collaboration Tasks
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
Quicksearch
Categories
Calendar
November '24 | ||||||
---|---|---|---|---|---|---|
Mo | Tu | We | Th | Fr | Sa | Su |
Tuesday, November 19. 2024 | ||||||
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 |