PageRenderTime 49ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/CmsData/Emailer.cs

https://bitbucket.org/mahalowe/bvcms
C# | 1054 lines | 973 code | 69 blank | 12 comment | 168 complexity | b2760617bffde7437bf43ce8758416c8 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, Apache-2.0, BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception, AGPL-3.0
  1. /* Author: David Carroll
  2. * Copyright (c) 2008, 2009 Bellevue Baptist Church
  3. * Licensed under the GNU General Public License (GPL v2)
  4. * you may not use this code except in compliance with the License.
  5. * You may obtain a copy of the License at http://bvcms.codeplex.com/license
  6. */
  7. using System;
  8. using System.Net.Mail;
  9. using System.Threading;
  10. using CmsData.Codes;
  11. using UtilityExtensions;
  12. using System.Linq;
  13. using System.Text;
  14. using System.Configuration;
  15. using System.Collections.Generic;
  16. using System.Web;
  17. using System.Text.RegularExpressions;
  18. using System.Diagnostics;
  19. using System.IO;
  20. using System.Xml.Linq;
  21. using HtmlAgilityPack;
  22. namespace CmsData
  23. {
  24. public partial class CMSDataContext
  25. {
  26. public string CmsHost
  27. {
  28. get
  29. {
  30. var h = ConfigurationManager.AppSettings["cmshost"];
  31. return h.Replace("{church}", Host);
  32. }
  33. }
  34. public void Email(string from, Person p, string subject, string body)
  35. {
  36. Email(from, p, null, subject, body, false);
  37. }
  38. public void EmailRedacted(string from, Person p, string subject, string body)
  39. {
  40. Email(from, p, null, subject, body, true);
  41. }
  42. public void Email(string from, Person p, List<MailAddress> addmail, string subject, string body, bool redacted)
  43. {
  44. var From = Util.FirstAddress(from);
  45. if (From == null)
  46. From = Util.FirstAddress(Util.SysFromEmail);
  47. var emailqueue = new EmailQueue
  48. {
  49. Queued = DateTime.Now,
  50. FromAddr = From.Address,
  51. FromName = From.DisplayName,
  52. Subject = subject,
  53. Body = body,
  54. QueuedBy = Util.UserPeopleId,
  55. Redacted = redacted,
  56. Transactional = true
  57. };
  58. EmailQueues.InsertOnSubmit(emailqueue);
  59. string addmailstr = null;
  60. if (addmail != null)
  61. addmailstr = addmail.EmailAddressListToString();
  62. emailqueue.EmailQueueTos.Add(new EmailQueueTo
  63. {
  64. PeopleId = p.PeopleId,
  65. OrgId = CurrentOrgId,
  66. AddEmail = addmailstr,
  67. Guid = Guid.NewGuid(),
  68. });
  69. SubmitChanges();
  70. SendPersonEmail(CmsHost, emailqueue.Id, p.PeopleId);
  71. }
  72. public List<MailAddress> PersonListToMailAddressList(IEnumerable<Person> list)
  73. {
  74. var aa = new List<MailAddress>();
  75. foreach (var p in list)
  76. aa.AddRange(GetAddressList(p));
  77. return aa;
  78. }
  79. public void Email(string from, IEnumerable<Person> list, string subject, string body)
  80. {
  81. if (list.Count() == 0)
  82. return;
  83. var aa = PersonListToMailAddressList(list);
  84. Email(from, list.First(), aa, subject, body, false);
  85. }
  86. public void EmailRedacted(string from, IEnumerable<Person> list, string subject, string body)
  87. {
  88. if (list.Count() == 0)
  89. return;
  90. var aa = PersonListToMailAddressList(list);
  91. Email(from, list.First(), aa, subject, body, redacted: true);
  92. }
  93. public IEnumerable<Person> PeopleFromPidString(string pidstring)
  94. {
  95. var a = pidstring.SplitStr(",").Select(ss => ss.ToInt()).ToArray();
  96. var q = from p in People
  97. where a.Contains(p.PeopleId)
  98. orderby p.PeopleId == a[0] descending
  99. select p;
  100. return q;
  101. }
  102. public List<Person> StaffPeopleForDiv(int divid)
  103. {
  104. var q = from o in Organizations
  105. where o.DivOrgs.Any(dd => dd.DivId == divid)
  106. where o.NotifyIds != null && o.NotifyIds != ""
  107. select o.NotifyIds;
  108. var pids = string.Join(",", q);
  109. var a = pids.SplitStr(",").Select(ss => ss.ToInt()).ToArray();
  110. var q2 = from p in People
  111. where a.Contains(p.PeopleId)
  112. orderby p.PeopleId == a[0] descending
  113. select p;
  114. if (q2.Count() == 0)
  115. return AdminPeople();
  116. return q2.ToList();
  117. }
  118. public List<Person> AdminPeople()
  119. {
  120. return (from p in CMSRoleProvider.provider.GetAdmins()
  121. orderby p.Users.Any(u => u.Roles.Contains("Developer")) ascending
  122. select p).ToList();
  123. }
  124. public List<Person> FinancePeople()
  125. {
  126. var q = from u in Users
  127. where u.UserRoles.Any(ur => ur.Role.RoleName == "Finance")
  128. select u.Person;
  129. return q.ToList();
  130. }
  131. public string StaffEmailForOrg(int orgid)
  132. {
  133. var q = from o in Organizations
  134. where o.OrganizationId == orgid
  135. where o.NotifyIds != null && o.NotifyIds != ""
  136. select o.NotifyIds;
  137. var pids = string.Join(",", q);
  138. var a = pids.SplitStr(",").Select(ss => ss.ToInt()).ToArray();
  139. var q2 = from p in People
  140. where p.PeopleId == a[0]
  141. select p.FromEmail;
  142. if (q2.Count() == 0)
  143. return (from p in CMSRoleProvider.provider.GetAdmins()
  144. orderby p.Users.Any(u => u.Roles.Contains("Developer")) descending
  145. select p.FromEmail).First();
  146. return q2.SingleOrDefault();
  147. }
  148. public List<Person> StaffPeopleForOrg(int orgid)
  149. {
  150. var org = LoadOrganizationById(orgid);
  151. var pids = org.NotifyIds ?? "";
  152. var a = pids.Split(',').Select(ss => ss.ToInt()).ToArray();
  153. var q2 = from p in People
  154. where a.Contains(p.PeopleId)
  155. orderby p.PeopleId == a.FirstOrDefault() descending
  156. select p;
  157. //if (q2.Count() == 0)
  158. // return (from p in CMSRoleProvider.provider.GetAdmins()
  159. // orderby p.Users.Any(u => u.Roles.Contains("Developer")) descending
  160. // select p).ToList();
  161. return q2.ToList();
  162. }
  163. public Person UserPersonFromEmail(string email)
  164. {
  165. var q = from u in Users
  166. where u.Person.EmailAddress == email || u.Person.EmailAddress2 == email
  167. select u.Person;
  168. var p = q.FirstOrDefault();
  169. if (p == null)
  170. p = CMSRoleProvider.provider.GetAdmins().First();
  171. return p;
  172. }
  173. public EmailQueue CreateQueue(MailAddress From, string subject, string body, DateTime? schedule, int tagId, bool publicViewable)
  174. {
  175. var emailqueue = new EmailQueue
  176. {
  177. Queued = DateTime.Now,
  178. FromAddr = From.Address,
  179. FromName = From.DisplayName,
  180. Subject = subject,
  181. Body = body,
  182. SendWhen = schedule,
  183. QueuedBy = Util.UserPeopleId,
  184. Transactional = false,
  185. PublicX = publicViewable,
  186. };
  187. EmailQueues.InsertOnSubmit(emailqueue);
  188. SubmitChanges();
  189. if (body.Contains("http://publiclink", ignoreCase: true))
  190. {
  191. var link = Util.URLCombine(CmsHost, "/Manage/Emails/View/" + emailqueue.Id);
  192. var re = new Regex("http://publiclink", RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.IgnoreCase);
  193. emailqueue.Body = re.Replace(body, link);
  194. }
  195. var tag = TagById(tagId);
  196. var q = tag.People(this);
  197. var q2 = from p in q.Distinct()
  198. where p.EmailAddress != null
  199. where p.EmailAddress != ""
  200. where (p.SendEmailAddress1 ?? true) || (p.SendEmailAddress2 ?? false)
  201. where !p.EmailOptOuts.Any(oo => oo.FromEmail == emailqueue.FromAddr)
  202. orderby p.PeopleId
  203. select p.PeopleId;
  204. var i = 0;
  205. foreach (var pid in q2)
  206. {
  207. i++;
  208. emailqueue.EmailQueueTos.Add(new EmailQueueTo
  209. {
  210. PeopleId = pid,
  211. OrgId = CurrentOrgId,
  212. Guid = Guid.NewGuid()
  213. });
  214. }
  215. SubmitChanges();
  216. return emailqueue;
  217. }
  218. public void SendPersonEmail(string CmsHost, int id, int pid)
  219. {
  220. var SysFromEmail = Setting("SysFromEmail", ConfigurationManager.AppSettings["sysfromemail"]);
  221. var emailqueue = EmailQueues.Single(eq => eq.Id == id);
  222. var emailqueueto = EmailQueueTos.Single(eq => eq.Id == id && eq.PeopleId == pid);
  223. var fromname = emailqueue.FromName;
  224. if (!fromname.HasValue())
  225. fromname = emailqueue.FromAddr;
  226. else
  227. fromname = emailqueue.FromName.Replace("\"", "");
  228. var From = Util.FirstAddress(emailqueue.FromAddr, fromname);
  229. try
  230. {
  231. var p = LoadPersonById(emailqueueto.PeopleId);
  232. string text = emailqueue.Body;
  233. var aa = DoReplacements(ref text, CmsHost, p, emailqueueto);
  234. var qs = "OptOut/UnSubscribe/?enc=" + Util.EncryptForUrl("{0}|{1}".Fmt(emailqueueto.PeopleId, From.Address));
  235. var url = Util.URLCombine(CmsHost, qs);
  236. var link = @"<a href=""{0}"">Unsubscribe</a>".Fmt(url);
  237. text = text.Replace("{unsubscribe}", link);
  238. text = text.Replace("{Unsubscribe}", link);
  239. if (aa.Count > 0)
  240. {
  241. text = text.Replace("{toemail}", aa[0].Address);
  242. text = text.Replace("%7Btoemail%7D", aa[0].Address);
  243. }
  244. text = text.Replace("{fromemail}", From.Address);
  245. text = text.Replace("%7Bfromemail%7D", From.Address);
  246. if (Setting("sendemail", "true") != "false")
  247. {
  248. if (aa.Count > 0)
  249. Util.SendMsg(SysFromEmail, CmsHost, From, emailqueue.Subject, text, aa, emailqueue.Id, pid);
  250. else
  251. Util.SendMsg(SysFromEmail, CmsHost, From,
  252. "(no email address) " + emailqueue.Subject,
  253. "<p style='color:red'>You are receiving this because there is no email address for {0}({1}). You should probably contact them since they were probably expecting this information.</p>\n{2}".Fmt(p.Name, p.PeopleId, text),
  254. Util.ToMailAddressList(From),
  255. emailqueue.Id, pid);
  256. emailqueueto.Sent = DateTime.Now;
  257. emailqueue.Sent = DateTime.Now;
  258. if (emailqueue.Redacted ?? false)
  259. emailqueue.Body = "redacted";
  260. SubmitChanges();
  261. }
  262. }
  263. catch (Exception ex)
  264. {
  265. Util.SendMsg(SysFromEmail, CmsHost, From,
  266. "sent emails - error", ex.ToString(),
  267. Util.ToMailAddressList(From),
  268. emailqueue.Id, null);
  269. throw ex;
  270. }
  271. }
  272. public List<MailAddress> DoReplacements(ref string text, string CmsHost, Person p, EmailQueueTo emailqueueto)
  273. {
  274. if (text == null)
  275. text = "(no content)";
  276. if (p.Name.Contains("?") || p.Name.Contains("unknown", true))
  277. text = text.Replace("{name}", string.Empty);
  278. else
  279. text = text.Replace("{name}", p.Name);
  280. if (p.PreferredName.Contains("?", true) || (p.PreferredName.Contains("unknown", true)))
  281. text = text.Replace("{first}", string.Empty);
  282. else
  283. text = text.Replace("{first}", p.PreferredName);
  284. text = text.Replace("{occupation}", p.OccupationOther);
  285. var eurl = Util.URLCombine(CmsHost, "Manage/Emails/View/" + emailqueueto.Id);
  286. text = text.Replace("{emailhref}", eurl);
  287. text = DoVoteLinkAnchorStyle(text, CmsHost, emailqueueto);
  288. text = DoVoteTag(text, CmsHost, emailqueueto);
  289. text = DoVoteTag2(text, CmsHost, emailqueueto);
  290. text = DoRegisterTag(text, CmsHost, emailqueueto);
  291. text = DoRegisterTag2(text, CmsHost, emailqueueto);
  292. text = DoExtraValueData(text, emailqueueto);
  293. if (emailqueueto.OrgId.HasValue)
  294. {
  295. if (text.Contains("{smallgroup:"))
  296. text = DoSmallGroupData(text, emailqueueto);
  297. if (text.Contains("{addsmallgroup:"))
  298. text = DoAddSmallGroup(text, emailqueueto);
  299. if (text.Contains("{nextmeetingtime}"))
  300. text = DoMeetingDate(text, emailqueueto);
  301. }
  302. if (text.Contains("{createaccount}"))
  303. text = text.Replace("{createaccount}", DoCreateUserTag(CmsHost, emailqueueto));
  304. if (text.Contains("http://votelink", ignoreCase: true))
  305. text = DoVoteLink(text, CmsHost, emailqueueto);
  306. if (text.Contains("http://registerlink", ignoreCase: true))
  307. text = DoRegisterLink(text, CmsHost, emailqueueto);
  308. if (text.Contains("http://rsvplink", ignoreCase: true))
  309. text = DoRsvpLink(text, CmsHost, emailqueueto);
  310. if (text.Contains("http://volsublink", ignoreCase: true))
  311. text = DoVolSubLink(text, CmsHost, emailqueueto);
  312. if (text.Contains("http://volreqlink", ignoreCase: true))
  313. text = DoVolReqLink(text, CmsHost, emailqueueto);
  314. if (text.Contains("{barcode}", ignoreCase: true))
  315. {
  316. var link = Util.URLCombine(CmsHost, "/Track/Barcode/" + emailqueueto.PeopleId);
  317. text = text.Replace("{barcode}", "<img src='" + link + "' />");
  318. }
  319. if (text.Contains("{campus}", ignoreCase: true))
  320. if (p.CampusId != null)
  321. text = text.Replace("{campus}", p.Campu.Description);
  322. else
  323. text = text.Replace("{campus}", "No Campus Specified");
  324. if (emailqueueto.Guid.HasValue)
  325. {
  326. var turl = Util.URLCombine(CmsHost, "/Track/Key/" + emailqueueto.Guid.Value.GuidToQuerystring());
  327. text = text.Replace("{track}", "<img src=\"{0}\" />".Fmt(turl));
  328. }
  329. var aa = GetAddressList(p);
  330. if (emailqueueto.AddEmail.HasValue())
  331. foreach (var ad in emailqueueto.AddEmail.SplitStr(","))
  332. Util.AddGoodAddress(aa, ad);
  333. if (emailqueueto.OrgId.HasValue)
  334. {
  335. var qm = (from m in OrganizationMembers
  336. where m.PeopleId == emailqueueto.PeopleId && m.OrganizationId == emailqueueto.OrgId
  337. select new { m.PayLink, m.Amount, m.AmountPaid, m.RegisterEmail }).SingleOrDefault();
  338. if (qm != null)
  339. {
  340. if (qm.PayLink.HasValue())
  341. text = text.Replace("{paylink}", "<a href=\"{0}\">payment link</a>".Fmt(qm.PayLink));
  342. text = text.Replace("{amtdue}", (qm.Amount - qm.AmountPaid).ToString2("c"));
  343. Util.AddGoodAddress(aa, Util.FullEmail(qm.RegisterEmail, p.Name));
  344. }
  345. }
  346. return aa.DistinctEmails();
  347. }
  348. private string DoMeetingDate(string text, EmailQueueTo emailqueueto)
  349. {
  350. var mt = (from aa in Attends
  351. where aa.OrganizationId == emailqueueto.OrgId
  352. where aa.PeopleId == emailqueueto.PeopleId
  353. where aa.Commitment == AttendCommitmentCode.Attending
  354. where aa.MeetingDate > DateTime.Now
  355. orderby aa.MeetingDate
  356. select aa.MeetingDate).FirstOrDefault();
  357. text = text.Replace("{nextmeetingtime}", mt.ToString("g"));
  358. return text;
  359. }
  360. private string DoSmallGroupData(string text, EmailQueueTo emailqueueto)
  361. {
  362. const string RE = @"\{smallgroup:\[(?<prefix>[^\]]*)\](?:,(?<def>[^}]*)){0,1}\}";
  363. var re = new Regex(RE, RegexOptions.Singleline);
  364. var match = re.Match(text);
  365. while (match.Success && emailqueueto.OrgId.HasValue)
  366. {
  367. var tag = match.Value;
  368. var prefix = match.Groups["prefix"].Value;
  369. var def = match.Groups["def"].Value;
  370. var sg = (from mm in OrgMemMemTags
  371. where mm.OrgId == emailqueueto.OrgId
  372. where mm.PeopleId == emailqueueto.PeopleId
  373. where mm.MemberTag.Name.StartsWith(prefix)
  374. select mm.MemberTag.Name).FirstOrDefault();
  375. if (!sg.HasValue())
  376. sg = def;
  377. text = text.Replace(tag, sg);
  378. match = match.NextMatch();
  379. }
  380. return text;
  381. }
  382. private string DoAddSmallGroup(string text, EmailQueueTo emailqueueto)
  383. {
  384. const string RE = @"\{addsmallgroup:\[(?<group>[^\]]*)\]\}";
  385. var re = new Regex(RE, RegexOptions.Singleline);
  386. var match = re.Match(text);
  387. if (match.Success && emailqueueto.OrgId.HasValue)
  388. {
  389. var tag = match.Value;
  390. var group = match.Groups["group"].Value;
  391. var om = (from mm in OrganizationMembers
  392. where mm.OrganizationId == emailqueueto.OrgId
  393. where mm.PeopleId == emailqueueto.PeopleId
  394. select mm).SingleOrDefault();
  395. if (om != null)
  396. om.AddToGroup(this, group);
  397. text = text.Replace(tag, "");
  398. }
  399. return text;
  400. }
  401. private string DoExtraValueData(string text, EmailQueueTo emailqueueto)
  402. {
  403. const string RE = @"{extra(?<type>.*?):(?<field>.*?)}";
  404. var re = new Regex(RE, RegexOptions.Singleline);
  405. var match = re.Match(text);
  406. while (match.Success)
  407. {
  408. var tag = match.Value;
  409. var field = match.Groups["field"].Value;
  410. var type = match.Groups["type"].Value;
  411. var ev = PeopleExtras.SingleOrDefault(ee => ee.Field == field && emailqueueto.PeopleId == ee.PeopleId);
  412. string value = "";
  413. switch (type)
  414. {
  415. case "value":
  416. value = ev.StrValue;
  417. break;
  418. case "data":
  419. value = ev.Data;
  420. break;
  421. case "date":
  422. value = ev.DateValue.FormatDate();
  423. break;
  424. case "int":
  425. value = ev.IntValue.ToString();
  426. break;
  427. }
  428. text = text.Replace(tag, value);
  429. match = match.NextMatch();
  430. }
  431. return text;
  432. }
  433. private string DoVoteLinkAnchorStyle(string text, string CmsHost, EmailQueueTo emailqueueto)
  434. {
  435. var list = new Dictionary<string, OneTimeLink>();
  436. const string VoteLinkRE = @"{votelink(?<inside>[^}]*)}";
  437. var re = new Regex(VoteLinkRE, RegexOptions.Singleline | RegexOptions.Multiline);
  438. var match = re.Match(text);
  439. while (match.Success)
  440. {
  441. var votelink = match.Value;
  442. var anchor = "<a " + match.Groups["inside"].Value + ">text</a>";
  443. anchor = anchor.Replace("&quot;", "\"");
  444. anchor = anchor.Replace("&rdquo;", "\"");
  445. anchor = anchor.Replace("&ldquo;", "\"");
  446. var doc = new HtmlDocument();
  447. doc.LoadHtml(anchor);
  448. var ele = doc.DocumentNode.Element("a");
  449. var d = ele.Attributes.ToDictionary(aa => aa.Name.ToString(), aa => aa.Value);
  450. var txt = "click here";
  451. if (d.ContainsKey("text"))
  452. txt = d["text"];
  453. string msg = "Thank you for responding.";
  454. if (d.ContainsKey("message"))
  455. msg = d["message"];
  456. string confirm = "false";
  457. if (d.ContainsKey("confirm"))
  458. confirm = d["confirm"];
  459. if (!d.ContainsKey("smallgroup"))
  460. throw new Exception("Votelink: no smallgroup attribute");
  461. var smallgroup = d["smallgroup"];
  462. var pre = "";
  463. var a = smallgroup.SplitStr(":");
  464. if (a.Length > 1)
  465. pre = a[0];
  466. if (!d.ContainsKey("id"))
  467. throw new Exception("Votelink: no id attribute");
  468. var id = d["id"];
  469. var url = VoteLinkUrl(text, CmsHost, emailqueueto, list, votelink, id, msg, confirm, smallgroup, pre);
  470. text = text.Replace(votelink, @"<a href=""{0}"">{1}</a>".Fmt(url, txt));
  471. match = match.NextMatch();
  472. }
  473. return text;
  474. }//&lt;votetag .*?&gt;(?<inside>.+?)&lt;/votetag&gt;
  475. private string DoVoteTag2(string text, string CmsHost, EmailQueueTo emailqueueto)
  476. {
  477. var list = new Dictionary<string, OneTimeLink>();
  478. const string VoteLinkRE = @"&lt;votetag .*?&gt;(?<inside>.+?)&lt;/votetag&gt;";
  479. var re = new Regex(VoteLinkRE, RegexOptions.Singleline | RegexOptions.Multiline);
  480. var match = re.Match(text);
  481. while (match.Success)
  482. {
  483. var tag = match.Value;
  484. var inside = HttpUtility.HtmlDecode(match.Groups["inside"].Value);
  485. var doc = new HtmlDocument();
  486. doc.LoadHtml(tag);
  487. var ele = doc.DocumentNode.Element("votetag");
  488. var d = ele.Attributes.ToDictionary(aa => aa.Name.ToString(), aa => aa.Value);
  489. string msg = "Thank you for responding.";
  490. if (d.ContainsKey("message"))
  491. msg = d["message"];
  492. string confirm = "false";
  493. if (d.ContainsKey("confirm"))
  494. confirm = d["confirm"];
  495. if (!d.ContainsKey("smallgroup"))
  496. throw new Exception("Votelink: no smallgroup attribute");
  497. var smallgroup = d["smallgroup"];
  498. var pre = "";
  499. var a = smallgroup.SplitStr(":");
  500. if (a.Length > 1)
  501. pre = a[0];
  502. if (!d.ContainsKey("id"))
  503. throw new Exception("Votelink: no id attribute");
  504. var id = d["id"];
  505. var url = VoteLinkUrl(text, CmsHost, emailqueueto, list, tag, id, msg, confirm, smallgroup, pre);
  506. text = text.Replace(tag, @"<a href=""{0}"">{1}</a>".Fmt(url, inside));
  507. match = match.NextMatch();
  508. }
  509. return text;
  510. }
  511. private string DoCreateUserTag(string CmsHost, EmailQueueTo emailqueueto)
  512. {
  513. var user = (from u in Users
  514. where u.PeopleId == emailqueueto.PeopleId
  515. select u).FirstOrDefault();
  516. if (user != null)
  517. {
  518. user.ResetPasswordCode = Guid.NewGuid();
  519. user.ResetPasswordExpires = DateTime.Now.AddHours(Setting("ResetPasswordExpiresHours", "24").ToInt());
  520. var link = Util.URLCombine(CmsHost, "/Account/SetPassword/" + user.ResetPasswordCode.ToString());
  521. SubmitChanges();
  522. return @"<a href=""{0}"">Set password for {1}</a>".Fmt(link, user.Username);
  523. }
  524. var ot = new OneTimeLink
  525. {
  526. Id = Guid.NewGuid(),
  527. Querystring = emailqueueto.PeopleId.ToString()
  528. };
  529. OneTimeLinks.InsertOnSubmit(ot);
  530. SubmitChanges();
  531. var url = Util.URLCombine(CmsHost, "/Account/CreateAccount/{0}".Fmt(ot.Id.ToCode()));
  532. return @"<a href=""{0}"">Create Account</a>".Fmt(url);
  533. }
  534. private string DoVoteLink(string text, string CmsHost, EmailQueueTo emailqueueto)
  535. {
  536. //<a dir="ltr" href="http://votelink" id="798" rel="smallgroup" title="This is a message">test</a>
  537. var list = new Dictionary<string, OneTimeLink>();
  538. const string VoteLinkRE = "<a[^>]*?href=\"https{0,1}://votelink\"[^>]*>.*?</a>";
  539. var re = new Regex(VoteLinkRE, RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.IgnoreCase);
  540. var match = re.Match(text);
  541. while (match.Success)
  542. {
  543. var tag = match.Value;
  544. var doc = new HtmlDocument();
  545. doc.LoadHtml(tag);
  546. var ele = doc.DocumentNode.Element("a");
  547. var inside = ele.InnerHtml;
  548. var d = ele.Attributes.ToDictionary(aa => aa.Name.ToString(), aa => aa.Value);
  549. string msg = "Thank you for responding.";
  550. if (d.ContainsKey("title"))
  551. msg = d["title"];
  552. string confirm = "false";
  553. if (d.ContainsKey("dir") && d["dir"] == "ltr")
  554. confirm = "true";
  555. if (!d.ContainsKey("rel"))
  556. throw new Exception("Votelink: no smallgroup attribute");
  557. var smallgroup = d["rel"];
  558. var pre = "";
  559. var a = smallgroup.SplitStr(":");
  560. if (a.Length > 1)
  561. pre = a[0];
  562. if (!d.ContainsKey("id"))
  563. throw new Exception("Votelink: no id attribute");
  564. var id = d["id"];
  565. var url = VoteLinkUrl(text, CmsHost, emailqueueto, list, tag, id, msg, confirm, smallgroup, pre);
  566. text = text.Replace(tag, @"<a href=""{0}"">{1}</a>".Fmt(url, inside));
  567. match = match.NextMatch();
  568. }
  569. return text;
  570. }
  571. private string DoRsvpLink(string text, string CmsHost, EmailQueueTo emailqueueto)
  572. {
  573. //<a dir="ltr" href="http://rsvplink" id="798" rel="meetingid" title="This is a message">test</a>
  574. var list = new Dictionary<string, OneTimeLink>();
  575. const string RsvpLinkRE = "<a[^>]*?href=\"https{0,1}://rsvplink\"[^>]*>.*?</a>";
  576. var re = new Regex(RsvpLinkRE, RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.IgnoreCase);
  577. var match = re.Match(text);
  578. while (match.Success)
  579. {
  580. var tag = match.Value;
  581. var doc = new HtmlDocument();
  582. doc.LoadHtml(tag);
  583. var ele = doc.DocumentNode.Element("a");
  584. var inside = ele.InnerHtml;
  585. var d = ele.Attributes.ToDictionary(aa => aa.Name.ToString(), aa => aa.Value);
  586. string msg = "Thank you for responding.";
  587. if (d.ContainsKey("title"))
  588. msg = d["title"];
  589. string confirm = "false";
  590. if (d.ContainsKey("dir") && d["dir"] == "ltr")
  591. confirm = "true";
  592. string smallgroup = null;
  593. if (d.ContainsKey("rel"))
  594. smallgroup = d["rel"];
  595. if (!d.ContainsKey("id"))
  596. throw new Exception("Rsvplink: no id attribute");
  597. var id = d["id"];
  598. var url = RsvpLinkUrl(CmsHost, emailqueueto, list, id, smallgroup, msg, confirm);
  599. text = text.Replace(tag, @"<a href=""{0}"">{1}</a>".Fmt(url, inside));
  600. match = match.NextMatch();
  601. }
  602. return text;
  603. }
  604. private string DoRegisterLink(string text, string CmsHost, EmailQueueTo emailqueueto)
  605. {
  606. var list = new Dictionary<string, OneTimeLink>();
  607. const string VoteLinkRE = "<a[^>]*?href=\"https{0,1}://(?<rlink>registerlink2{0,1})\"[^>]*>.*?</a>";
  608. var re = new Regex(VoteLinkRE, RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.IgnoreCase);
  609. var match = re.Match(text);
  610. while (match.Success)
  611. {
  612. var tag = match.Value;
  613. var rlink = match.Groups["rlink"].Value;
  614. var doc = new HtmlDocument();
  615. doc.LoadHtml(tag);
  616. var ele = doc.DocumentNode.Element("a");
  617. var inside = ele.InnerHtml;
  618. var d = ele.Attributes.ToDictionary(aa => aa.Name.ToString(), aa => aa.Value);
  619. if (!d.ContainsKey("id"))
  620. throw new Exception("RegisterTag: no id attribute");
  621. var id = d["id"];
  622. var url = RegisterTagUrl(text, CmsHost, emailqueueto, list, tag, id,
  623. showfamily: rlink == "registerlink2");
  624. text = text.Replace(tag, @"<a href=""{0}"">{1}</a>".Fmt(url, inside));
  625. match = match.NextMatch();
  626. }
  627. return text;
  628. }
  629. public string DoVolSubLink(string text, string CmsHost, EmailQueueTo emailqueueto)
  630. {
  631. var list = new Dictionary<string, OneTimeLink>();
  632. const string VolSubLinkRE = "<a[^>]*?href=\"https{0,1}://volsublink\"[^>]*>.*?</a>";
  633. var re = new Regex(VolSubLinkRE, RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.IgnoreCase);
  634. var match = re.Match(text);
  635. while (match.Success)
  636. {
  637. var tag = match.Value;
  638. var doc = new HtmlDocument();
  639. doc.LoadHtml(tag);
  640. var ele = doc.DocumentNode.Element("a");
  641. var inside = ele.InnerHtml;
  642. var d = ele.Attributes.ToDictionary(aa => aa.Name.ToString(), aa => aa.Value);
  643. var qs = "{0},{1},{2},{3}"
  644. .Fmt(d["aid"], d["pid"], d["ticks"], emailqueueto.PeopleId);
  645. OneTimeLink ot = null;
  646. if (list.ContainsKey(qs))
  647. ot = list[qs];
  648. else
  649. {
  650. ot = new OneTimeLink
  651. {
  652. Id = Guid.NewGuid(),
  653. Querystring = qs
  654. };
  655. OneTimeLinks.InsertOnSubmit(ot);
  656. SubmitChanges();
  657. list.Add(qs, ot);
  658. }
  659. var url = Util.URLCombine(CmsHost, "/OnlineReg/ClaimVolSub/{0}/{1}".Fmt(d["ans"], ot.Id.ToCode()));
  660. text = text.Replace(tag, @"<a href=""{0}"">{1}</a>".Fmt(url, inside));
  661. match = match.NextMatch();
  662. }
  663. return text;
  664. }
  665. public string DoVolReqLink(string text, string CmsHost, EmailQueueTo emailqueueto)
  666. {
  667. var list = new Dictionary<string, OneTimeLink>();
  668. const string VolSubLinkRE = "<a[^>]*?href=\"https{0,1}://volreqlink\"[^>]*>.*?</a>";
  669. var re = new Regex(VolSubLinkRE, RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.IgnoreCase);
  670. var match = re.Match(text);
  671. while (match.Success)
  672. {
  673. var tag = match.Value;
  674. var doc = new HtmlDocument();
  675. doc.LoadHtml(tag);
  676. var ele = doc.DocumentNode.Element("a");
  677. var inside = ele.InnerHtml;
  678. var d = ele.Attributes.ToDictionary(aa => aa.Name.ToString(), aa => aa.Value);
  679. var qs = "{0},{1},{2},{3}"
  680. .Fmt(d["mid"], d["pid"], d["ticks"], emailqueueto.PeopleId);
  681. OneTimeLink ot = null;
  682. if (list.ContainsKey(qs))
  683. ot = list[qs];
  684. else
  685. {
  686. ot = new OneTimeLink
  687. {
  688. Id = Guid.NewGuid(),
  689. Querystring = qs
  690. };
  691. OneTimeLinks.InsertOnSubmit(ot);
  692. SubmitChanges();
  693. list.Add(qs, ot);
  694. }
  695. var url = Util.URLCombine(CmsHost, "/OnlineReg/RequestResponse?ans={0}&guid={1}".Fmt(d["ans"], ot.Id.ToCode()));
  696. text = text.Replace(tag, @"<a href=""{0}"">{1}</a>".Fmt(url, inside));
  697. match = match.NextMatch();
  698. }
  699. return text;
  700. }
  701. private string DoVoteTag(string text, string CmsHost, EmailQueueTo emailqueueto)
  702. {
  703. var list = new Dictionary<string, OneTimeLink>();
  704. const string VoteLinkRE = @"<votetag[^>]*>(?<inside>.+?)</votetag>";
  705. var re = new Regex(VoteLinkRE, RegexOptions.Singleline | RegexOptions.Multiline);
  706. var match = re.Match(text);
  707. while (match.Success)
  708. {
  709. var tag = match.Value;
  710. var inside = match.Groups["inside"].Value;
  711. var doc = new HtmlDocument();
  712. doc.LoadHtml(tag);
  713. var ele = doc.DocumentNode.Element("votetag");
  714. var d = ele.Attributes.ToDictionary(aa => aa.Name.ToString(), aa => aa.Value);
  715. string msg = "Thank you for responding.";
  716. if (d.ContainsKey("message"))
  717. msg = d["message"];
  718. string confirm = "false";
  719. if (d.ContainsKey("confirm"))
  720. confirm = d["confirm"];
  721. if (!d.ContainsKey("smallgroup"))
  722. throw new Exception("Votelink: no smallgroup attribute");
  723. var smallgroup = d["smallgroup"];
  724. var pre = "";
  725. var a = smallgroup.SplitStr(":");
  726. if (a.Length > 1)
  727. pre = a[0];
  728. if (!d.ContainsKey("id"))
  729. throw new Exception("Votelink: no id attribute");
  730. var id = d["id"];
  731. var url = VoteLinkUrl(text, CmsHost, emailqueueto, list, tag, id, msg, confirm, smallgroup, pre);
  732. text = text.Replace(tag, @"<a href=""{0}"">{1}</a>".Fmt(url, inside));
  733. match = match.NextMatch();
  734. }
  735. return text;
  736. }
  737. private string DoRegisterTag2(string text, string CmsHost, EmailQueueTo emailqueueto)
  738. {
  739. var list = new Dictionary<string, OneTimeLink>();
  740. const string VoteLinkRE = @"&lt;registertag .*?&gt;(?<inside>.+?)&lt;/registertag&gt;";
  741. var re = new Regex(VoteLinkRE, RegexOptions.Singleline | RegexOptions.Multiline);
  742. var match = re.Match(text);
  743. while (match.Success)
  744. {
  745. var tag = match.Value;
  746. var inside = HttpUtility.HtmlDecode(match.Groups["inside"].Value);
  747. var doc = new HtmlDocument();
  748. doc.LoadHtml(tag);
  749. var ele = doc.DocumentNode.Element("registertag");
  750. var d = ele.Attributes.ToDictionary(aa => aa.Name.ToString(), aa => aa.Value);
  751. if (!d.ContainsKey("id"))
  752. throw new Exception("RegisterTag: no id attribute");
  753. var id = d["id"];
  754. var url = RegisterTagUrl(text, CmsHost, emailqueueto, list, tag, id);
  755. text = text.Replace(tag, @"<a href=""{0}"">{1}</a>".Fmt(url, inside));
  756. match = match.NextMatch();
  757. }
  758. return text;
  759. }
  760. private string DoRegisterTag(string text, string CmsHost, EmailQueueTo emailqueueto)
  761. {
  762. var list = new Dictionary<string, OneTimeLink>();
  763. const string VoteLinkRE = @"<registertag[^>]*>(?<inside>.+?)</registertag>";
  764. var re = new Regex(VoteLinkRE, RegexOptions.Singleline | RegexOptions.Multiline);
  765. var match = re.Match(text);
  766. while (match.Success)
  767. {
  768. var tag = match.Value;
  769. var inside = match.Groups["inside"].Value;
  770. var doc = new HtmlDocument();
  771. doc.LoadHtml(tag);
  772. var ele = doc.DocumentNode.Element("registertag");
  773. var d = ele.Attributes.ToDictionary(aa => aa.Name.ToString(), aa => aa.Value);
  774. if (!d.ContainsKey("id"))
  775. throw new Exception("RegisterTag: no id attribute");
  776. var id = d["id"];
  777. var url = RegisterTagUrl(text, CmsHost, emailqueueto, list, tag, id);
  778. text = text.Replace(tag, @"<a href=""{0}"">{1}</a>".Fmt(url, inside));
  779. match = match.NextMatch();
  780. }
  781. return text;
  782. }
  783. private string RsvpLinkUrl(
  784. string CmsHost,
  785. EmailQueueTo emailqueueto,
  786. Dictionary<string, OneTimeLink> list,
  787. string id,
  788. string smallgroup,
  789. string msg,
  790. string confirm)
  791. {
  792. var qs = "{0},{1},{2}".Fmt(id, emailqueueto.PeopleId, emailqueueto.Id);
  793. OneTimeLink ot;
  794. if (list.ContainsKey(qs))
  795. ot = list[qs];
  796. else
  797. {
  798. ot = new OneTimeLink
  799. {
  800. Id = Guid.NewGuid(),
  801. Querystring = qs
  802. };
  803. OneTimeLinks.InsertOnSubmit(ot);
  804. SubmitChanges();
  805. list.Add(qs, ot);
  806. }
  807. var url = Util.URLCombine(CmsHost, "/OnlineReg/RsvpLink/{0}?confirm={1}&smallgroup={2}&message={3}"
  808. .Fmt(ot.Id.ToCode(), confirm, smallgroup, HttpUtility.UrlEncode(msg)));
  809. return url;
  810. }
  811. private string VoteLinkUrl(string text,
  812. string CmsHost,
  813. EmailQueueTo emailqueueto,
  814. Dictionary<string, OneTimeLink> list,
  815. string votelink,
  816. string id,
  817. string msg,
  818. string confirm,
  819. string smallgroup,
  820. string pre)
  821. {
  822. var qs = "{0},{1},{2},{3}".Fmt(id, emailqueueto.PeopleId, emailqueueto.Id, pre);
  823. OneTimeLink ot;
  824. if (list.ContainsKey(qs))
  825. ot = list[qs];
  826. else
  827. {
  828. ot = new OneTimeLink
  829. {
  830. Id = Guid.NewGuid(),
  831. Querystring = qs
  832. };
  833. OneTimeLinks.InsertOnSubmit(ot);
  834. SubmitChanges();
  835. list.Add(qs, ot);
  836. }
  837. var url = Util.URLCombine(CmsHost, "/OnlineReg/VoteLink/{0}?smallgroup={1}&confirm={2}&message={3}"
  838. .Fmt(ot.Id.ToCode(), HttpUtility.UrlEncode(smallgroup), confirm, HttpUtility.UrlEncode(msg)));
  839. return url;
  840. }
  841. private string RegisterTagUrl(string text,
  842. string CmsHost,
  843. EmailQueueTo emailqueueto,
  844. Dictionary<string, OneTimeLink> list,
  845. string votelink,
  846. string id,
  847. bool showfamily = false)
  848. {
  849. var qs = "{0},{1},{2}".Fmt(id, emailqueueto.PeopleId, emailqueueto.Id);
  850. OneTimeLink ot;
  851. if (list.ContainsKey(qs))
  852. ot = list[qs];
  853. else
  854. {
  855. ot = new OneTimeLink
  856. {
  857. Id = Guid.NewGuid(),
  858. Querystring = qs
  859. };
  860. OneTimeLinks.InsertOnSubmit(ot);
  861. SubmitChanges();
  862. list.Add(qs, ot);
  863. }
  864. var url = Util.URLCombine(CmsHost, "/OnlineReg/RegisterLink/{0}".Fmt(ot.Id.ToCode()));
  865. if (showfamily)
  866. url += "?showfamily=true";
  867. return url;
  868. }
  869. public List<MailAddress> GetAddressList(Person p)
  870. {
  871. return GetAddressList(p, null);
  872. }
  873. public List<MailAddress> GetAddressList(Person p, string regemail)
  874. {
  875. var aa = new List<MailAddress>();
  876. if (p.SendEmailAddress1 ?? true)
  877. Util.AddGoodAddress(aa, p.FromEmail);
  878. if (p.SendEmailAddress2 ?? false)
  879. Util.AddGoodAddress(aa, p.FromEmail2);
  880. if (regemail.HasValue())
  881. foreach (var ad in regemail.SplitStr(",;"))
  882. Util.AddGoodAddress(aa, ad);
  883. return aa;
  884. }
  885. bool EmailMatch(string existing, string addemail)
  886. {
  887. var exist = Util.TryGetMailAddress(existing, null);
  888. var add = Util.TryGetMailAddress(addemail, null);
  889. if (add == null || exist == null)
  890. return false;
  891. var r = string.Compare(exist.Address, add.Address, true);
  892. return r == 0;
  893. }
  894. public void SendPeopleEmail(int queueid)
  895. {
  896. var emailqueue = EmailQueues.Single(ee => ee.Id == queueid);
  897. var sysFromEmail = Setting("SysFromEmail", ConfigurationManager.AppSettings["sysfromemail"]);
  898. var From = Util.FirstAddress(emailqueue.FromAddr, emailqueue.FromName);
  899. if (!emailqueue.Subject.HasValue() || !emailqueue.Body.HasValue())
  900. {
  901. Util.SendMsg(sysFromEmail, CmsHost, From,
  902. "sent emails - error", "no subject or body, no emails sent",
  903. Util.ToMailAddressList(From),
  904. emailqueue.Id, null);
  905. return;
  906. }
  907. emailqueue.Started = DateTime.Now;
  908. SubmitChanges();
  909. var q = from To in EmailQueueTos
  910. where To.Id == emailqueue.Id
  911. where To.Sent == null
  912. orderby To.PeopleId
  913. select To;
  914. foreach (var To in q)
  915. {
  916. try
  917. {
  918. var p = LoadPersonById(To.PeopleId);
  919. string text = emailqueue.Body;
  920. var aa = DoReplacements(ref text, CmsHost, p, To);
  921. var qs = "OptOut/UnSubscribe/?enc=" + Util.EncryptForUrl("{0}|{1}".Fmt(To.PeopleId, From.Address));
  922. var url = Util.URLCombine(CmsHost, qs);
  923. var link = @"<a href=""{0}"">Unsubscribe</a>".Fmt(url);
  924. text = text.Replace("{unsubscribe}", link);
  925. text = text.Replace("{Unsubscribe}", link);
  926. if (aa.Count > 0)
  927. {
  928. text = text.Replace("{toemail}", aa[0].Address);
  929. text = text.Replace("%7Btoemail%7D", aa[0].Address);
  930. }
  931. text = text.Replace("{fromemail}", From.Address);
  932. text = text.Replace("%7Bfromemail%7D", From.Address);
  933. if (Setting("sendemail", "true") != "false")
  934. {
  935. Util.SendMsg(sysFromEmail, CmsHost, From,
  936. emailqueue.Subject, text, aa, emailqueue.Id, To.PeopleId);
  937. To.Sent = DateTime.Now;
  938. SubmitChanges();
  939. }
  940. }
  941. catch (Exception ex)
  942. {
  943. Util.SendMsg(sysFromEmail, CmsHost, From,
  944. "sent emails - error: {0}".Fmt(CmsHost), ex.Message,
  945. Util.ToMailAddressList(From),
  946. emailqueue.Id, null);
  947. Util.SendMsg(sysFromEmail, CmsHost, From,
  948. "sent emails - error: {0}".Fmt(CmsHost), ex.Message,
  949. Util.SendErrorsTo(),
  950. emailqueue.Id, null);
  951. }
  952. }
  953. emailqueue.Sent = DateTime.Now;
  954. if (emailqueue.Redacted ?? false)
  955. emailqueue.Body = "redacted";
  956. else if (emailqueue.Transactional == false)
  957. {
  958. var nitems = emailqueue.EmailQueueTos.Count();
  959. if (nitems > 1)
  960. NotifySentEmails(CmsHost, From.Address, From.DisplayName,
  961. emailqueue.Subject, nitems, emailqueue.Id);
  962. }
  963. SubmitChanges();
  964. }
  965. private void NotifySentEmails(string CmsHost, string From, string FromName, string subject, int count, int id)
  966. {
  967. if (Setting("sendemail", "true") != "false")
  968. {
  969. var from = new MailAddress(From, FromName);
  970. string subj = "sent emails: " + subject;
  971. var uri = new Uri(new Uri(CmsHost), "/Manage/Emails/Details/" + id);
  972. string body = @"<a href=""{0}"">{1} emails sent</a>".Fmt(uri, count);
  973. var SysFromEmail = Setting("SysFromEmail", ConfigurationManager.AppSettings["sysfromemail"]);
  974. var SendErrorsTo = ConfigurationManager.AppSettings["senderrorsto"];
  975. SendErrorsTo = SendErrorsTo.Replace(';', ',');
  976. Util.SendMsg(SysFromEmail, CmsHost, from,
  977. subj, body, Util.ToMailAddressList(from), id, null);
  978. var host = uri.Host;
  979. Util.SendMsg(SysFromEmail, CmsHost, from,
  980. host + " " + subj, body,
  981. Util.SendErrorsTo(), id, null);
  982. }
  983. }
  984. }
  985. }