public Control GetConfigurationControl(AlteryxGuiToolkit.Document.Properties docProperties, XmlElement eConfig, XmlElement[] eIncomingMetaInfo, int nToolId, string strToolName) { // This method is called by Alteryx to initialize this configuration control from data // stored in the module containing this tool. // Tool configuration is handled through an XML document managed by Alteryx. When it is // time to initialize this control (generally when it is made visible to the user), this // method is called, passing the XML document in with the eConfig parameter. // When this tool is connected to one or more upstream data providers, the structure of // each data stream is passed as an entry in the eIncomingMetaInfo array. This data can // then be used to dynamically construct your UI based on the type of input. // Since this tool is an input tool, the eIncomingMetaInfo parameter will be empty. // We will use the information in eConfig to populate the XmlFile text box. This will // cause the file to be examined if it exists (through the XmlFile_TextChanged event // handler) in order to populate the sample information. We will then use the remaining // information in eConfig to set the field properties if that information exists. // Call LoadFromConfiguration to get the xml file name and field information from eConfig. XmlInputConfiguration xmlConfig = XmlInputConfiguration.LoadFromConfiguration(eConfig); if (xmlConfig != null) { // Update the XmlFile and ElementName textboxes. txtUserName.Text = xmlConfig.UserName; txtPassword.Text = xmlConfig.Password; cboFolderToSearch.SelectedValue = xmlConfig.Folder; txtAttachmentPath.Text = xmlConfig.AttachmentPath; txtQueryString.Text = xmlConfig.QueryString; foreach (XmlInputField field in xmlConfig.Fields) { // Use a little LINQ to find the row in the field list that // corresponds to the current field. var item = clbFields.Items.Cast <KeyValuePair <string, string> >().Where(x => x.Value == field.Name).FirstOrDefault(); if (clbFields.Items.IndexOf(item) != -1) { clbFields.SetItemChecked(clbFields.Items.IndexOf(item), true); } } } return(this); }
// Creates a new instance of the XmlInputConfiguration class based on the information // in the eConfig xml element. This is the eConfig that Alteryx provides in the // IPluginConfiguration.GetConfigurationControl() method. public static XmlInputConfiguration LoadFromConfiguration(XmlElement eConfig) { // Get the configuration values from the XML config elements to be place in their corresponding fields in the UI. XmlElement userName = eConfig.SelectSingleNode("UserName") as XmlElement; XmlElement password = eConfig.SelectSingleNode("Password") as XmlElement; XmlElement folder = eConfig.SelectSingleNode("Folder") as XmlElement; XmlElement attachmentPath = eConfig.SelectSingleNode("AttachmentPath") as XmlElement; XmlElement queryString = eConfig.SelectSingleNode("QueryString") as XmlElement; if (userName != null && password != null) { // Create the new XmlInputConfiguration object. XmlInputConfiguration xmlConfig = new XmlInputConfiguration(userName.InnerText, password.InnerText, Convert.ToInt16(folder.InnerText), attachmentPath.InnerText, queryString.InnerText); // Find all of the Field elements in the configuration. XmlNodeList fields = eConfig.SelectNodes("Fields/Field"); foreach (XmlElement fieldElement in fields) { // For each field element, add a new field to the object with the name, type, size and scale info. string name = fieldElement.GetAttribute("Name"); AlteryxRecordInfoNet.FieldType type = AlteryxRecordInfoNet.FieldType.E_FT_String; Enum.TryParse <AlteryxRecordInfoNet.FieldType>(fieldElement.GetAttribute("Type"), out type); int size = 0; int.TryParse(fieldElement.GetAttribute("Size"), out size); int scale = 0; int.TryParse(fieldElement.GetAttribute("Scale"), out scale); xmlConfig.AddField(name, type, size, scale); } return(xmlConfig); } return(null); }
// Creates a new instance of the XmlInputConfiguration class based on the information // in the eConfig xml element. This is the eConfig that Alteryx provides in the // IPluginConfiguration.GetConfigurationControl() method. public static XmlInputConfiguration LoadFromConfiguration(XmlElement eConfig) { // Get the configuration values from the XML config elements to be place in their corresponding fields in the UI. XmlElement userName = (XmlElement)eConfig.SelectSingleNode("UserName"); XmlElement password = (XmlElement)eConfig.SelectSingleNode("Password"); XmlElement exchangeVersion = (XmlElement)eConfig.SelectSingleNode("ExchangeVersion"); XmlElement useManualServiceURL = (XmlElement)eConfig.SelectSingleNode("UseManualServiceURL"); XmlElement serviceURL = (XmlElement)eConfig.SelectSingleNode("ServiceURL"); XmlElement useDifferentMailbox = (XmlElement)eConfig.SelectSingleNode("UseDifferentMailbox"); XmlElement mailbox = (XmlElement)eConfig.SelectSingleNode("Mailbox"); XmlElement folder = (XmlElement)eConfig.SelectSingleNode("Folder"); XmlElement includeRecurringEvents = (XmlElement)eConfig.SelectSingleNode("IncludeRecurringEvents"); XmlElement startDate = (XmlElement)eConfig.SelectSingleNode("StartDate"); XmlElement endDate = (XmlElement)eConfig.SelectSingleNode("EndDate"); XmlElement attachmentPath = (XmlElement)eConfig.SelectSingleNode("AttachmentPath"); XmlElement queryString = (XmlElement)eConfig.SelectSingleNode("QueryString"); XmlElement includeSubFolders = (XmlElement)eConfig.SelectSingleNode("IncludeSubFolders"); XmlElement subFolderName = (XmlElement)eConfig.SelectSingleNode("SubFolderName"); XmlElement skipRootFolder = (XmlElement)eConfig.SelectSingleNode("SkipRootFolder"); XmlElement useUniqueFileName = (XmlElement)eConfig.SelectSingleNode("UseUniqueFileName"); XmlElement attachmentFilter = (XmlElement)eConfig.SelectSingleNode("AttachmentFilter"); if (userName != null && password != null) { // Create the new XmlInputConfiguration object. XmlInputConfiguration xmlConfig = new XmlInputConfiguration(userName.InnerString(), password.InnerString(), exchangeVersion.InnerInt <ExchangeVersion>(), useManualServiceURL.InnerBoolean(), serviceURL.InnerString(), useDifferentMailbox.InnerBoolean(), mailbox.InnerString(), folder.InnerInt <WellKnownFolderName>(), includeRecurringEvents.InnerBoolean(), startDate.InnerDateTime(), endDate.InnerDateTime(), attachmentPath.InnerString(), queryString.InnerString(), includeSubFolders.InnerBoolean(), subFolderName.InnerString(), skipRootFolder.InnerBoolean(), useUniqueFileName.InnerBoolean(), attachmentFilter.InnerString()); // Find all of the Field elements in the configuration. XmlNodeList fields = eConfig.SelectNodes("Fields/Field"); foreach (XmlElement fieldElement in fields) { // For each field element, add a new field to the object with the name, type, size and scale info. string name = fieldElement.GetAttribute("Name"); AlteryxRecordInfoNet.FieldType type = AlteryxRecordInfoNet.FieldType.E_FT_String; Enum.TryParse <AlteryxRecordInfoNet.FieldType>(fieldElement.GetAttribute("Type"), out type); int size = 0; int.TryParse(fieldElement.GetAttribute("Size"), out size); int scale = 0; int.TryParse(fieldElement.GetAttribute("Scale"), out scale); xmlConfig.AddField(name, type, size, scale); } return(xmlConfig); } return(null); }
// Called by Alteryx for an Input tool to request all of the records. public bool PI_PushAllRecords(long nRecordLimit) { // The nRecordLimit parameter specifies the maximum number of records that // should be provided, or -1 for unlimited. If it is -1, set it to // long.MaxValue to make the processing easier later on. Sometimes Alteryx // will call this function with a record limit of 0 just to get the output // record configuration. if (nRecordLimit < 0) { nRecordLimit = long.MaxValue; } m_engineInterface.OutputMessage(m_nToolId, AlteryxRecordInfoNet.MessageStatus.STATUS_Info, nRecordLimit.ToString()); if (m_engineInterface.GetInitVar("UpdateOnly") == "True") { m_engineInterface.OutputMessage(m_nToolId, AlteryxRecordInfoNet.MessageStatus.STATUS_Complete, nRecordLimit.ToString()); } else { // Get the configuration section out of the properties xml that was passed // into PI_Init() and use it to determine the xml file, container element, // and field configuration for our tool. XmlElement configXml = m_xmlProperties.SelectSingleNode("Configuration") as XmlElement; XmlInputConfiguration xmlConfig = XmlInputConfiguration.LoadFromConfiguration(configXml); if (xmlConfig == null) { throw new ApplicationException("Invalid configuration. Ensure that the input file is set correctly."); } if (xmlConfig.Fields.Count == 0) { throw new ApplicationException("There are no fields. Make sure your container element is set properly."); } // Create a new RecordInfo object to describe our outgoing message records and // configure it based on the field information in our saved configuration. AlteryxRecordInfoNet.RecordInfo recordInfoOut = new AlteryxRecordInfoNet.RecordInfo(); foreach (XmlInputField field in xmlConfig.Fields) { // For each field in our configuration, add it to our RecordInfo object. recordInfoOut.AddField(field.Name, field.FieldType, field.Size, field.Scale, "", ""); } // Use the new RecordInfo object to initialize the PluginOutputConnectionHelper. // The PluginOutputConnectionHelper can't be used until this step is performed. m_outputHelper.Init(recordInfoOut, "Message Output", null, m_xmlProperties); // Create a Record object to hold the data for each outgoing message record. AlteryxRecordInfoNet.Record recordOut = recordInfoOut.CreateRecord(); // Create a new RecordInfo object to describe our outgoing attachment records and // configure it based on the field information in our saved configuration. AlteryxRecordInfoNet.RecordInfo recordInfoOut_AttachmentPaths = new AlteryxRecordInfoNet.RecordInfo(); // For each field in our configuration, add it to our RecordInfo object. recordInfoOut_AttachmentPaths.AddField("Id", AlteryxRecordInfoNet.FieldType.E_FT_String, 4000, 0, "", ""); recordInfoOut_AttachmentPaths.AddField("AttachmentPath", AlteryxRecordInfoNet.FieldType.E_FT_String, 4000, 0, "", ""); // Use the new RecordInfo object to initialize the PluginOutputConnectionHelper. // The PluginOutputConnectionHelper can't be used until this step is performed. m_attachmentOutputHelper.Init(recordInfoOut_AttachmentPaths, "Attachment Output", null, m_xmlProperties); // Create a Record object to hold the data for each outgoing attachment record. AlteryxRecordInfoNet.Record recordOut_AttachmentPaths = recordInfoOut_AttachmentPaths.CreateRecord(); // Define the necessary PropertyDefinitionBase objects for each field in the XML configuration document. PropertyDefinitionBase[] propertyDefinitionBase = new PropertyDefinitionBase[xmlConfig.Fields.Count]; for (int i = 0; i < xmlConfig.Fields.Count; i++) { if ((WellKnownFolderName)xmlConfig.Folder == WellKnownFolderName.Calendar && typeof(AppointmentSchema).GetField(xmlConfig.Fields[i].Name) != null) { propertyDefinitionBase[i] = (PropertyDefinitionBase)typeof(AppointmentSchema).GetField(xmlConfig.Fields[i].Name).GetValue(null); } else if ((WellKnownFolderName)xmlConfig.Folder == WellKnownFolderName.Inbox && typeof(EmailMessageSchema).GetField(xmlConfig.Fields[i].Name) != null) { propertyDefinitionBase[i] = (PropertyDefinitionBase)typeof(EmailMessageSchema).GetField(xmlConfig.Fields[i].Name).GetValue(null); } else if ((WellKnownFolderName)xmlConfig.Folder == WellKnownFolderName.Tasks && typeof(TaskSchema).GetField(xmlConfig.Fields[i].Name) != null) { propertyDefinitionBase[i] = (PropertyDefinitionBase)typeof(TaskSchema).GetField(xmlConfig.Fields[i].Name).GetValue(null); } else { propertyDefinitionBase[i] = (PropertyDefinitionBase)typeof(ItemSchema).GetField(xmlConfig.Fields[i].Name).GetValue(null); } } // Assign the configuration settings and field list to the OutlookEmail object. OutlookEmail email = new OutlookEmail() { UserName = xmlConfig.UserName, Password = xmlConfig.Password, ExchangeServerVersion = xmlConfig.ExchangeVersion, UseManualServiceURL = xmlConfig.UseManualServiceURL, ServiceURL = xmlConfig.ServiceURL, UseDifferentMailbox = xmlConfig.UseDifferentMailbox, Mailbox = xmlConfig.Mailbox, Folder = (WellKnownFolderName)xmlConfig.Folder, IncludeRecurringEvents = xmlConfig.IncludeRecurringEvents, StartDate = xmlConfig.StartDate, EndDate = xmlConfig.EndDate, AttachmentPath = xmlConfig.AttachmentPath, QueryString = xmlConfig.QueryString, IncludeSubFolders = xmlConfig.IncludeSubFolders, SubFolderName = xmlConfig.SubFolderName, SkipRootFolder = xmlConfig.SkipRootFolder, UseUniqueFileName = xmlConfig.UseUniqueFileName, AttachmentFilter = xmlConfig.AttachmentFilter }; email.Fields = new PropertySet(propertyDefinitionBase); // Get the list of items (this includes attachments if the Attachment field was selected for output). List <OItem> oItems = email.GetItems(nRecordLimit); // We will need to send status updates to Alteryx at regular intervals during // this process, so we'll do that based on an elapsed time. DateTime last = DateTime.Now; // We need to keep track of how many records we have processed. long nRecords = 0; // Process the data in each message object. foreach (var oItem in oItems) { // If we've exceeded the record limit, stop processing. if (nRecords >= nRecordLimit) { break; } // Reset our output record so we can reuse it. This is better than // creating a new Record in each iteration as these objects can get large. recordOut.Reset(); // For each field, load the data from the corresponding element into the Record. foreach (XmlInputField field in xmlConfig.Fields) { // Get the FieldBase from the RecordInfo for the field. AlteryxRecordInfoNet.FieldBase fieldBase = recordInfoOut.GetFieldByName(field.Name, false); if (fieldBase != null) { // Find the element within the container element that has the same name as the field. var value = Convert.ToString(oItem.Item.GetType().GetProperty(field.Name).GetValue(oItem.Item, null)); if (value == null) { // If the field element doesn't exist, set the output field's value to null. fieldBase.SetNull(recordOut); } else { // Otherwise, set the output field's value based on the element's inner text. fieldBase.SetFromString(recordOut, value); } } } // Return message attachments if applicable. if (!string.IsNullOrWhiteSpace(xmlConfig.AttachmentPath)) { foreach (var attachment in oItem.Attachments) { // Reset our output record so we can reuse it. This is better than // creating a new Record in each iteration as these objects can get large. recordOut_AttachmentPaths.Reset(); // Get the FieldBase from the RecordInfo for the ID field. AlteryxRecordInfoNet.FieldBase fieldBase_ID = recordInfoOut_AttachmentPaths.GetFieldByName("ID", false); if (fieldBase_ID != null) { fieldBase_ID.SetFromString(recordOut_AttachmentPaths, oItem.Item.Id.ToString()); } // Get the FieldBase from the RecordInfo for the AttachmentPath field. AlteryxRecordInfoNet.FieldBase fieldBase_AttachmentPath = recordInfoOut_AttachmentPaths.GetFieldByName("AttachmentPath", false); if (fieldBase_AttachmentPath != null) { fieldBase_AttachmentPath.SetFromString(recordOut_AttachmentPaths, attachment.AttachmentPath); } // Send the record to the downstream tools through the PluginOutputConnectionHelper. m_attachmentOutputHelper.PushRecord(recordOut_AttachmentPaths.GetRecord()); } } // Send the record to the downstream tools through the PluginOutputConnectionHelper. m_outputHelper.PushRecord(recordOut.GetRecord()); // If at least 1 second has passed since we started or our last update, update progress. if (DateTime.Now.Subtract(last).TotalSeconds >= 1) { // Determine the percent complete: (Records Processed) / Min(RecordLimit, # of Container Elements) double percentComplete = (double)nRecords / Math.Min(nRecordLimit, oItems.Count); // Output the progress if (m_engineInterface.OutputToolProgress(m_nToolId, percentComplete) != 0) { // If this returns anything but 0, then the user has canceled the operation. throw new AlteryxRecordInfoNet.UserCanceledException(); } // Have the PluginOutputConnectionHelper ask the downstream tools to update their progress. m_outputHelper.UpdateProgress(percentComplete); // Reset the timer. last = DateTime.Now; } // Have the PluginOutputConnectionHelper update the record count display in Alteryx. // The PluginOutputConnectionHelper will actually only do this if enough time and data has elapsed, // so it's ok to call this in every iteration. m_outputHelper.OutputRecordCount(false); // Update our record count. nRecords++; } // If we weren't just getting the output config, send a status message to Alterys that // will display the number of records that we output. if (nRecordLimit > 0) { m_engineInterface.OutputMessage(m_nToolId, AlteryxRecordInfoNet.MessageStatus.STATUS_Info, nRecords.ToString() + " records read from " + xmlConfig.UserName); } // Tell Alteryx that we are done sending data so that it can close the connections to our plugin. m_engineInterface.OutputMessage(m_nToolId, AlteryxRecordInfoNet.MessageStatus.STATUS_Complete, ""); } // Close our ouput connections. m_outputHelper.Close(); m_attachmentOutputHelper.Close(); // Return true to indicate that we successfully processed our data. return(true); }