code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.ServiceProcess;
using System.Text;
using EmailAlerts.Service.Properties;
using System.Net.Mail;
using DAL.findahome;
using System.Data.Linq;
using System.IO;
using System.Transactions;
using TargetState = DAL.findahome.InOut_Target.States;
using KeyState = DAL.findahome.InOut_Key.States;
using System.Threading;
using System.Globalization;
using System.Net.Mime;
namespace EmailAlerts.Service
{
partial class Engine : ServiceBase
{
BedroomList emptyBedroomList = new BedroomList();
Agent emptyAgent = new Agent() { idOffice = -1 };
SmtpClient smtpClient = new SmtpClient();
AgentContactFrequency defaultPeriod = new AgentContactFrequency() { LastSent = DateTime.Today.AddDays(-8), Frequency = 7 };
BedroomList bedroomList = new BedroomList();
PropertyHit propertyHit = new PropertyHit() { Emails = 0, Hits = 0 };
EmailComparer emailComparer = new EmailComparer();
public Engine()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Process.GetCurrentProcess().PriorityClass = Settings.Default.Priority;
this.Pulse.Enabled = true;
#if DEBUG
this.Pulse.Interval = 20000;
#else
this.Pulse.Interval = Settings.Default.Pulse.TotalMilliseconds;
#endif
}
protected override void OnStop()
{
this.Pulse.Enabled = false;
}
private void Pulse_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
this.Pulse.Enabled = false;
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-IE");
// Control Sent in the Morning
DateTime dt = DateTime.Now;
if (dt.Hour > 6 && dt.Hour < 9)
{
if (Settings.Default.ApplicantAlertsOn)
{
ProcessApplicantAlerts();
}
if (Settings.Default.AgentAlertsOn)
{
ProcessAgentAlerts();
}
}
Trace.Flush();
this.Pulse.Enabled = true;
}
private void ProcessAgentAlerts()
{
try
{
var now = DateTime.Now;
var dlo = new DataLoadOptions();
dlo.LoadWith<Agency>(c => c.User);
dlo.LoadWith<AgencyOffice>(c => c.Agency);
dlo.LoadWith<AgencyOffice>(c => c.Agents);
dlo.LoadWith<Agent>(c => c.AgentContactFrequency);
dlo.LoadWith<Agent>(c => c.User);
dlo.LoadWith<Property>(c => c.AlertContents);
dlo.LoadWith<Property>(c => c.Frequency);
dlo.LoadWith<Property>(c => c.PropMarket);
dlo.LoadWith<Property>(c => c.PropertyType);
dlo.LoadWith<Property>(c => c.PropertyHits);
dlo.LoadWith<Property>(c => c.District);
dlo.LoadWith<Property>(c => c.CountyCity);
dlo.LoadWith<Property>(c => c.Country);
using (var dc = new findahomeDataContext() { CommandTimeout = 600, LoadOptions = dlo })
{
#if DEBUG
dc.Log = new StreamWriter(@"\linq2sql.log") { AutoFlush = true };
#endif
var officeCollection =
(from office in dc.AgencyOffices
from agent in office.Agents
let report = (agent.AgentContactFrequency ?? defaultPeriod)
where report.Frequency != Settings.Default.Unsubscribe
&& now >= (report.LastSent ?? now.AddYears(-report.Frequency)).AddDays(report.Frequency)
&& agent.User.Properties.Any(e => e.idCountry == 1/*only properties from Ireland*/ && e.idCRule == Settings.Default.Active && e.idPropMarket != Settings.Default.CollegeMarket || e.idCRule == Settings.Default.Agreed)
&& agent.User.idCountry == 1 //only agent who have address Ireland
//********************** Test for martin**********
//&& agent.User.idUser == 32158 // martin's office account
&& agent.AgencyOffice.Agency.idAffiliation == 3 // all the account that belong to IPAV
//&& agent.User.idUser == 65276 // kidd's personal test account
//************************************************
select office).Take(300)
.ToArray();
var exportTargetCollection = dc.InOut_Targets.Where(c => c.State == TargetState.OutOn).ToArray();
var template = dc.InOut_Target_Contents.Where(c => c.Website_Id == Settings.Default.fourpmWebsiteId).ToList();
// template.ForEach(delegate(InOut_Target_Content c) { c.Text = Uri.UnescapeDataString(c.Text); });
var onstyle = template.First(c => c.Name.Equals(Settings.Default.propertyreport_onstyle)).Text;
foreach (var office in officeCollection)
{
try
{
var publisherCollection = office.Agents.Where(c => c.User.Properties.Any(e => e.idCRule == Settings.Default.Active || e.idCRule == Settings.Default.Agreed && e.idPropMarket != Settings.Default.CollegeMarket)).ToArray();
var marketCollection = new StringBuilder();
var marketCounter = 0;
var propertyCollection = new StringBuilder();
var currentMarket = string.Empty;
var currentOwner = string.Empty;
var odd = false;
var propCounter = 0;
foreach (var p in publisherCollection.SelectMany(d => d.User.Properties.Where(c => c.idCRule == Settings.Default.Active || c.idCRule == Settings.Default.Agreed && c.idPropMarket != Settings.Default.CollegeMarket)).OrderBy(c => c.PropMarket.MarketName).ThenBy(c => c.idCreatedBy).ThenByDescending(c => c.ModifyDate))
{
if (currentMarket != p.PropMarket.MarketName)
{
currentMarket = p.PropMarket.MarketName;
propertyCollection.AppendFormat(template.First(c => c.Name.Equals(Settings.Default.propertyreport_marketline)).Text, p.idPropMarket, currentMarket);
marketCollection.AppendFormat(template.First(c => c.Name.Equals(Settings.Default.propertyreport_marketindex)).Text, p.idPropMarket, currentMarket);
marketCounter++;
odd = false;
if (currentOwner != p.User.Name)
{
currentOwner = p.User.Name;
}
propertyCollection.AppendFormat(template.First(c => c.Name.Equals(Settings.Default.propertyreport_publisherline)).Text, currentOwner);
}
if (currentOwner != p.User.Name)
{
currentOwner = p.User.Name;
propertyCollection.AppendFormat(template.First(c => c.Name.Equals(Settings.Default.propertyreport_publisherline)).Text, currentOwner);
}
var expire = p.ModifyDate.Add(p.PropMarket.StatusGroup == PropMarket.StatusGroupVariant.Sales ? Settings.Default.SaleExpiration : Settings.Default.LetExpiration);
expire = expire < p.ExpiryDate ? p.ExpiryDate : expire;
var expiredays = (expire - now).Days;
var pclass = expiredays <= 3 ? " color: #e00!important;" : string.Empty;
var temp = 0;
var size = currentMarket.ToLower().Contains("commercial") || currentMarket.ToLower().Contains("land") ?
string.Format("<span>{0}</span> {1}", p.PropSize > 0 ? (Int32)p.PropSize : (Int32)p.PropSizeAcres, p.PropSize > 0 ? "SqM" : "Acr")
:
string.Format("<span>{0}</span> bed{1}", temp = (p.BedroomLists.FirstOrDefault() ?? bedroomList).TotalRooms, temp == 1 ? string.Empty : "s");
var price = string.Format("{0:c0} {1}", p.PriceVal, (p.PropMarket.StatusGroup == PropMarket.StatusGroupVariant.Sales ? string.Empty : p.Frequency.FrequencyName));
var pics = p.PictureAdded > 0 ? p.PropertyPictures.Count(c => (c.Thumbnail ?? 0) == 0) : 0;
var hit = (p.PropertyHits ?? propertyHit);
var alert = p.AlertContents.Count;
int? num = null;
propertyCollection.AppendFormat(template.First(c => c.Name.Equals(Settings.Default.propertyreport_propertyline)).Text,
pclass + ((odd = !odd) ? " background-color: #F8F4F0;" : string.Empty),
p.idList, //{0}
//string.Format("{0}, {1}, {2}, {3}", p.DisplayAddress, p.District.DistrictName, p.CountyCity.CountyCityName, p.Country.CountryName).Trim(' ', '.', ','),
p.DisplayAddress,
size,
p.PropertyType.PTypeName,
price,
num,
pics == 0 ? string.Empty : pics.ToString() + "pics",
//pics,
//pics == 1 ? string.Empty : "s",
// ********** response the john request, when hits & Email Equal 0, hidden it *************
//hit.Hits,
num,
hit.Hits == 0 ? string.Empty : hit.Hits.ToString() + " hits",
//hit.Hits == 1 ? string.Empty : "s",
num,
// hit.Emails,
hit.Emails == 0 ? string.Empty : hit.Emails.ToString() + " Emails",
// hit.Emails == 1 ? string.Empty : "s",
// *****************************************************************************************
//alert,
//alert == 1 ? string.Empty : "s",
num,
alert == 0 ? string.Empty : alert.ToString() + "alerts",
p.ModifyDate,
expiredays < 30 && expiredays > 0 ? string.Format(" {0} day{1}", expiredays, (Math.Abs(expiredays) > 1 ? "s" : string.Empty)) : string.Empty,
string.Format("{0}.{1}", p.User.idUser, p.User.Key),
//p.idPropMarket == 3 || p.idPropMarket == 8 || p.idPropMarket == 10 || p.idPropMarket == 11 || p.idPropMarket == 13 ? "Sale Agreed" : "Rent Agreed",
p.idCRule == Settings.Default.Active ?
p.idPropMarket == 3 || p.idPropMarket == 8 || p.idPropMarket == 10 || p.idPropMarket == 11 || p.idPropMarket == 13 ? String.Format(Settings.Default.PropertyRuleControl, string.Format("{0}.{1}", p.User.idUser, p.User.Key), p.idList, "agreed", Settings.Default.GreenColor, "Sale Agreed") : String.Format(Settings.Default.PropertyRuleControl, string.Format("{0}.{1}", p.User.idUser, p.User.Key), p.idList, "agreed", Settings.Default.GreenColor, "Rent Agreed")
: p.idPropMarket == 3 || p.idPropMarket == 8 || p.idPropMarket == 10 || p.idPropMarket == 11 || p.idPropMarket == 13 ? String.Format(Settings.Default.PropertyRuleControl, string.Format("{0}.{1}", p.User.idUser, p.User.Key), p.idList, "close", Settings.Default.BlueColor, "Take Offline") : String.Format(Settings.Default.PropertyRuleControl, string.Format("{0}.{1}", p.User.idUser, p.User.Key), p.idList, "close", Settings.Default.BlueColor, "Take Offline"),
string.Format("{0}, {1}, {2}", p.District.DistrictName, p.CountyCity.CountyCityName, p.Country.CountryName) //{18}
);
propCounter++;
}
foreach (var p in
(from p in publisherCollection
let report = (p.AgentContactFrequency ?? defaultPeriod)
where p.User.ValidEmail
&& report.Frequency != Settings.Default.Unsubscribe
&& now >= (report.LastSent ?? now.AddYears(-report.Frequency)).AddDays(report.Frequency)
select p)
.Distinct(emailComparer))
{
var officeName = office.OfficeName.Trim(' ', '.', ',');
var reportOwner = string.Format("{0}, {1} {2}", p.User.Name, officeName.Equals(office.Agency.User.Name, StringComparison.InvariantCultureIgnoreCase) ? string.Empty : officeName + ",", office.Agency.User.Name).Trim(' ', '.', ',');
var body = new StringBuilder();
var exportCollection = new StringBuilder();
var key = string.Format("{0}.{1}", p.User.idUser, p.User.Key);
foreach (var target in exportTargetCollection.OrderBy(c => c.Name))
{
var tkey = p.User.InOut_Keys.FirstOrDefault(c => c.Target_Id == target.Id) ?? new InOut_Key() { Approved = !Settings.Default.DefaultClosedTargets.Contains(target.Id.ToString()), State = KeyState.Open };
var on = tkey.Approved && tkey.State == KeyState.Open ? onstyle : string.Empty;
var off = string.IsNullOrEmpty(on) ? onstyle : string.Empty;
exportCollection.AppendFormat(template.First(c => c.Name.Equals(Settings.Default.propertyreport_exportline)).Text, target.Name, key, target.Id, on, off);
}
//############################Template select function for Onview.ie#############################################
if (p.AgencyOffice.Agency.idAffiliation.Equals(3))
{
body.AppendFormat(template.First(c => c.Name.Equals(Settings.Default.propertyreport_template_onview)).Text, string.Empty, now, reportOwner, key, propertyCollection, marketCollection, marketCounter > 1 ? string.Empty : " display: none;");
}
else
{
//body.AppendFormat(template.First(c => c.Name.Equals(Settings.Default.propertyreport_template_onview)).Text, string.Empty, now, reportOwner, key, exportCollection, propertyCollection, marketCollection, marketCounter > 1 ? string.Empty : " display: none;");
body.AppendFormat(template.First(c => c.Name.Equals(Settings.Default.propertyreport_template)).Text, string.Empty, now, reportOwner, key, exportCollection, propertyCollection, marketCollection, marketCounter > 1 ? string.Empty : " display: none;");
}
//if(p.AgentContactFrequency.Template.Equals(0))
//{
// body.AppendFormat(template.First(c => c.Name.Equals(Settings.Default.propertyreport_template)).Text, string.Empty, now, reportOwner, key, exportCollection, propertyCollection, marketCollection, marketCounter > 1 ? string.Empty : " display: none;");
//}
//else if (p.AgentContactFrequency.Template.Equals(1))
//{
// body.AppendFormat(template.First(c => c.Name.Equals(Settings.Default.propertyreport_template_onview)).Text, string.Empty, now, reportOwner, key, propertyCollection, marketCollection, marketCounter > 1 ? string.Empty : " display: none;");
//}
//else
//{
// body.AppendFormat(template.First(c => c.Name.Equals(Settings.Default.propertyreport_template)).Text, string.Empty, now, reportOwner, key, exportCollection, propertyCollection, marketCollection, marketCounter > 1 ? string.Empty : " display: none;");
//}
//####################################################################################################################
var report = new MailMessage(Settings.Default.ReportEmail,
#if DEBUG
"kidd@4pm.ie,michael@4pm.ie,john@4pm.ie",
#else
//"kidd@4pm.ie",
p.User.UserEmail,
#endif
string.Format(template.First(c => c.Name.Equals(Settings.Default.propertyreport_subject)).Text, propCounter), body.ToString()) { IsBodyHtml = true };
report.Bcc.Add(Settings.Default.ReportEmail);
report.ReplyTo = new MailAddress(template.First(c => c.Name.Equals(Settings.Default.propertyreport_replyto)).Text);
smtpClient.Send(report);
#if !DEBUG
if (p.AgentContactFrequency == null)
{
dc.AgentContactFrequencies.InsertOnSubmit(new AgentContactFrequency() { AgentId = p.idAgent, Frequency = 7, LastSent = now });
}
else
{
p.AgentContactFrequency.LastSent = now;
}
dc.SubmitChanges();
#endif
}
}
catch (Exception ex)
{
Trace.TraceWarning("OfficeId={0}, err: {1}", office.idOffice, ex);
}
}
#if DEBUG
dc.Log.Close();
#endif
}
}
catch (Exception ex)
{
Trace.TraceError(ex.ToString());
}
}
private void ProcessApplicantAlerts()
{
try
{
var dlo = new DataLoadOptions();
dlo.LoadWith<Property>(c => c.PropertyPictures);
dlo.AssociateWith<Property>(c => c.PropertyPictures.Where(d => (d.Thumbnail ?? 0) == 1));
dlo.LoadWith<Property>(c => c.Country);
dlo.LoadWith<Property>(c => c.CountyCity);
dlo.LoadWith<Property>(c => c.LivingType);
dlo.LoadWith<Property>(c => c.PropertyType);
dlo.LoadWith<Property>(c => c.PropMarket);
dlo.LoadWith<Property>(c => c.User);
dlo.LoadWith<User>(c => c.Agents);
dlo.LoadWith<Property>(c => c.District);
dlo.LoadWith<AlertRequest>(c => c.Applicant);
dlo.LoadWith<AlertRequest>(c => c.User);
dlo.LoadWith<AlertRequest>(c => c.Country);
dlo.LoadWith<AlertRequest>(c => c.CountyCity);
dlo.LoadWith<AlertRequest>(c => c.District);
dlo.LoadWith<AlertRequest>(c => c.DistrictGroup);
dlo.LoadWith<AlertRequest>(c => c.LetCategory);
dlo.LoadWith<AlertRequest>(c => c.PropertyType);
dlo.LoadWith<AlertRequest>(c => c.PropMarket);
dlo.LoadWith<AlertRequest>(c => c.Site);
dlo.LoadWith<AlertRequest>(c => c.InOut_Target);
dlo.LoadWith<Applicant>(c => c.User);
dlo.LoadWith<AgencyOfficeWebSite>(c => c.ClientWebSite);
using (var dc = new findahomeDataContext() { LoadOptions = dlo, CommandTimeout = 600, })
{
#if DEBUG
dc.Log = new StreamWriter(@"\linq2sql.log") { AutoFlush = true };
#endif
var log = new AlertEngineLog();
var now = DateTime.Now;
try
{
log.CalledBy = this.ServiceName;
log.Date = DateTime.Now;
log.Error = string.Empty;
var currentAlertRequests = dc.AlertRequests.Where(c =>
c.Active
&& now >= (c.LastSend ?? c.CreatedDate).AddDays(c.Frequency ?? 0)
&& (c.Applicant.AllowEmail ?? c.Applicant.AllowSMS ?? c.Applicant.AllowMMS ?? c.idApplicant == 0)
&& c.Applicant.User != null//this check constraint must be set on the db level!
)
.ToArray();
if (currentAlertRequests.Count() > 0)
{
var minDate = currentAlertRequests.Min(c => c.LastSend ?? c.CreatedDate);
var properties = dc.Properties.Where(c => c.idCRule == 1 && c.CreatedDate >= minDate).ToArray();
var portalIds = currentAlertRequests.Select(c => c.idSite).Where(c => c.HasValue).Distinct().ToArray();
var officeIds = currentAlertRequests.Select(c => c.idOffice).Where(c => c.HasValue).Distinct().ToArray();
var agentIds = dc.Agents.Where(c => officeIds.Contains(c.idOffice)).Select(c => new { c.idOffice, c.idUser }).ToArray();
var officesTemplates =
(from template in dc.gw_newsletter_templates
join a in dc.Agents on template.UserId equals a.idAgent
where officeIds.Contains(a.idOffice) && (template.Active ?? false) && template.idTemplateType == 1
select new { template, a.idOffice })
.ToArray();
var portalsTemplates = dc.gw_newsletter_templates.Where(c => (c.Active ?? false) && c.idTemplateType == 1 && portalIds.Contains(c.idSite)).ToArray();
var defaultTemplate = dc.gw_newsletter_templates.FirstOrDefault(c => (c.Locked ?? false) && c.idTemplateType == 1);
var clientWebsites = dc.AgencyOfficeWebSites.Where(c => officeIds.Contains(c.idAgencyOffice)).Select(c => new { c.ClientWebSite, c.idAgencyOffice }).ToArray();
var portalWebsites = dc.Sites.ToArray();
foreach (var alertRequest in currentAlertRequests)
{
if (alertRequest.idApplicant != 0 && !alertRequest.Applicant.User.ValidEmail)
{
alertRequest.Active = false;
alertRequest.LastSend = now;
log.Error += string.Format("\nUser.Id {0} have invalid email '{1}'", alertRequest.Applicant.User.idUser, alertRequest.Applicant.User.UserEmail);
dc.SubmitChanges();
continue;//bypass bad emails
}
else if (alertRequest.idApplicant == 0 && !alertRequest.User.ValidEmail)
{
alertRequest.Active = false;
alertRequest.LastSend = now;
log.Error += string.Format("\nUser.Id {0} have invalid email '{1}'", alertRequest.User.idUser, alertRequest.User.UserEmail);
dc.SubmitChanges();
continue;//bypass bad emails
}
if (alertRequest.InOut_Target_Id != 0)//new EmailAlerts.Client
{
var sentCollection = alertRequest.User.AlertRequests.SelectMany(a => a.Alerts.SelectMany(c => c.AlertContents.Select(d => d.idList))).Distinct().ToArray();
var ownerCollection = alertRequest.InOut_Target.Office_Id == 0 ? alertRequest.Website.Agency.AgencyOffices.SelectMany(c => c.Agents.Select(d => d.idUser)).ToList()
: alertRequest.InOut_Target.Agency_Id == 0 ? alertRequest.Website.AgencyOffice.Agents.Select(d => d.idUser).ToList()
: new List<int>()
;
var propertiesToSend = (from c in properties
let l = Compare(alertRequest, c)
let t = c.AdTypeList.Length > alertRequest.InOut_Target.SiteIndex - 1 ? (int)c.AdTypeList[alertRequest.InOut_Target.SiteIndex - 1] != (int)Ad_TypeX.Variant.DontShow : false
where ownerCollection.Contains(c.idCreatedBy) || t
&& !sentCollection.Contains(c.idList)
&& alertRequest.idPropertyMarket == c.idPropMarket
&& alertRequest.idPropertyType == c.idPType
&& alertRequest.idCountry == c.idCountry
&& (alertRequest.idCounty ?? c.idCountyCity) == c.idCountyCity
&& c.CreatedDate >= (alertRequest.LastSend ?? alertRequest.CreatedDate)
&& l >= Settings.Default.MinimumLikeness
orderby string.Format("{0}.{1}", l, c.idList) descending
select c)
.Take(Settings.Default.PropertyLimit)
.ToArray();
if (propertiesToSend.Count() > 0)
{
var header = alertRequest.InOut_Target.InOut_Target_Contents.FirstOrDefault(c => c.Name == Settings.Default.emailalert_header);
var propertyline = alertRequest.InOut_Target.InOut_Target_Contents.FirstOrDefault(c => c.Name == Settings.Default.emailalert_propertyline);
var footer = alertRequest.InOut_Target.InOut_Target_Contents.FirstOrDefault(c => c.Name == Settings.Default.emailalert_footer);
var alert = new Alert()
{
Type = Alert.TypeVariant.Email,
Request_Id = alertRequest.idRequest,
SendDate = now,
};
dc.Alerts.InsertOnSubmit(alert);
var key = alertRequest.Applicant.User.Key;
var body = new StringBuilder(@"<html xmlns=""http://www.w3.org/1999/xhtml""><head><title>email alert</title></head><body>");
body.AppendFormat(header.Text, now);
foreach (var property in propertiesToSend)
{
//{0} - id property
//{1} - main image src
//{2} - address
//{3} - property status
//{4} - price
//{5} - proprty type
//{6} - part of description
body.AppendFormat(propertyline.Text,
property.idList,
property.PropertyPictures.Any() ? string.Format("http://www.4pm.ie/ShowThumbnail.aspx?id={0}&img={1}", property.idList, Uri.EscapeDataString(property.PropertyPictures.First().PicPath)) : string.Empty,
string.Format("{0}, {1}, {2}", property.DisplayAddress, property.District.DistrictName, property.CountyCity.CountyCityName),
property.PropStatus.StatusName,
property.PriceVal > 0 ? string.Format("{0:c0} {1}", property.PriceVal, property.PropMarket.StatusGroup == PropMarket.StatusGroupVariant.Rental /*show frequency for rental only*/ ? property.Frequency.FrequencyName : string.Empty) : "On request",
string.Format("{0} {1}", property.PropertyType.PTypeName, property.LivingType.LTypeName.Equals("not applicable", StringComparison.InvariantCultureIgnoreCase) ? string.Empty : string.Format("({0})", property.LivingType.LTypeName)),
property.Description.PadRight(300).Substring(0, 300).Trim() + "..."
)
;
var alertContent = new AlertContent();
alertContent.Alert = alert;
alertContent.idList = property.idList;
dc.AlertContents.InsertOnSubmit(alertContent);
}
body.AppendFormat(footer.Text,
string.Format("http://api.4pm.ie/alert.svc/{0}.{1}/unsubscribe", alertRequest.idRequest, key)
);
body.Append(@"</body></html>");
var message = new MailMessage(
string.Format("info@{0}", alertRequest.Website.Domain),
alertRequest.Applicant.User.UserEmail,
Settings.Default.EmailSubject,
body.ToString())
{
IsBodyHtml = true,
};
message.Bcc.Add(Settings.Default.ReportEmail);
smtpClient.Send(message);
}
log.NbAlertsSent++;
}
else if (alertRequest.Website_Id != 0)//new EmailAlerts.Client
{
var sentCollection = alertRequest.Applicant.AlertRequests.SelectMany(a => a.Alerts.SelectMany(c => c.AlertContents.Select(d => d.idList))).Distinct().ToArray();
var ownerCollection = alertRequest.Website.Office_Id == 0 ?
alertRequest.Website.Agency.AgencyOffices.SelectMany(c => c.Agents.Select(d => d.idUser)).ToList() :
alertRequest.Website.AgencyOffice.Agents.Select(d => d.idUser).ToList()
;
var propertiesToSend = (from c in properties
let l = Compare(alertRequest, c)
where ownerCollection.Contains(c.idCreatedBy)
&& !sentCollection.Contains(c.idList)
&& alertRequest.idPropertyMarket == c.idPropMarket
&& alertRequest.idPropertyType == c.idPType
&& alertRequest.idCountry == c.idCountry
&& (alertRequest.idCounty ?? c.idCountyCity) == c.idCountyCity
&& c.CreatedDate >= (alertRequest.LastSend ?? alertRequest.CreatedDate)
&& l >= Settings.Default.MinimumLikeness
orderby string.Format("{0}.{1}", l, c.idList) descending
select c)
.Take(Settings.Default.PropertyLimit)
.ToArray();
if ((alertRequest.Applicant.AllowEmail ?? false) && propertiesToSend.Count() > 0)
{
var header = alertRequest.Website.InOut_Target_Contents.FirstOrDefault(c => c.Name == Settings.Default.emailalert_header);
var propertyline = alertRequest.Website.InOut_Target_Contents.FirstOrDefault(c => c.Name == Settings.Default.emailalert_propertyline);
var footer = alertRequest.Website.InOut_Target_Contents.FirstOrDefault(c => c.Name == Settings.Default.emailalert_footer);
var alert = new Alert()
{
Type = Alert.TypeVariant.Email,
Request_Id = alertRequest.idRequest,
SendDate = now,
};
dc.Alerts.InsertOnSubmit(alert);
var key = alertRequest.Applicant.User.Key;
var body = new StringBuilder(@"<html xmlns=""http://www.w3.org/1999/xhtml""><head><title>email alert</title></head><body>");
body.AppendFormat(header.Text, now);
foreach (var property in propertiesToSend)
{
//{0} - id property
//{1} - main image src
//{2} - address
//{3} - property status
//{4} - price
//{5} - proprty type
//{6} - part of description
body.AppendFormat(propertyline.Text,
property.idList,
property.PropertyPictures.Any() ? string.Format("http://www.4pm.ie/ShowThumbnail.aspx?id={0}&img={1}", property.idList, Uri.EscapeDataString(property.PropertyPictures.First().PicPath)) : string.Empty,
string.Format("{0}, {1}, {2}", property.DisplayAddress, property.District.DistrictName, property.CountyCity.CountyCityName),
property.PropStatus.StatusName,
property.PriceVal > 0 ? string.Format("{0:c0} {1}", property.PriceVal, property.PropMarket.StatusGroup == PropMarket.StatusGroupVariant.Rental /*show frequency for rental only*/ ? property.Frequency.FrequencyName : string.Empty) : "On request",
string.Format("{0} {1}", property.PropertyType.PTypeName, property.LivingType.LTypeName.Equals("not applicable", StringComparison.InvariantCultureIgnoreCase) ? string.Empty : string.Format("({0})", property.LivingType.LTypeName)),
property.Description.PadRight(300).Substring(0, 300).Trim() + "..."
)
;
var alertContent = new AlertContent();
alertContent.Alert = alert;
alertContent.idList = property.idList;
dc.AlertContents.InsertOnSubmit(alertContent);
}
body.AppendFormat(footer.Text,
string.Format("http://api.4pm.ie/alert.svc/{0}.{1}/unsubscribe", alertRequest.idRequest, key)
);
body.Append(@"</body></html>");
var message = new MailMessage(
string.Format("info@{0}", alertRequest.Website.Domain),
alertRequest.Applicant.User.UserEmail,
Settings.Default.EmailSubject,
body.ToString())
{
IsBodyHtml = true,
};
message.Bcc.Add(Settings.Default.ReportEmail);
smtpClient.Send(message);
}
log.NbAlertsSent++;
}
else//old EmailAlerts.Client TODO: remove
{
#if !DEBUG
var sentList = alertRequest.Applicant.AlertRequests.SelectMany(a => a.Alerts.SelectMany(c => c.AlertContents.Select(d => d.idList))).Distinct().ToArray();
var relatedAlertRequestList = alertRequest.Applicant.AlertRequests.Where(a => a.Active && ((alertRequest.idSite.HasValue && a.idSite == alertRequest.idSite) || (alertRequest.idOffice.HasValue && a.idOffice == alertRequest.idOffice))).Select(a => a.idRequest).ToArray();
var ownerList = agentIds.Where(c => alertRequest.idOffice.HasValue && c.idOffice == alertRequest.idOffice).Select(c => c.idUser).Distinct().ToArray();
var propertiesToSend =
(from c in properties
let l = Compare(alertRequest, c)
where ((alertRequest.idOffice.HasValue && ownerList.Contains(c.idCreatedBy)) || (alertRequest.idSite.HasValue))
&& !sentList.Contains(c.idList)
&& alertRequest.idPropertyMarket == c.idPropMarket
&& alertRequest.idPropertyType == c.idPType
&& alertRequest.idCountry == c.idCountry
&& (alertRequest.idCounty ?? c.idCountyCity) == c.idCountyCity
&& c.CreatedDate >= (alertRequest.LastSend ?? alertRequest.CreatedDate)
&& l >= Settings.Default.MinimumLikeness
&& (alertRequest.idSite.HasValue || (alertRequest.idOffice ?? 0) == (c.User.Agents ?? emptyAgent).idOffice)
orderby string.Format("{0}.{1}", l, c.idList) descending
select c)
.Take(Settings.Default.PropertyLimit)
.ToArray();
if ((alertRequest.Applicant.AllowEmail ?? false) && propertiesToSend.Count() > 0)
{
var template = defaultTemplate;
if (alertRequest.idSite.HasValue)
{
var tempTemplate = portalsTemplates.FirstOrDefault(c => c.idSite == alertRequest.idSite);
if (tempTemplate != null)
template = tempTemplate;
}
else if (alertRequest.idOffice.HasValue)
{
var tempTemplate = officesTemplates.FirstOrDefault(c => c.idOffice == alertRequest.idOffice);
if (tempTemplate != null)
template = tempTemplate.template;
}
if (template != null)
{
var alert = new Alert()
{
Type = Alert.TypeVariant.Email,
Request_Id = alertRequest.idRequest,
SendDate = now,
};
dc.Alerts.InsertOnSubmit(alert);
var key = alertRequest.Applicant.User.Key;
var body = new StringBuilder();
var websiteURL = string.Empty;
var showPropertyPageURL = string.Empty;
var showUserPageURL = string.Empty;
if ((alertRequest.idOffice ?? 0) > 0)
{
var website = clientWebsites.FirstOrDefault(c => c.idAgencyOffice == alertRequest.idOffice);
if (website != null)
{
websiteURL = website.ClientWebSite.mainURL;
showPropertyPageURL = website.ClientWebSite.showPropertyURL;
showUserPageURL = websiteURL + "/AlertRequest.aspx";
}
else
{
alertRequest.LastSend = now;
log.Error += string.Format("\nwe have no ClientWebSite for this office {0}", alertRequest.idOffice);
continue;//bypass because bad office configuration
}
}
else if (alertRequest.idSite.HasValue)
{
websiteURL = "http://www." + alertRequest.Site.SiteName;
showPropertyPageURL = websiteURL + "/ShowProp.aspx?id=";
showUserPageURL = websiteURL + "/AlertRequest.aspx";
}
body.Append("<div style=\"color:#000; text-align:left; \">");
body.Append(template.Content);
var StyleBoldText = "font-family: Trebuchet MS, Verdana, Arial, Helvetica, sans-serif; font-size: 9pt; color: #414141; line-height: 18px; font-weight:bold;";
#region " Alert Request "
body.Append("<br/><span style=\"font-family: Trebuchet MS, Verdana, Arial, Helvetica, sans-serif;font-size: 16px;font-weight: bold;color: #414141;\">You requested properties matching these criteria :</span>");
body.Append("<i>(Request created on : " + alertRequest.CreatedDate.ToShortDateString() + ")</i><br/>");
body.Append(@"<div style=""text-align:left; margin-bottom:10px;padding:0px;""><img src=""http://www.4pm.ie/emailAlertTemplates/bar.gif"" border=""0"" /></div>");
body.Append("<table border=\"0\" style=\" \" cellpadding=\"5\">");
body.Append("<tr><td>Country : </td><td style=\"" + StyleBoldText + "\"> " + alertRequest.Country.CountryName + "</td></tr>");
body.Append("<tr><td>County/City : </td><td style=\"" + StyleBoldText + "\"> " + alertRequest.CountyCity.CountyCityName + "</td></tr>");
if (alertRequest.idDistrict.HasValue)
body.Append("<tr><td>District : </td><td style=\"" + StyleBoldText + "\"> " + alertRequest.District.DistrictName + "</td></tr>");
if (alertRequest.idDistrictGroup.HasValue)
body.Append("<tr><td>District group : </td><td style=\"" + StyleBoldText + "\"> " + alertRequest.DistrictGroup.GroupName + "</td></tr>");
if (!string.IsNullOrEmpty(alertRequest.PostCode))
body.Append("<tr><td>Post code : </td><td style=\"" + StyleBoldText + "\"> " + alertRequest.PostCode + "</td></tr>");
body.Append("<tr><td>Market : </td><td style=\"" + StyleBoldText + "\"> " + alertRequest.PropMarket.MarketName);
if (alertRequest.idLetCategory.HasValue)
body.Append(" - " + alertRequest.LetCategory.CategoryName);
body.Append("</td></tr>");
body.Append("<tr><td>Type of property : </td><td style=\"" + StyleBoldText + "\"> " + alertRequest.PropertyType.PTypeName);
if (alertRequest.idLivingType.HasValue)
body.Append(" - " + alertRequest.LivingType.LTypeName);
body.Append("</td></tr>");
if ((alertRequest.NumberOfBeds ?? 0) != 0)
body.Append("<tr><td>Number of beds : </td><td style=\"" + StyleBoldText + "\"> " + alertRequest.NumberOfBeds + "</td></tr>");
if (alertRequest.MinPrice != 0)
body.Append("<tr><td>Minimum price : </td><td style=\"" + StyleBoldText + "\"> " + alertRequest.MinPrice.ToString("c") + "</td></tr>");
if (alertRequest.MaxPrice != 0)
body.Append("<tr><td>Maximum price : </td><td style=\"" + StyleBoldText + "\"> " + alertRequest.MaxPrice.ToString("c") + "</td></tr>");
body.Append("</table>");
#endregion
body.Append("<br/><br/><span style=\"font-family: Trebuchet MS, Verdana, Arial, Helvetica, sans-serif;font-size: 16px;font-weight: bold;color: #414141;\">Properties matching your request:</span><br/>");
body.Append("<div style=\"text-align:left; margin-bottom:10px;padding:0px;\"><img src=\"http://www.4pm.ie/emailAlertTemplates/bar.gif\" border=\"0\" /></div>");
body.Append("<table border=\"0\" style=\"\" cellspacing=\"4\" >");
var isAlternateRow = false;
var isFirstInRow = true;
#region " Property section "
foreach (var property in propertiesToSend)
{
if (isFirstInRow)
{
body.Append("<tr style=\"\">");
}
var detailsLink = showPropertyPageURL + property.idList;
body.Append("<td width=\"309\" height=\"145\" valign=\"top\"><table width=\"98%\" border=\"0\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\" style=\"background-color: #ffffff;border: #bda68e 1px solid;padding: 2px;\">");
body.Append("<tr><td width=\"45\" valign=\"top\"><div style=\"width: 124px;height: 124px; background-color: #FFFFFF;\">");
if (property.PictureAdded == 1)
body.Append("<img src=\"" + "http://www.4pm.ie/ShowThumbnail.aspx?id=" + property.idList + "&img=" + Uri.EscapeDataString(property.PropertyPictures.First().PicPath) + "\" style=\"margin: 2px;\" />");
else
body.Append("<div style=\"width:120px; height:120px; margin:2px; border: solid 1px #f4ebe0; color:#d8d1ca; text-align:center;line-height: 18px;vertical-align:middle\" ><br/><br/>No picture<br/>Available</div>");
body.Append("</div></td><td width=\"62%\" valign=\"top\" style=\"padding:2px;\">");
body.Append("<div style=\"overflow: hidden;height: 40px;background-color: #F8F4F0;vertical-align:middle; padding:4px;\"><span style=\"font-family: Trebuchet MS, Verdana, Arial, Helvetica, sans-serif;font-size: 12px;color: #ac651d;font-weight:bold;\">" + (String.Format("{0}, {1}, {2}", property.DisplayAddress, property.District.DistrictName, property.CountyCity.CountyCityName)) + "</span></div>");
body.Append("<span style=\"font-family: Trebuchet MS, Verdana, Arial, Helvetica, sans-serif; font-size: 9pt; color: #414141; line-height: 18px;\"><strong>" + property.PropertyType.PTypeName);
if ((property.BedroomLists.FirstOrDefault() ?? emptyBedroomList).TotalBedspaces != 0)
body.Append(" - <span style=\"font-family: Trebuchet MS, Verdana, Arial, Helvetica, sans-serif; font-size: 11px; color: #4d8989;\">" + (property.BedroomLists.FirstOrDefault() ?? emptyBedroomList).TotalBedspaces + "</span> </strong>bed(s)<strong>");
body.Append("<br /></strong></span> ");
body.Append("<span style=\"font-family: Trebuchet MS, Verdana, Arial, Helvetica, sans-serif; font-size: 11px; color: #4d8989;\">" + (property.PriceVal > 0 ? property.PriceVal.ToString("c") : "Price on request") + "</span><br />");
body.Append("</td></tr>");
body.Append("<tr><td colspan=\"2\" style=\"background-color: #F8F4F0;height:12px;vertical-align:bottom; text-align:right;\"><a href=\"" + detailsLink + "\" target=\"_blank\" style=\"font-family: Trebuchet MS, Verdana, Arial, Helvetica, sans-serif;font-size: 10px;color: #414141;font-weight:bold; text-decoration:none;\">View more details >>></a></td></tr></table>");
body.Append("</td>");
if (!isFirstInRow)
{
body.Append("</tr>");
}
isAlternateRow = !isAlternateRow;
isFirstInRow = !isFirstInRow;
var alertContent = new AlertContent();
alertContent.Alert = alert;
alertContent.idList = property.idList;
dc.AlertContents.InsertOnSubmit(alertContent);
}
#endregion
if (!isFirstInRow) body.Append("</tr>");//in case the last row was incomplete, close it
body.Append("</table>");
body.AppendFormat(@"<br/><a href=""{0}"" target=""_blank"">Click here</a> to access your alerts management page and change your research criteria or alerts frequency settings.<br/>
You can also <a href=""{1}"" target=""_blank"">unsubscribe from this alert</a>,<br/>
or <a href=""{2}"" target=""_blank"">cancel all email alerts at once</a>.<br/>
<br/>",
showUserPageURL,
string.Format("http://api.4pm.ie/alert.svc/{0}.{1}/unsubscribe", alertRequest.idRequest, key),
string.Format("http://api.4pm.ie/alert.svc/{0}.{1}/unsubscribe", string.Join(",", relatedAlertRequestList.Select(c => c.ToString()).ToArray()), key)
);
body.Append(template.footer);
body.Append("</div>");
var senderEmail = template.sender;
try { new MailAddress(senderEmail); }
catch (FormatException ex)
{
log.Error += "\n" + ex.ToString();
senderEmail = defaultTemplate.sender;
}
smtpClient.Send(
new MailMessage(
senderEmail,
alertRequest.Applicant.User.UserEmail,
Settings.Default.EmailSubject,
body.ToString())
{
IsBodyHtml = true
});
}
log.NbAlertsSent++;
}
if ((alertRequest.Applicant.AllowSMS ?? false) && propertiesToSend.Count() > 0)
{
//TODO
}
if ((alertRequest.Applicant.AllowMMS ?? false) && propertiesToSend.Count() > 0)
{
//TODO
}
#endif
}
alertRequest.LastSend = now;
dc.SubmitChanges();
}
}
}
catch (Exception ex)
{
log.Error += "\n" + ex.ToString();
}
finally
{
if (!string.IsNullOrEmpty(log.Error))
{
Trace.TraceWarning(log.Error);
}
log.ExecutionTime = (decimal)DateTime.Now.Subtract(log.Date).TotalSeconds;
dc.AlertEngineLogs.InsertOnSubmit(log);
dc.SubmitChanges();
}
#if DEBUG
dc.Log.Close();
#endif
}
}
catch (Exception ex)
{
Trace.TraceError(ex.ToString());
}
}
private double Compare(AlertRequest alertRequest, Property property)
{
var result = 0.0;
var likeness = 0.0;
if ((!(alertRequest.MaxPrice >= property.PriceVal || alertRequest.MaxPrice == 0 || property.PriceVal == 0 || LikenessPercentage((double)alertRequest.MaxPrice, (double)property.PriceVal) > Settings.Default.MaxPriceK))
||
(!(alertRequest.MinPrice <= property.PriceVal || alertRequest.MinPrice == 0 || property.PriceVal == 0 || LikenessPercentage((double)alertRequest.MinPrice, (double)property.PriceVal) > Settings.Default.MinPriceK)))
{
result = 1;//return 0;
}
else
{
if ((alertRequest.idDistrict ?? 0) != 0 && property.idDistrict != 0)
{
result += Settings.Default.DistrictK;
likeness += Settings.Default.DistrictK;
if (alertRequest.idDistrict != property.idDistrict)
likeness -= Settings.Default.DistrictK;
}
if ((alertRequest.idDistrictGroup ?? 0) != 0)
{
result += Settings.Default.DistrictGroupK;
likeness += Settings.Default.DistrictGroupK;
if (property.District.DistrictGroupLists.FirstOrDefault(c => c.idDistrictGroup == alertRequest.idDistrictGroup) == null)
likeness -= Settings.Default.DistrictGroupK;
}
if ((alertRequest.NumberOfBeds ?? 0) != 0)
{
result += Settings.Default.NumberOfBedsK;
likeness += Settings.Default.NumberOfBedsK;
if (Math.Abs((property.BedroomLists.FirstOrDefault() ?? emptyBedroomList).TotalBedspaces - alertRequest.NumberOfBeds ?? 0) > 1)
likeness -= Settings.Default.NumberOfBedsK;
}
if ((alertRequest.idLivingType ?? 0) != 0)
{
result += Settings.Default.LivingTypeK;
likeness += Settings.Default.LivingTypeK;
if (alertRequest.idLivingType != property.idLType)
likeness -= Settings.Default.LivingTypeK;
}
if (!string.IsNullOrEmpty(alertRequest.PostCode))
{
result += Settings.Default.PostCodeK;
likeness += Settings.Default.PostCodeK;
if (!(property.Postcode ?? string.Empty).Trim().StartsWith(alertRequest.PostCode.Trim(), StringComparison.InvariantCultureIgnoreCase))
likeness -= Settings.Default.PostCodeK;
}
if ((alertRequest.idLetCategory ?? 0) != 0)
{
result += Settings.Default.LetCategoryK;
likeness += Settings.Default.LetCategoryK;
if ((property.LetCategoryLists.Count == 0 && property.idPropMarket == 2 && alertRequest.idLetCategory != 4) ||
(property.LetCategoryLists.FirstOrDefault(c => c.idLetCategory == alertRequest.idLetCategory) == null)
)
likeness -= Settings.Default.LetCategoryK;
}
if (result == 0)
{
likeness = result = 1;
}
if (property.PriceVal == 0)
{
likeness -= Settings.Default.PriceOnRequestPenalty;
}
}
return likeness / result;
}
private double LikenessPercentage(double val1, double val2)
{
var likeness = 1 - (Math.Abs(val1 - val2) / val1);
return (likeness > 0 ? likeness : 0);
}
}
}