using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net.Mail;
using System.IO;
using System.Threading;
using newtelligence.DasBlog.Runtime;
using newtelligence.DasBlog.Util;
using System.Collections;
using newtelligence.DasBlog.Web.Core;
namespace newtelligence.DasBlog.Web.Services{
/// <summary>
/// This is the handler class for the Daily Report email functionality.
/// </summary>
public class ReportMailer
{
string configPath;
string contentPath;
string logPath;
public ReportMailer(string configPath, string contentPath, string logPath)
{
this.configPath = configPath;
this.contentPath = contentPath;
this.logPath = logPath;
}
/// <summary>
/// Report-Mailer runs in background thread and this is the thread function.
/// </summary>
public void Run()
{
IBlogDataService dataService = null;
ILoggingDataService loggingService = null;
DateTime lastReportDateUTC = DateTime.Now.ToUniversalTime();
SiteConfig siteConfig = SiteConfig.GetSiteConfig( configPath );
loggingService = LoggingDataServiceFactory.GetService(logPath);
dataService = BlogDataServiceFactory.GetService(contentPath, loggingService );
ErrorTrace.Trace(System.Diagnostics.TraceLevel.Info,"ReportMailer thread spinning up");
loggingService.AddEvent( new EventDataItem( EventCodes.ReportMailerServiceStart,"",""));
do
{
try
{
// reload on every cycle to get the current settings
siteConfig = SiteConfig.GetSiteConfig( configPath );
loggingService = LoggingDataServiceFactory.GetService(logPath);
dataService = BlogDataServiceFactory.GetService(contentPath, loggingService);
if (siteConfig.EnableDailyReportEmail)
{
if (siteConfig.SmtpServer != null && siteConfig.SmtpServer.Length > 0 &&
lastReportDateUTC.Day != DateTime.Now.ToUniversalTime().Day )
{
// It's a new day so send the report
SendEmailReport(lastReportDateUTC, siteConfig, dataService, loggingService);
// and update the cached date to today
lastReportDateUTC = DateTime.Now.ToUniversalTime();
}
}
// tick again in an hour
Thread.Sleep( TimeSpan.FromSeconds( 3600 ) );
}
catch( ThreadAbortException abortException )
{
ErrorTrace.Trace(System.Diagnostics.TraceLevel.Info,abortException);
loggingService.AddEvent( new EventDataItem( EventCodes.ReportMailerServiceShutdown,"",""));
break;
}
catch( Exception e )
{
// if the siteConfig can't be read, stay running regardless
// default wait time is 60 minutes in that case
ErrorTrace.Trace(System.Diagnostics.TraceLevel.Error,e);
loggingService.AddEvent(new EventDataItem( EventCodes.ReportMailerServiceError, e.ToString().Replace("\n","<br />"), null, null));
Thread.Sleep( TimeSpan.FromSeconds(3600));
}
}
while ( true );
ErrorTrace.Trace(System.Diagnostics.TraceLevel.Info,"ReportMailer thread terminating");
loggingService.AddEvent( new EventDataItem( EventCodes.ReportMailerServiceShutdown,"",""));
}
public void SendEmailReport(DateTime reportDate, SiteConfig siteConfig, IBlogDataService dataService, ILoggingDataService loggingService)
{
MailMessage emailMessage = new MailMessage();
if ( siteConfig.NotificationEMailAddress != null && siteConfig.NotificationEMailAddress.Length > 0 )
{
emailMessage.To.Add(siteConfig.NotificationEMailAddress);
}
else
{
emailMessage.To.Add(siteConfig.Contact);
}
emailMessage.Subject = String.Format("Weblog Daily Activity Report for '{0}'", reportDate.ToLongDateString());
emailMessage.Body = GenerateReportEmailBody(reportDate);
emailMessage.IsBodyHtml = true;
emailMessage.BodyEncoding = System.Text.Encoding.UTF8;
emailMessage.From = new MailAddress(siteConfig.Contact);
SendMailInfo sendMailInfo = new SendMailInfo(emailMessage, siteConfig.SmtpServer,
siteConfig.EnableSmtpAuthentication, siteConfig.UseSSLForSMTP, siteConfig.SmtpUserName, siteConfig.SmtpPassword, siteConfig.SmtpPort);
dataService.AddTracking(null, sendMailInfo ); // use this with null tracking object, just to get the email sent
loggingService.AddEvent( new EventDataItem( EventCodes.ReportMailerReportSent,"",""));
}
private string GenerateReportEmailBody(DateTime reportDate)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append(GetStyleSheet());
sb.Append("<p><table><tr><td class=\"mainheader\" width=\"100%\">Weblog Daily Email Report (" + reportDate.ToLongDateString() + " UTC)</td></tr></table></p>");
try
{
Hashtable referrerUrls = new Hashtable();
Hashtable userAgents = new Hashtable();
Hashtable searchUrls = new Hashtable();
Hashtable userDomains = new Hashtable();
SiteConfig siteConfig = SiteConfig.GetSiteConfig( configPath );
ILoggingDataService logService = LoggingDataServiceFactory.GetService(logPath);
string siteRoot = siteConfig.Root.ToUpper();
LogDataItemCollection logItems = new LogDataItemCollection();
logItems.AddRange(logService.GetReferralsForDay(reportDate));
foreach (LogDataItem log in logItems)
{
bool exclude = false;
if (log.UrlReferrer != null)
{
exclude = log.UrlReferrer.ToUpper().StartsWith(siteRoot);
// Let Utils.ParseSearchString decide whether it's a search engine referrer.
HyperLink link = SiteUtilities.ParseSearchString(log.UrlReferrer);
if (link != null)
{
string linktext = "<a href=\"" + link.NavigateUrl + "\">" + link.Text + "</a>";
exclude = true;
if (!searchUrls.Contains(linktext))
{
searchUrls[linktext] = 0;
}
searchUrls[linktext] = ((int) searchUrls[linktext]) + 1;
}
}
if (!exclude)
{
string linktext = log.UrlReferrer;
if (linktext.Length > 0)
linktext = "<a href=\"" + log.UrlReferrer + "\">" + log.UrlReferrer + "</a>";
if (!referrerUrls.Contains(linktext))
{
referrerUrls[linktext] = 0;
}
referrerUrls[linktext] = ((int) referrerUrls[linktext]) + 1;
log.UserAgent = HttpUtility.HtmlEncode(log.UserAgent);
if (!userAgents.Contains(log.UserAgent))
{
userAgents[log.UserAgent] = 0;
}
userAgents[log.UserAgent] = ((int) userAgents[log.UserAgent]) + 1;
log.UserDomain = HttpUtility.HtmlEncode(log.UserDomain);
if(!userDomains.Contains(log.UserDomain))
{
userDomains[log.UserDomain] = 0;
}
userDomains[log.UserDomain] = ((int) userDomains[log.UserDomain]) + 1;
}
}
sb.Append("<p>");
sb.Append("<table width=\"100%\">");
sb.Append(MakeTableHeader("Summary", "Hits"));
sb.Append(MakeTableRow("Internet Searches", GetTotal(searchUrls)));
sb.Append(MakeTableRow("Referrers", GetTotal(referrerUrls) ));
sb.Append("</table>");
sb.Append("</p>");
sb.Append("<p>");
sb.Append("<table width=\"100%\">");
sb.Append(MakeTableHeader("Internet Searches", "Count"));
sb.Append(MakeTableRowsFromArray(searchUrls));
sb.Append("</table>");
sb.Append("</p>");
sb.Append( "<p>");
sb.Append( "<table width=\"100%\">");
sb.Append( MakeTableHeader("Referrers", "Count"));
sb.Append( MakeTableRowsFromArray(referrerUrls));
sb.Append( "</table>");
sb.Append( "</p>");
sb.Append("<p>");
sb.Append("<table width=\"100%\">");
sb.Append(MakeTableHeader("User Agents", "Count"));
sb.Append(MakeTableRowsFromArray(userAgents));
sb.Append("</table>");
sb.Append("</p>");
sb.Append("<p>");
sb.Append("<table width=\"100%\">");
sb.Append(MakeTableHeader("User Domains", "Count"));
sb.Append(MakeTableRowsFromArray(userDomains));
sb.Append("</table>");
sb.Append("</p>");
sb.Append("<br/><br/>");
}
catch ( Exception e)
{
sb.Append("<p>Error : " + e.ToString() + "</p>");
}
return sb.ToString();
}
private string GetStyleSheet()
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append("<style type=\"text/css\">");
sb.Append("table {border: 0; border-spacing: 0; border-collapse: collapse; padding: 0; width: 100%; font-family: Tahoma,Arial,Helvetica; font-size: 8pt; }");
sb.Append("td.heading { text-align: left; font-weight: bold; color: white; background-color: #919eae; border: 0; padding: 10px 5px 10px 5px;}");
sb.Append("td.data {font-weight: normal; border: 0; border-color: #fff #fff #abc #fff; border-style: solid; border-width: 1px; padding: 0 5px 0 5px; }");
sb.Append("td.mainheader {text-align: center; font-weight: bold; color: white; background-color: #919eae; border: 0; padding: 10px 5px 10px 5px; font-size: 16pt;}");
sb.Append("</style>");
return sb.ToString();
}
private string GetTotal(Hashtable hash)
{
int count = 0;
foreach (object key in hash.Keys)
{
count += (int)hash[key];
}
return count.ToString();
}
private string MakeTableHeader(string col1, string col2)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append("<tr>");
sb.Append("<td class=\"heading\" width=\"90%\"><b>" + HttpUtility.HtmlEncode(col1) + "</b></td>");
sb.Append("<td class=\"heading\" width=\"10%\"><b>" + HttpUtility.HtmlEncode(col2) + "</b></td>");
sb.Append("</tr>");
return sb.ToString();
}
private string MakeTableRow(string title, string count)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append("<tr>");
sb.Append("<td class=\"data\">"); // needed to split this as the doted IP is not liked
sb.Append(title); // when adding strings together ??
sb.Append("</td>"); // depending on email client / SMTP server ??
sb.Append("<td class=\"data\">" + count + "</td>");
sb.Append("</tr>");
return sb.ToString();
}
private string MakeTableRowsFromArray(Hashtable hash)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
ArrayList arrayList = GenerateSortedItemList(hash);
foreach (ActivityItem ai in arrayList)
{
sb.Append(MakeTableRow(ai.Key, ai.Val.ToString()));
}
return sb.ToString();
}
protected ArrayList GenerateSortedItemList( IDictionary dict )
{
ArrayList listItems = new ArrayList(dict.Count);
foreach (DictionaryEntry de in dict)
{
listItems.Add(new ActivityItem(de.Key.ToString(), (int)de.Value));
}
listItems.Sort(new ActivityItem.Comparer());
return listItems;
}
}
class ActivityItem
{
public string Key;
public int Val;
public ActivityItem(string key, int val)
{
Key = key;
Val = val;
}
public class Comparer : IComparer
{
public int Compare(object left, object right)
{
int leftValue = ((ActivityItem)left).Val;
int rightValue = ((ActivityItem)right).Val;
if (leftValue > rightValue)
{
return -1;
}
else if (leftValue < rightValue)
{
return 1;
}
return 0;
}
}
}
}
|