/ThinkEmailFomatter/Controllers/TemplateController.cs
C# | 542 lines | 391 code | 66 blank | 85 comment | 76 complexity | f355bb7da45963b20d69c4f98cbb46c3 MD5 | raw file
Possible License(s): BSD-3-Clause
- using System;
- using System.Collections.Generic;
- using System.Data;
- using System.Data.Entity;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
- using ThinkEmailFormatter.Models;
- using ThinkEmailFormatter.Models.Extensions;
- using System.Xml.Linq;
- using System.IO;
- using System.Xml;
- using System.Web.UI;
- using System.Text;
- using ThinkEmailFormatter.Utilities;
- using Microsoft.Practices.EnterpriseLibrary.Common;
- using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
- using Microsoft.Practices.EnterpriseLibrary.Logging;
- using System.Net;
- using Newtonsoft.Json.Linq;
- using ThinkEmailFormatter.ThinkOdata;
- namespace ThinkEmailFormatter.Controllers
- {
- public class TemplateController : BaseController
- {
- #region [ CONSTRUCTOR ]
- public TemplateController(IControllerAggregateService controllerAggregateService)
- : base(controllerAggregateService)
- {
- }
- #endregion
- #region [ ACTIONS ]
- /// <summary>
- /// Return a view with all template(.cshtml) files contained
- /// inside "Views/Template/Templates" folder
- /// </summary>
- /// <returns></returns>
- public ViewResult Index()
- {
- try
- {
- // get all views frmo the file system. Each view corresponds to a template
- var templates = _aggSvc.ViewHelper.GetTemplates();
- // get all template settings from the DB
- List<TemplateSetting> allTemplatesettings = _aggSvc.ThinkHelper.GetAllTemplateSettings();
- List<Template> templatesWithDescr = new List<Template>();
- foreach (var template in templates.ToList())
- {
- Template tmplt = new Template();
- tmplt.Name = template.Name;
- string subject = allTemplatesettings.Where(s => string.Compare(s.Name, template.Name, true) == 0).Select(t => t.Subject).FirstOrDefault();
- tmplt.Description = string.IsNullOrEmpty(subject) ? "(No Subject)" : subject;
- templatesWithDescr.Add(tmplt);
- }
- TemplateContext tc = new TemplateContext()
- {
- Templates = templatesWithDescr,
- EmailContext = new EmailContext(),
- };
- return View(tc);
- }
- catch (Exception ie)
- {
- _aggSvc.Log.Exception(ie);
- return View("Error");
- }
- }
- /// <summary>
- /// Preview the selected template associated with the selected dummy request
- /// Allow power user to visualize the email template in their browser
- /// </summary>
- /// <param name="dummyData"></param>
- /// <returns></returns>
- public ViewResult Preview(string template)
- {
- try
- {
- string templateName = string.Format("Templates/{0}", template);
- bool viewExists = this.ControllerContext.ViewExist(templateName);
- if (viewExists)
- {
- ViewBag.EmailEditorMode = false; // Enable all javascripts and display the email editor at the top
- ViewBag.TemplateName = template;
- ThinkTransactionData dummyDataObject = GetDummyThinkObject("DummyEvent.xml");
- return View(templateName, new EmailContext() { ThinkData = dummyDataObject, AttachmentsRootUrl = _aggSvc.EmailContext.AttachmentsRootUrl });
- }
- else
- return View("Unknown");
- }
- catch (Exception ie)
- {
- _aggSvc.Log.Exception(ie);
- return View("Error");
- }
- }
- /// <summary>
- /// Redirect to the "Settings" view
- /// where all email template's setting can be maintained
- /// </summary>
- /// <param name="emailTemplate"></param>
- /// <returns></returns>
- public ViewResult Settings(string emailTemplate)
- {
- var templateSettings = _aggSvc.ThinkHelper.GetTemplateSettings(emailTemplate);
- var eventTypes = _aggSvc.ThinkHelper.GetEventTypeList();
- var orderClasses = _aggSvc.ThinkHelper.GetOrderClassList();
- ViewData["EventType.Id"] = eventTypes;
- if (templateSettings == null)
- {
- templateSettings = new TemplateSetting()
- {
- Name = emailTemplate,
- DefaultEnabled = true,
- };
- templateSettings.InitiateRequiredComplexTypes();
- ViewData["OrderClass.Id"] = new SelectList(orderClasses, "Id", "Name", string.Empty);
- ViewBag.EventTypeSelected = 0;
- ViewBag.ButtonName = "Create New Settings";
- }
- else
- {
- ViewData["OrderClass.Id"] = new SelectList(orderClasses, "Id", "Name", templateSettings.OrderClass.Id);
- ViewBag.EventTypeSelected = templateSettings.EventType.Id;
- ViewBag.ButtonName = "Update Settings";
- }
- return View(templateSettings);
- }
- /// <summary>
- /// Submit the settings to the DB
- /// </summary>
- /// <param name="emailTemplate"></param>
- /// <returns></returns>
- [HttpPost]
- public ActionResult Settings(TemplateSetting templateSettings)
- {
- try
- {
- templateSettings.DefaultEnabled = false;
- if (string.IsNullOrEmpty(templateSettings.FromEmail))
- templateSettings.FromEmail = string.Empty;
-
- // if flag is false, it means that the selected event type does not
- // support filter options. Therefore, all filters should be deleted
- // if some were defined in a previous settings
- if (!templateSettings.EventType.Flag)
- {
- if (templateSettings.Filters != null && templateSettings.Filters.Any())
- templateSettings.Filters.ForEach(f => f.Description = "delete");
- }
- _aggSvc.ThinkHelper.CommitSettings(templateSettings);
- return RedirectToAction("Settings", new { emailTemplate = templateSettings.Name });
- }
- catch (Exception ie)
- {
- _aggSvc.Log.Exception(ie, "'Template' controller, 'Settings' action on Http-POST");
- return View("Error");
- }
- }
- /// <summary>
- /// Format the email so an HTML response is generated after the THINK email request
- /// The URL pattern that needs to be used is http://<domain>/afr/template/{templateName}
- /// This has been defined within the global.asax file under the "Main" route
- /// </summary>
- /// <param name="templateName"></param>
- /// <returns></returns>
- public ActionResult Format(string templateName)
- {
- // By default, an http status code 204 is sent back to THINK meaning
- // all went well and an email has been successfully sent. This response
- // lets THINK know that it can remove the event from the "event_queue" table
- HttpStatusCodeResult httpStatusCode = new HttpStatusCodeResult(204);
- try
- {
- if (Request.HttpMethod.ToUpper().CompareTo("POST") != 0 || Request.ContentLength == 0)
- {
- throw new InvalidDataException();
- }
- else
- {
- // Convert request to Business Object
- ThinkStreamToObject<ThinkTransactionData> thinkToObject = new ThinkStreamToObject<ThinkTransactionData>(Request.InputStream);
- ThinkTransactionData dataObject = thinkToObject.Convert();
- var matchedTemplate = MatchTemplateSettingsToRequest(dataObject);
- if (matchedTemplate != null)
- {
- string templateNamePath = string.Format("Templates/{0}", matchedTemplate.Name);
- bool viewExists = this.ControllerContext.ViewExist(templateNamePath);
- if (viewExists)
- {
- //Get Customer Number
- int customerId;
- Int32.TryParse(dataObject.td_customer.customer_id, out customerId);
- var customerInfo = _aggSvc.ThinkHelper.GetCustomerInfo(customerId);
- dataObject.td_customer.Username = customerInfo.Username;
- // Send email
- try
- {
- _aggSvc.EmailContext.FromEmail = matchedTemplate.FromEmail;
- _aggSvc.EmailContext.Subject = matchedTemplate.Subject;
- _aggSvc.EmailContext.Recipients = dataObject.td_email_recipient;
- _aggSvc.EmailContext.EmailHtmlBody = _aggSvc.ViewHelper.RenderViewToString(this.ControllerContext, templateNamePath, new EmailContext() { ThinkData = dataObject, AttachmentsRootUrl = _aggSvc.EmailContext.AttachmentsRootUrl });
- _aggSvc.EmailContext.HtmlSend();
- _aggSvc.Log.Information("Email sent:" + Environment.NewLine +
- " - Customer Id: " + dataObject.td_customer.customer_id + Environment.NewLine +
- " - email: " + dataObject.td_email_recipient + Environment.NewLine +
- " - transaction event: " + dataObject.transaction_event_descr);
- }
- catch (Exception ie)
- {
- // Internal server error
- httpStatusCode = new HttpStatusCodeResult(500);
- _aggSvc.Log.Exception(ie, "'Template' controller, 'Format' action, in the 'Send email' block of code");
- }
- }
- else
- _aggSvc.Log.Warning(string.Format("Request for email template '{0}' has failed. This template" +
- " has matching settings defined, but no View associated to it. Make sure that a" +
- " '{0}.cshtml' file has been defined in the Views/Template/Templates/ folder.",
- matchedTemplate.Name));
- }
- else
- {
- _aggSvc.Log.Warning(string.Format("Request for email template matching a '{0}' transaction has failed. " +
- "There are no templates that can match the settings defnied in that request.",
- dataObject.transaction_event_descr));
- }
- }
- }
- catch (Exception ie)
- {
- _aggSvc.Log.Exception(ie, "'Template' controller in the 'Format' action");
- }
- return httpStatusCode;
- }
- /// <summary>
- /// Send email
- /// </summary>
- /// <param name="emailContext"></param>
- /// <returns></returns>
- public ActionResult Send(EmailContext emailContext)
- {
- try
- {
- // Copy content into the EmailContext instance that has
- // a valid host configured
- _aggSvc.EmailContext.AbsorbContent(emailContext);
- string templateName = string.Format("Templates/{0}", _aggSvc.EmailContext.TemplateName);
- bool viewExists = this.ControllerContext.ViewExist(templateName);
- if (viewExists)
- {
- ThinkTransactionData dummyDataObject = GetDummyThinkObject("DummyEvent.xml");
- _aggSvc.EmailContext.EmailHtmlBody = _aggSvc.ViewHelper.RenderViewToString(this.ControllerContext, templateName, new EmailContext() { ThinkData = dummyDataObject, AttachmentsRootUrl = _aggSvc.EmailContext.AttachmentsRootUrl });
- _aggSvc.EmailContext.HtmlSend();
- ViewBag.Title = "Email successfully sent";
- return PartialView();
- }
- else
- return PartialView("Unknown");
- }
- catch (Exception ie)
- {
- _aggSvc.Log.Exception(ie);
- return PartialView("Error");
- }
- }
- public ActionResult DeleteTemplate(string emailTemplate)
- {
- try
- {
- string templateName = string.Format("Templates/{0}", emailTemplate);
- bool viewExists = this.ControllerContext.ViewExist(templateName);
- if (viewExists)
- {
- string fileNameWithExt = string.Format("{0}.cshtml", emailTemplate);
- string fileMachinePath = Path.Combine(_aggSvc.HttpContext.Request.MapPath("~/Views/Template/Templates"), fileNameWithExt);
- System.IO.File.Delete(fileMachinePath);
- _aggSvc.ThinkHelper.DeleteTemplateSettings(emailTemplate);
- }
- return RedirectToAction("Index");
- }
- catch (Exception ie)
- {
- _aggSvc.Log.Exception(ie);
- return View("Error");
- }
- }
- public ActionResult DownloadTemplate(string emailTemplate)
- {
- try
- {
- string templateName = string.Format("Templates/{0}", emailTemplate);
- bool viewExists = this.ControllerContext.ViewExist(templateName);
- if (viewExists)
- {
- string fileName = string.Format("{0}.cshtml", emailTemplate);
- return File(_aggSvc.HttpContext.Request.MapPath(string.Format("~/Views/Template/Templates/{0}", fileName)), "text/plain", fileName);
- }
- else
- return RedirectToAction("Index");
- }
- catch (Exception ie)
- {
- _aggSvc.Log.Exception(ie);
- return View("Error");
- }
- }
- /// <summary>
- /// Upload template file to the file system.
- /// That is the second part of a 2 steps process to Upload
- /// a new file to the file system. The first step was the client asynchronous
- /// request(using jQuery) to the "CheckTemplateExists" method
- /// </summary>
- /// <param name="file"></param>
- /// <returns></returns>
- [HttpPost]
- public ActionResult UploadTemplate(HttpPostedFileBase file)
- {
- try
- {
- // Verify that the user selected a file
- if (file != null && file.ContentLength > 0)
- {
- string fileName = Path.GetFileNameWithoutExtension(file.FileName);
- string fileNameWithExt = Path.GetFileName(file.FileName);
- string fileMachinePath = Path.Combine(_aggSvc.HttpContext.Request.MapPath("~/Views/Template/Templates"), fileNameWithExt);
- string templateName = string.Format("Templates/{0}", fileName);
- bool viewExists = this.ControllerContext.ViewExist(templateName);
- if (viewExists)
- System.IO.File.Delete(fileMachinePath);
- file.SaveAs(fileMachinePath);
- }
- // redirect back to the index action to show the form once again
- return RedirectToAction("Index");
- }
- catch (Exception ie)
- {
- _aggSvc.Log.Exception(ie);
- return View("Error");
- }
- }
- /// <summary>
- /// Check if template exists in the file system.
- /// That is the first part of a 2 steps process to Upload
- /// a new file to the file system. This first part is asynchronously
- /// requested from the client using jQuery. Then, depending on the
- /// client response to that first step, the second step(UploadTemplate)
- /// may or may not be requested
- /// </summary>
- /// <param name="fileName"></param>
- /// <returns></returns>
- [HttpPost]
- public JsonResult CheckTemplateExists(string fileName)
- {
- try
- {
- string template = Path.GetFileNameWithoutExtension(fileName);
- string ext = Path.GetExtension(fileName);
- if (ext == ".cshtml")
- {
- string templateName = string.Format("Templates/{0}", template);
- bool viewExists = this.ControllerContext.ViewExist(templateName);
- if (viewExists)
- {
- return Json(new { code = "existingfile", message = "This file already exists." });
- }
- else
- {
- return Json(new { code = "newfile", message = "This file does not exist yet." });
- }
- }
- else
- {
- return Json(new { code = "wrongextension", message = "Your file is not valid. Please, provide a '.cshtml' file." });
- }
- }
- catch (Exception ie)
- {
- _aggSvc.Log.Exception(ie);
- return Json(new { code = "error", message = "An error occured. Please try again." });
- }
- }
- #endregion
- #region [ METHODS ]
- private TemplateSetting MatchTemplateSettingsToRequest(ThinkTransactionData thinkRequest)
- {
- TemplateSetting templateSettings = null;
- // Get the orderCode from the request
- int orderCode = 0;
- int sourceCode = 0;
- int subDef = 0;
- int orderClass = 0;
- if (thinkRequest != null &&
- thinkRequest.td_order != null &&
- thinkRequest.td_order.Any() &&
- thinkRequest.td_order.First().td_item != null &&
- thinkRequest.td_order.First().td_item.Any())
- {
- Int32.TryParse(thinkRequest.td_order.First().td_item.First().order_code_id, out orderCode);
- Int32.TryParse(thinkRequest.td_order.First().td_item.First().source_code_id, out sourceCode);
- Int32.TryParse(thinkRequest.td_order.First().td_item.First().subscription_def_id, out subDef);
- }
- // Get the order class associated to the order code(if the order code has been specified)
- if (orderCode != 0)
- orderClass = _aggSvc.ThinkHelper.GetMatchingOrderClass(orderCode);
- // Get all email settings that matches the request transaction event(e.g. all email settings for "Order Item Added")
- IEnumerable<TemplateSetting> matchingEmailSettings = _aggSvc.ThinkHelper.GetMatchingEmailSettings(thinkRequest);
- if (matchingEmailSettings != null)
- {
- // If an order class has been found, filter all email settings that match that order class
- if (orderClass != 0)
- matchingEmailSettings = matchingEmailSettings.Where(e => e.OrderClass != null && e.OrderClass.Id == orderClass).Select(e => e);
- // Set the default template if none of the following conditions return a result
- templateSettings = matchingEmailSettings.FirstOrDefault();
- // Get email setting that have a active filters
- matchingEmailSettings = matchingEmailSettings.Where(e => e.Filters != null && e.Filters.Any() && e.Filters.Any(f => f.Active)).Select(e => e);
- if (matchingEmailSettings != null && matchingEmailSettings.Any())
- {
- // The filtering priority has been defined by the requirement as follow:
- // 1st priority = source code
- // 2nd priority = subscription definition
- // 3rd priority = order code
- // Ex: if the request specifies OC:1 - SC:2 - SD:3, and there are 2 configs (1,null,3) and (1,2,null), then though both of them matches the request, the prioriry rule
- // will validate (1,2,null) over (1,null,3) for the source code is more important than the subscription def
- matchingEmailSettings = matchingEmailSettings
- .Where(e => e.Filters.Any(f =>
- !((f.OrderCode == null || f.OrderCode.Id == 0) && (f.SourceCode == null || f.SourceCode.Id == 0) && (f.SubscriptionDefinition == null || f.SubscriptionDefinition.Id == 0)) &&
- (f.OrderCode == null || f.OrderCode.Id == 0 || f.OrderCode.Id == orderCode) &&
- (f.SourceCode == null || f.SourceCode.Id == 0 || f.SourceCode.Id == sourceCode) &&
- (f.SubscriptionDefinition == null || f.SubscriptionDefinition.Id == 0 || f.SubscriptionDefinition.Id == subDef) &&
- f.Active))
- .OrderByDescending(e => e.Filters.OrderByDescending(f => f, new FilterComparer()).First(), new FilterComparer())
- .Select(e => e);
- if (matchingEmailSettings != null && matchingEmailSettings.Any())
- templateSettings = matchingEmailSettings.First();
- }
- }
- return templateSettings;
- }
- /// <summary>
- /// Convert a dummy XML file stored in the "DummyData" folder to a "ThinkTransactionData" object
- /// </summary>
- /// <returns></returns>
- private ThinkTransactionData GetDummyThinkObject(string dummyXmlFile)
- {
- string dummyRequest;
- string dummyFilePath = _aggSvc.HttpContext.Request.MapPath(string.Format(@"~/DummyData/{0}", dummyXmlFile));
- using (StreamReader streamReader = new StreamReader(dummyFilePath))
- {
- dummyRequest = streamReader.ReadToEnd();
- }
- XElement xmlRequest = XElement.Parse(dummyRequest);
- // Convert request to Business Object
- ThinkStreamToObject<ThinkTransactionData> thinkToObject = new ThinkStreamToObject<ThinkTransactionData>(xmlRequest);
- ThinkTransactionData dummyData = thinkToObject.Convert();
- if (dummyData != null)
- {
- dummyData.td_customer.Username = "[Username]";
- dummyData.CardType = "[Card Type]";
- dummyData.Last4Digits = "[Last 4 CC Digits]";
- dummyData.RenewDate = "[Renewal date]";
- dummyData.OrderPrice = "[Order Price]";
- dummyData.AddressStreet = "[Street Address]";
- dummyData.AddressUnit = "[Unit Address]";
- dummyData.State = "[State]";
- dummyData.Country = "[Country]";
- dummyData.OrderDescription = "[Order Description]";
- dummyData.FullAddress = "[Address]";
- }
- return dummyData;
- }
- protected override void Dispose(bool disposing)
- {
- base.Dispose(disposing);
- }
- #endregion
- }
- }