createBody)
+ {
+ if (performingUser == null) throw new ArgumentNullException("performingUser");
+ if (mailingUser == null) throw new ArgumentNullException("mailingUser");
+ if (content == null) throw new ArgumentNullException("content");
+ if (allVersions == null) throw new ArgumentNullException("allVersions");
+ if (http == null) throw new ArgumentNullException("http");
+ if (createSubject == null) throw new ArgumentNullException("createSubject");
+ if (createBody == null) throw new ArgumentNullException("createBody");
+
+ int versionCount = (allVersions.Length > 1) ? (allVersions.Length - 2) : (allVersions.Length - 1);
+ var oldDoc = _contentService.GetByVersion(allVersions[versionCount].Version);
+
+ // build summary
+ var summary = new StringBuilder();
+ var props = content.Properties.ToArray();
+ foreach (var p in props)
+ {
+ var newText = p.Value != null ? p.Value.ToString() : "";
+ var oldText = newText;
+
+ // check if something was changed and display the changes otherwise display the fields
+ if (oldDoc.Properties.Contains(p.PropertyType.Alias))
+ {
+ var oldProperty = oldDoc.Properties[p.PropertyType.Alias];
+ oldText = oldProperty.Value != null ? oldProperty.Value.ToString() : "";
+
+ // replace html with char equivalent
+ ReplaceHtmlSymbols(ref oldText);
+ ReplaceHtmlSymbols(ref newText);
+ }
+
+
+ // make sure to only highlight changes done using TinyMCE editor... other changes will be displayed using default summary
+ // TODO: We should probably allow more than just tinymce??
+ if ((p.PropertyType.DataTypeId == Guid.Parse(Constants.PropertyEditors.TinyMCEv3) || p.PropertyType.DataTypeId == Guid.Parse(Constants.PropertyEditors.TinyMCE))
+ && string.CompareOrdinal(oldText, newText) != 0)
+ {
+ summary.Append("");
+ summary.Append("| Note: | ");
+ summary.Append(
+ " Red for deleted characters Yellow for inserted characters | ");
+ summary.Append("
");
+ summary.Append("");
+ summary.Append("| New " +
+ p.PropertyType.Name + " | ");
+ summary.Append("" +
+ ReplaceLinks(CompareText(oldText, newText, true, false, "", string.Empty), http.Request) +
+ " | ");
+ summary.Append("
");
+ summary.Append("");
+ summary.Append("| Old " +
+ p.PropertyType.Name + " | ");
+ summary.Append("" +
+ ReplaceLinks(CompareText(newText, oldText, true, false, "", string.Empty), http.Request) +
+ " | ");
+ summary.Append("
");
+ }
+ else
+ {
+ summary.Append("");
+ summary.Append("| " +
+ p.PropertyType.Name + " | ");
+ summary.Append("" + newText + " | ");
+ summary.Append("
");
+ }
+ summary.Append(
+ "| |
");
+ }
+
+ string protocol = GlobalSettings.UseSSL ? "https" : "http";
+
+
+ string[] subjectVars = {
+ http.Request.ServerVariables["SERVER_NAME"] + ":" +
+ http.Request.Url.Port +
+ IOHelper.ResolveUrl(SystemDirectories.Umbraco),
+ actionName,
+ content.Name
+ };
+ string[] bodyVars = {
+ mailingUser.Name,
+ actionName,
+ content.Name,
+ performingUser.Name,
+ http.Request.ServerVariables["SERVER_NAME"] + ":" + http.Request.Url.Port + IOHelper.ResolveUrl(SystemDirectories.Umbraco),
+ content.Id.ToString(CultureInfo.InvariantCulture), summary.ToString(),
+ string.Format("{2}://{0}/{1}",
+ http.Request.ServerVariables["SERVER_NAME"] + ":" + http.Request.Url.Port,
+ //TODO: RE-enable this so we can have a nice url
+ /*umbraco.library.NiceUrl(documentObject.Id))*/
+ content.Id + ".aspx",
+ protocol)
+
+ };
+
+ // create the mail message
+ var mail = new MailMessage(UmbracoSettings.NotificationEmailSender, mailingUser.Email);
+
+ // populate the message
+ mail.Subject = createSubject(mailingUser, subjectVars);
+ //mail.Subject = ui.Text("notifications", "mailSubject", subjectVars, mailingUser);
+ if (UmbracoSettings.NotificationDisableHtmlEmail)
+ {
+ mail.IsBodyHtml = false;
+ //mail.Body = ui.Text("notifications", "mailBody", bodyVars, mailingUser);
+ mail.Body = createBody(mailingUser, bodyVars);
+ }
+ else
+ {
+ mail.IsBodyHtml = true;
+ mail.Body =
+ @"
+
+
+" + createBody(mailingUser, bodyVars);
+ //ui.Text("notifications", "mailBodyHtml", bodyVars, mailingUser) + "";
+ }
+
+ // nh, issue 30724. Due to hardcoded http strings in resource files, we need to check for https replacements here
+ // adding the server name to make sure we don't replace external links
+ if (GlobalSettings.UseSSL && string.IsNullOrEmpty(mail.Body) == false)
+ {
+ string serverName = http.Request.ServerVariables["SERVER_NAME"];
+ mail.Body = mail.Body.Replace(
+ string.Format("http://{0}", serverName),
+ string.Format("https://{0}", serverName));
+ }
+
+
+ // send it asynchronously, we don't want to got up all of the request time to send emails!
+ ThreadPool.QueueUserWorkItem(state =>
+ {
+ try
+ {
+ var sender = new SmtpClient();
+ sender.Send(mail);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.Error("An error occurred sending notification", ex);
+ }
+ });
+ }
+
+ private static string ReplaceLinks(string text, HttpRequestBase request)
+ {
+ string domain = GlobalSettings.UseSSL ? "https://" : "http://";
+ domain += request.ServerVariables["SERVER_NAME"] + ":" + request.Url.Port + "/";
+ text = text.Replace("href=\"/", "href=\"" + domain);
+ text = text.Replace("src=\"/", "src=\"" + domain);
+ return text;
+ }
+
+ ///
+ /// Replaces the HTML symbols with the character equivalent.
+ ///
+ /// The old string.
+ private static void ReplaceHtmlSymbols(ref string oldString)
+ {
+ oldString = oldString.Replace(" ", " ");
+ oldString = oldString.Replace("’", "'");
+ oldString = oldString.Replace("&", "&");
+ oldString = oldString.Replace("“", "“");
+ oldString = oldString.Replace("”", "”");
+ oldString = oldString.Replace(""", "\"");
+ }
+
+ ///
+ /// Compares the text.
+ ///
+ /// The old text.
+ /// The new text.
+ /// if set to true [display inserted text].
+ /// if set to true [display deleted text].
+ /// The inserted style.
+ /// The deleted style.
+ ///
+ private static string CompareText(string oldText, string newText, bool displayInsertedText,
+ bool displayDeletedText, string insertedStyle, string deletedStyle)
+ {
+ var sb = new StringBuilder();
+ var diffs = Diff.DiffText1(oldText, newText);
+
+ int pos = 0;
+ for (int n = 0; n < diffs.Length; n++)
+ {
+ Diff.Item it = diffs[n];
+
+ // write unchanged chars
+ while ((pos < it.StartB) && (pos < newText.Length))
+ {
+ sb.Append(newText[pos]);
+ pos++;
+ } // while
+
+ // write deleted chars
+ if (displayDeletedText && it.DeletedA > 0)
+ {
+ sb.Append(deletedStyle);
+ for (int m = 0; m < it.DeletedA; m++)
+ {
+ sb.Append(oldText[it.StartA + m]);
+ } // for
+ sb.Append("");
+ }
+
+ // write inserted chars
+ if (displayInsertedText && pos < it.StartB + it.InsertedB)
+ {
+ sb.Append(insertedStyle);
+ while (pos < it.StartB + it.InsertedB)
+ {
+ sb.Append(newText[pos]);
+ pos++;
+ } // while
+ sb.Append("");
+ } // if
+ } // while
+
+ // write rest of unchanged chars
+ while (pos < newText.Length)
+ {
+ sb.Append(newText[pos]);
+ pos++;
+ } // while
+
+ return sb.ToString();
+ }
+
+ #endregion
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Services/PackagingService.cs b/src/Umbraco.Core/Services/PackagingService.cs
index 03e0d96a59..850b26627f 100644
--- a/src/Umbraco.Core/Services/PackagingService.cs
+++ b/src/Umbraco.Core/Services/PackagingService.cs
@@ -4,6 +4,7 @@ using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
+using System.Xml;
using System.Xml.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Events;
diff --git a/src/Umbraco.Core/Services/ServiceContext.cs b/src/Umbraco.Core/Services/ServiceContext.cs
index 4bd2f433ba..ac2b8b24be 100644
--- a/src/Umbraco.Core/Services/ServiceContext.cs
+++ b/src/Umbraco.Core/Services/ServiceContext.cs
@@ -29,6 +29,7 @@ namespace Umbraco.Core.Services
private Lazy _sectionService;
private Lazy _macroService;
private Lazy _memberTypeService;
+ private Lazy _notificationService;
///
/// public ctor - will generally just be used for unit testing
@@ -101,6 +102,9 @@ namespace Umbraco.Core.Services
var provider = dbUnitOfWorkProvider;
var fileProvider = fileUnitOfWorkProvider;
+ if (_notificationService == null)
+ _notificationService = new Lazy(() => new NotificationService(provider, _userService.Value, _contentService.Value));
+
if (_serverRegistrationService == null)
_serverRegistrationService = new Lazy(() => new ServerRegistrationService(provider, repositoryFactory.Value));
@@ -153,6 +157,14 @@ namespace Umbraco.Core.Services
_tagService = new Lazy(() => new TagService(provider, repositoryFactory.Value));
}
+ ///
+ /// Gets the
+ ///
+ internal INotificationService NotificationService
+ {
+ get { return _notificationService.Value; }
+ }
+
///
/// Gets the
///
diff --git a/src/Umbraco.Core/Strings/Diff.cs b/src/Umbraco.Core/Strings/Diff.cs
new file mode 100644
index 0000000000..ed381d4f6f
--- /dev/null
+++ b/src/Umbraco.Core/Strings/Diff.cs
@@ -0,0 +1,510 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Umbraco.Core.Strings
+{
+ ///
+ /// This Class implements the Difference Algorithm published in
+ /// "An O(ND) Difference Algorithm and its Variations" by Eugene Myers
+ /// Algorithmica Vol. 1 No. 2, 1986, p 251.
+ ///
+ /// The algorithm itself is comparing 2 arrays of numbers so when comparing 2 text documents
+ /// each line is converted into a (hash) number. See DiffText().
+ ///
+ /// diff.cs: A port of the algorithm to C#
+ /// Copyright (c) by Matthias Hertel, http://www.mathertel.de
+ /// This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
+ ///
+ internal class Diff
+ {
+ /// Data on one input file being compared.
+ ///
+ internal class DiffData
+ {
+
+ /// Number of elements (lines).
+ internal int Length;
+
+ /// Buffer of numbers that will be compared.
+ internal int[] Data;
+
+ ///
+ /// Array of booleans that flag for modified data.
+ /// This is the result of the diff.
+ /// This means deletedA in the first Data or inserted in the second Data.
+ ///
+ internal bool[] Modified;
+
+ ///
+ /// Initialize the Diff-Data buffer.
+ ///
+ /// reference to the buffer
+ internal DiffData(int[] initData)
+ {
+ Data = initData;
+ Length = initData.Length;
+ Modified = new bool[Length + 2];
+ } // DiffData
+
+ } // class DiffData
+
+ /// details of one difference.
+ public struct Item
+ {
+ /// Start Line number in Data A.
+ public int StartA;
+ /// Start Line number in Data B.
+ public int StartB;
+
+ /// Number of changes in Data A.
+ public int DeletedA;
+ /// Number of changes in Data B.
+ public int InsertedB;
+ } // Item
+
+ ///
+ /// Shortest Middle Snake Return Data
+ ///
+ private struct Smsrd
+ {
+ internal int X, Y;
+ // internal int u, v; // 2002.09.20: no need for 2 points
+ }
+
+ ///
+ /// Find the difference in 2 texts, comparing by textlines.
+ ///
+ /// A-version of the text (usualy the old one)
+ /// B-version of the text (usualy the new one)
+ /// Returns a array of Items that describe the differences.
+ public static Item[] DiffText(string textA, string textB)
+ {
+ return (DiffText(textA, textB, false, false, false));
+ } // DiffText
+
+ ///
+ /// Find the difference in 2 texts, comparing by textlines.
+ /// This method uses the DiffInt internally by 1st converting the string into char codes
+ /// then uses the diff int method
+ ///
+ /// A-version of the text (usualy the old one)
+ /// B-version of the text (usualy the new one)
+ /// Returns a array of Items that describe the differences.
+ public static Item[] DiffText1(string textA, string textB)
+ {
+ return DiffInt(DiffCharCodes(textA, false), DiffCharCodes(textB, false));
+ }
+
+
+ ///
+ /// Find the difference in 2 text documents, comparing by textlines.
+ /// The algorithm itself is comparing 2 arrays of numbers so when comparing 2 text documents
+ /// each line is converted into a (hash) number. This hash-value is computed by storing all
+ /// textlines into a common hashtable so i can find dublicates in there, and generating a
+ /// new number each time a new textline is inserted.
+ ///
+ /// A-version of the text (usualy the old one)
+ /// B-version of the text (usualy the new one)
+ /// When set to true, all leading and trailing whitespace characters are stripped out before the comparation is done.
+ /// When set to true, all whitespace characters are converted to a single space character before the comparation is done.
+ /// When set to true, all characters are converted to their lowercase equivivalence before the comparation is done.
+ /// Returns a array of Items that describe the differences.
+ public static Item[] DiffText(string textA, string textB, bool trimSpace, bool ignoreSpace, bool ignoreCase)
+ {
+ // prepare the input-text and convert to comparable numbers.
+ var h = new Hashtable(textA.Length + textB.Length);
+
+ // The A-Version of the data (original data) to be compared.
+ var dataA = new DiffData(DiffCodes(textA, h, trimSpace, ignoreSpace, ignoreCase));
+
+ // The B-Version of the data (modified data) to be compared.
+ var dataB = new DiffData(DiffCodes(textB, h, trimSpace, ignoreSpace, ignoreCase));
+
+ h = null; // free up hashtable memory (maybe)
+
+ var max = dataA.Length + dataB.Length + 1;
+ // vector for the (0,0) to (x,y) search
+ var downVector = new int[2 * max + 2];
+ // vector for the (u,v) to (N,M) search
+ var upVector = new int[2 * max + 2];
+
+ Lcs(dataA, 0, dataA.Length, dataB, 0, dataB.Length, downVector, upVector);
+
+ Optimize(dataA);
+ Optimize(dataB);
+ return CreateDiffs(dataA, dataB);
+ } // DiffText
+
+
+ ///
+ /// Diffs the char codes.
+ ///
+ /// A text.
+ /// if set to true [ignore case].
+ ///
+ private static int[] DiffCharCodes(string aText, bool ignoreCase)
+ {
+ if (ignoreCase)
+ aText = aText.ToUpperInvariant();
+
+ var codes = new int[aText.Length];
+
+ for (int n = 0; n < aText.Length; n++)
+ codes[n] = (int)aText[n];
+
+ return (codes);
+ } // DiffCharCodes
+
+ ///
+ /// If a sequence of modified lines starts with a line that contains the same content
+ /// as the line that appends the changes, the difference sequence is modified so that the
+ /// appended line and not the starting line is marked as modified.
+ /// This leads to more readable diff sequences when comparing text files.
+ ///
+ /// A Diff data buffer containing the identified changes.
+ private static void Optimize(DiffData data)
+ {
+ var startPos = 0;
+ while (startPos < data.Length)
+ {
+ while ((startPos < data.Length) && (data.Modified[startPos] == false))
+ startPos++;
+ int endPos = startPos;
+ while ((endPos < data.Length) && (data.Modified[endPos] == true))
+ endPos++;
+
+ if ((endPos < data.Length) && (data.Data[startPos] == data.Data[endPos]))
+ {
+ data.Modified[startPos] = false;
+ data.Modified[endPos] = true;
+ }
+ else
+ {
+ startPos = endPos;
+ } // if
+ } // while
+ } // Optimize
+
+
+ ///
+ /// Find the difference in 2 arrays of integers.
+ ///
+ /// A-version of the numbers (usualy the old one)
+ /// B-version of the numbers (usualy the new one)
+ /// Returns a array of Items that describe the differences.
+ public static Item[] DiffInt(int[] arrayA, int[] arrayB)
+ {
+ // The A-Version of the data (original data) to be compared.
+ var dataA = new DiffData(arrayA);
+
+ // The B-Version of the data (modified data) to be compared.
+ var dataB = new DiffData(arrayB);
+
+ var max = dataA.Length + dataB.Length + 1;
+ // vector for the (0,0) to (x,y) search
+ var downVector = new int[2 * max + 2];
+ // vector for the (u,v) to (N,M) search
+ var upVector = new int[2 * max + 2];
+
+ Lcs(dataA, 0, dataA.Length, dataB, 0, dataB.Length, downVector, upVector);
+ return CreateDiffs(dataA, dataB);
+ } // Diff
+
+
+ ///
+ /// This function converts all textlines of the text into unique numbers for every unique textline
+ /// so further work can work only with simple numbers.
+ ///
+ /// the input text
+ /// This extern initialized hashtable is used for storing all ever used textlines.
+ /// ignore leading and trailing space characters
+ ///
+ ///
+ /// a array of integers.
+ private static int[] DiffCodes(string aText, IDictionary h, bool trimSpace, bool ignoreSpace, bool ignoreCase)
+ {
+ // get all codes of the text
+ var lastUsedCode = h.Count;
+
+ // strip off all cr, only use lf as textline separator.
+ aText = aText.Replace("\r", "");
+ var lines = aText.Split('\n');
+
+ var codes = new int[lines.Length];
+
+ for (int i = 0; i < lines.Length; ++i)
+ {
+ string s = lines[i];
+ if (trimSpace)
+ s = s.Trim();
+
+ if (ignoreSpace)
+ {
+ s = Regex.Replace(s, "\\s+", " "); // TODO: optimization: faster blank removal.
+ }
+
+ if (ignoreCase)
+ s = s.ToLower();
+
+ object aCode = h[s];
+ if (aCode == null)
+ {
+ lastUsedCode++;
+ h[s] = lastUsedCode;
+ codes[i] = lastUsedCode;
+ }
+ else
+ {
+ codes[i] = (int)aCode;
+ } // if
+ } // for
+ return (codes);
+ } // DiffCodes
+
+
+ ///
+ /// This is the algorithm to find the Shortest Middle Snake (SMS).
+ ///
+ /// sequence A
+ /// lower bound of the actual range in DataA
+ /// upper bound of the actual range in DataA (exclusive)
+ /// sequence B
+ /// lower bound of the actual range in DataB
+ /// upper bound of the actual range in DataB (exclusive)
+ /// a vector for the (0,0) to (x,y) search. Passed as a parameter for speed reasons.
+ /// a vector for the (u,v) to (N,M) search. Passed as a parameter for speed reasons.
+ /// a MiddleSnakeData record containing x,y and u,v
+ private static Smsrd Sms(DiffData dataA, int lowerA, int upperA, DiffData dataB, int lowerB, int upperB, int[] downVector, int[] upVector)
+ {
+ int max = dataA.Length + dataB.Length + 1;
+
+ int downK = lowerA - lowerB; // the k-line to start the forward search
+ int upK = upperA - upperB; // the k-line to start the reverse search
+
+ int delta = (upperA - lowerA) - (upperB - lowerB);
+ bool oddDelta = (delta & 1) != 0;
+
+ // The vectors in the publication accepts negative indexes. the vectors implemented here are 0-based
+ // and are access using a specific offset: UpOffset UpVector and DownOffset for DownVektor
+ int downOffset = max - downK;
+ int upOffset = max - upK;
+
+ int maxD = ((upperA - lowerA + upperB - lowerB) / 2) + 1;
+
+ // Debug.Write(2, "SMS", String.Format("Search the box: A[{0}-{1}] to B[{2}-{3}]", LowerA, UpperA, LowerB, UpperB));
+
+ // init vectors
+ downVector[downOffset + downK + 1] = lowerA;
+ upVector[upOffset + upK - 1] = upperA;
+
+ for (int d = 0; d <= maxD; d++)
+ {
+
+ // Extend the forward path.
+ Smsrd ret;
+ for (int k = downK - d; k <= downK + d; k += 2)
+ {
+ // Debug.Write(0, "SMS", "extend forward path " + k.ToString());
+
+ // find the only or better starting point
+ int x, y;
+ if (k == downK - d)
+ {
+ x = downVector[downOffset + k + 1]; // down
+ }
+ else
+ {
+ x = downVector[downOffset + k - 1] + 1; // a step to the right
+ if ((k < downK + d) && (downVector[downOffset + k + 1] >= x))
+ x = downVector[downOffset + k + 1]; // down
+ }
+ y = x - k;
+
+ // find the end of the furthest reaching forward D-path in diagonal k.
+ while ((x < upperA) && (y < upperB) && (dataA.Data[x] == dataB.Data[y]))
+ {
+ x++; y++;
+ }
+ downVector[downOffset + k] = x;
+
+ // overlap ?
+ if (oddDelta && (upK - d < k) && (k < upK + d))
+ {
+ if (upVector[upOffset + k] <= downVector[downOffset + k])
+ {
+ ret.X = downVector[downOffset + k];
+ ret.Y = downVector[downOffset + k] - k;
+ // ret.u = UpVector[UpOffset + k]; // 2002.09.20: no need for 2 points
+ // ret.v = UpVector[UpOffset + k] - k;
+ return (ret);
+ } // if
+ } // if
+
+ } // for k
+
+ // Extend the reverse path.
+ for (int k = upK - d; k <= upK + d; k += 2)
+ {
+ // Debug.Write(0, "SMS", "extend reverse path " + k.ToString());
+
+ // find the only or better starting point
+ int x, y;
+ if (k == upK + d)
+ {
+ x = upVector[upOffset + k - 1]; // up
+ }
+ else
+ {
+ x = upVector[upOffset + k + 1] - 1; // left
+ if ((k > upK - d) && (upVector[upOffset + k - 1] < x))
+ x = upVector[upOffset + k - 1]; // up
+ } // if
+ y = x - k;
+
+ while ((x > lowerA) && (y > lowerB) && (dataA.Data[x - 1] == dataB.Data[y - 1]))
+ {
+ x--; y--; // diagonal
+ }
+ upVector[upOffset + k] = x;
+
+ // overlap ?
+ if (!oddDelta && (downK - d <= k) && (k <= downK + d))
+ {
+ if (upVector[upOffset + k] <= downVector[downOffset + k])
+ {
+ ret.X = downVector[downOffset + k];
+ ret.Y = downVector[downOffset + k] - k;
+ // ret.u = UpVector[UpOffset + k]; // 2002.09.20: no need for 2 points
+ // ret.v = UpVector[UpOffset + k] - k;
+ return (ret);
+ } // if
+ } // if
+
+ } // for k
+
+ } // for D
+
+ throw new ApplicationException("the algorithm should never come here.");
+ } // SMS
+
+
+ ///
+ /// This is the divide-and-conquer implementation of the longes common-subsequence (LCS)
+ /// algorithm.
+ /// The published algorithm passes recursively parts of the A and B sequences.
+ /// To avoid copying these arrays the lower and upper bounds are passed while the sequences stay constant.
+ ///
+ /// sequence A
+ /// lower bound of the actual range in DataA
+ /// upper bound of the actual range in DataA (exclusive)
+ /// sequence B
+ /// lower bound of the actual range in DataB
+ /// upper bound of the actual range in DataB (exclusive)
+ /// a vector for the (0,0) to (x,y) search. Passed as a parameter for speed reasons.
+ /// a vector for the (u,v) to (N,M) search. Passed as a parameter for speed reasons.
+ private static void Lcs(DiffData dataA, int lowerA, int upperA, DiffData dataB, int lowerB, int upperB, int[] downVector, int[] upVector)
+ {
+ // Debug.Write(2, "LCS", String.Format("Analyse the box: A[{0}-{1}] to B[{2}-{3}]", LowerA, UpperA, LowerB, UpperB));
+
+ // Fast walkthrough equal lines at the start
+ while (lowerA < upperA && lowerB < upperB && dataA.Data[lowerA] == dataB.Data[lowerB])
+ {
+ lowerA++; lowerB++;
+ }
+
+ // Fast walkthrough equal lines at the end
+ while (lowerA < upperA && lowerB < upperB && dataA.Data[upperA - 1] == dataB.Data[upperB - 1])
+ {
+ --upperA; --upperB;
+ }
+
+ if (lowerA == upperA)
+ {
+ // mark as inserted lines.
+ while (lowerB < upperB)
+ dataB.Modified[lowerB++] = true;
+
+ }
+ else if (lowerB == upperB)
+ {
+ // mark as deleted lines.
+ while (lowerA < upperA)
+ dataA.Modified[lowerA++] = true;
+
+ }
+ else
+ {
+ // Find the middle snakea and length of an optimal path for A and B
+ Smsrd smsrd = Sms(dataA, lowerA, upperA, dataB, lowerB, upperB, downVector, upVector);
+ // Debug.Write(2, "MiddleSnakeData", String.Format("{0},{1}", smsrd.x, smsrd.y));
+
+ // The path is from LowerX to (x,y) and (x,y) to UpperX
+ Lcs(dataA, lowerA, smsrd.X, dataB, lowerB, smsrd.Y, downVector, upVector);
+ Lcs(dataA, smsrd.X, upperA, dataB, smsrd.Y, upperB, downVector, upVector); // 2002.09.20: no need for 2 points
+ }
+ } // LCS()
+
+
+ /// Scan the tables of which lines are inserted and deleted,
+ /// producing an edit script in forward order.
+ ///
+ /// dynamic array
+ private static Item[] CreateDiffs(DiffData dataA, DiffData dataB)
+ {
+ ArrayList a = new ArrayList();
+ Item aItem;
+ Item[] result;
+
+ int lineA = 0;
+ int lineB = 0;
+ while (lineA < dataA.Length || lineB < dataB.Length)
+ {
+ if ((lineA < dataA.Length) && (!dataA.Modified[lineA])
+ && (lineB < dataB.Length) && (!dataB.Modified[lineB]))
+ {
+ // equal lines
+ lineA++;
+ lineB++;
+
+ }
+ else
+ {
+ // maybe deleted and/or inserted lines
+ int startA = lineA;
+ int startB = lineB;
+
+ while (lineA < dataA.Length && (lineB >= dataB.Length || dataA.Modified[lineA]))
+ // while (LineA < DataA.Length && DataA.modified[LineA])
+ lineA++;
+
+ while (lineB < dataB.Length && (lineA >= dataA.Length || dataB.Modified[lineB]))
+ // while (LineB < DataB.Length && DataB.modified[LineB])
+ lineB++;
+
+ if ((startA < lineA) || (startB < lineB))
+ {
+ // store a new difference-item
+ aItem = new Item();
+ aItem.StartA = startA;
+ aItem.StartB = startB;
+ aItem.DeletedA = lineA - startA;
+ aItem.InsertedB = lineB - startB;
+ a.Add(aItem);
+ } // if
+ } // if
+ } // while
+
+ result = new Item[a.Count];
+ a.CopyTo(result);
+
+ return (result);
+ }
+
+ } // class Diff
+
+
+}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index ad49b46b54..45170dfc51 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -1011,6 +1011,7 @@
+
diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
index eaa279c342..f97ff2ca1e 100644
--- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
+++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
@@ -115,15 +115,15 @@
False
..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll
-
+
False
..\packages\ClientDependency.1.7.1.1\lib\ClientDependency.Core.dll
-
+
False
..\packages\ClientDependency-Mvc.1.7.0.4\lib\ClientDependency.Core.Mvc.dll
-
+
False
..\packages\Examine.0.1.52.2941\lib\Examine.dll
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 94e3ea315b..b829f6cc7a 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -102,7 +102,7 @@
..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll
-
+
False
..\packages\ClientDependency.1.7.1.1\lib\ClientDependency.Core.dll
@@ -110,7 +110,7 @@
False
..\packages\xmlrpcnet.2.5.0\lib\net20\CookComputing.XmlRpcV2.dll
-
+
False
..\packages\Examine.0.1.52.2941\lib\Examine.dll
diff --git a/src/UmbracoExamine.Azure/UmbracoExamine.Azure.csproj b/src/UmbracoExamine.Azure/UmbracoExamine.Azure.csproj
index db7b95bd7a..22792d6aa0 100644
--- a/src/UmbracoExamine.Azure/UmbracoExamine.Azure.csproj
+++ b/src/UmbracoExamine.Azure/UmbracoExamine.Azure.csproj
@@ -40,11 +40,11 @@
..\packages\AzureDirectory.1.0.5\lib\AzureDirectory.dll
-
+
False
..\packages\Examine.0.1.52.2941\lib\Examine.dll
-
+
False
..\packages\Examine.Azure.0.1.51.2941\lib\Examine.Azure.dll
diff --git a/src/UmbracoExamine.PDF.Azure/UmbracoExamine.PDF.Azure.csproj b/src/UmbracoExamine.PDF.Azure/UmbracoExamine.PDF.Azure.csproj
index d17a4c4921..203fc935dc 100644
--- a/src/UmbracoExamine.PDF.Azure/UmbracoExamine.PDF.Azure.csproj
+++ b/src/UmbracoExamine.PDF.Azure/UmbracoExamine.PDF.Azure.csproj
@@ -40,11 +40,11 @@
..\packages\AzureDirectory.1.0.5\lib\AzureDirectory.dll
-
+
False
..\packages\Examine.0.1.52.2941\lib\Examine.dll
-
+
False
..\packages\Examine.Azure.0.1.51.2941\lib\Examine.Azure.dll
diff --git a/src/UmbracoExamine.PDF/UmbracoExamine.PDF.csproj b/src/UmbracoExamine.PDF/UmbracoExamine.PDF.csproj
index 6bdc3d3666..aed13c7c13 100644
--- a/src/UmbracoExamine.PDF/UmbracoExamine.PDF.csproj
+++ b/src/UmbracoExamine.PDF/UmbracoExamine.PDF.csproj
@@ -46,7 +46,7 @@
false
-
+
False
..\packages\Examine.0.1.52.2941\lib\Examine.dll
diff --git a/src/UmbracoExamine/UmbracoExamine.csproj b/src/UmbracoExamine/UmbracoExamine.csproj
index c180189a64..7bcb270bce 100644
--- a/src/UmbracoExamine/UmbracoExamine.csproj
+++ b/src/UmbracoExamine/UmbracoExamine.csproj
@@ -82,7 +82,7 @@
..\Solution Items\TheFARM-Public.snk
-
+
False
..\packages\Examine.0.1.52.2941\lib\Examine.dll
diff --git a/src/umbraco.cms/businesslogic/utilities/Diff.cs b/src/umbraco.cms/businesslogic/utilities/Diff.cs
index 62397f2495..3aa159de7e 100644
--- a/src/umbraco.cms/businesslogic/utilities/Diff.cs
+++ b/src/umbraco.cms/businesslogic/utilities/Diff.cs
@@ -3,6 +3,8 @@ using System.Collections;
using System.Text;
using System.Text.RegularExpressions;
+//TODO: We've alraedy moved most of this logic to Core.Strings - need to review this as it has slightly more functionality but should be moved to core and obsoleted!
+
namespace umbraco.cms.businesslogic.utilities {
///
/// This Class implements the Difference Algorithm published in
diff --git a/src/umbraco.cms/businesslogic/workflow/Diff.cs b/src/umbraco.cms/businesslogic/workflow/Diff.cs
index e4e4d505a9..39cbc1d2c3 100644
--- a/src/umbraco.cms/businesslogic/workflow/Diff.cs
+++ b/src/umbraco.cms/businesslogic/workflow/Diff.cs
@@ -18,7 +18,7 @@ namespace umbraco.cms.businesslogic.workflow
/// Copyright (c) by Matthias Hertel, http://www.mathertel.de
/// This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx
///
-
+ [Obsolete("This class will be removed from the codebase in the future")]
public class Diff
{
@@ -489,6 +489,7 @@ namespace umbraco.cms.businesslogic.workflow
/// Data on one input file being compared.
///
+ [Obsolete("This class will be removed from the codebase in the future, logic has moved to the Core project")]
internal class DiffData
{
diff --git a/src/umbraco.cms/businesslogic/workflow/Notification.cs b/src/umbraco.cms/businesslogic/workflow/Notification.cs
index b272491362..4a0afbb38d 100644
--- a/src/umbraco.cms/businesslogic/workflow/Notification.cs
+++ b/src/umbraco.cms/businesslogic/workflow/Notification.cs
@@ -72,138 +72,19 @@ namespace umbraco.cms.businesslogic.workflow
}
}
- ///TODO: Include update with html mail notification and document contents
+ //TODO: Include update with html mail notification and document contents
private static void SendNotification(User performingUser, User mailingUser, Document documentObject, IAction action)
{
- // retrieve previous version of the document
- DocumentVersionList[] versions = documentObject.GetVersions();
- int versionCount = (versions.Length > 1) ? (versions.Length - 2) : (versions.Length - 1);
- var oldDoc = new Document(documentObject.Id, versions[versionCount].Version);
+ var nService = ApplicationContext.Current.Services.NotificationService;
+ var pUser = ApplicationContext.Current.Services.UserService.GetById(performingUser.Id);
- // build summary
- var summary = new StringBuilder();
- var props = documentObject.GenericProperties;
- foreach (Property p in props)
- {
- // check if something was changed and display the changes otherwise display the fields
- Property oldProperty = oldDoc.getProperty(p.PropertyType.Alias);
- string oldText = oldProperty.Value != null ? oldProperty.Value.ToString() : "";
- string newText = p.Value != null ? p.Value.ToString() : "";
-
- // replace html with char equivalent
- ReplaceHtmlSymbols(ref oldText);
- ReplaceHtmlSymbols(ref newText);
-
- // make sure to only highlight changes done using TinyMCE editor... other changes will be displayed using default summary
- //TODO PPH: Had to change this, as a reference to the editorcontrols is not allowed, so a string comparison is the only way, this should be a DIFF or something instead..
- if (p.PropertyType.DataTypeDefinition.DataType.ToString() ==
- "umbraco.editorControls.tinymce.TinyMCEDataType" &&
- string.CompareOrdinal(oldText, newText) != 0)
- {
- summary.Append("");
- summary.Append("| Note: | ");
- summary.Append(
- " Red for deleted characters Yellow for inserted characters | ");
- summary.Append("
");
- summary.Append("");
- summary.Append("| New " +
- p.PropertyType.Name + " | ");
- summary.Append("" +
- ReplaceLinks(CompareText(oldText, newText, true, false,
- "", string.Empty)) +
- " | ");
- summary.Append("
");
- summary.Append("");
- summary.Append("| Old " +
- oldProperty.PropertyType.Name + " | ");
- summary.Append("" +
- ReplaceLinks(CompareText(newText, oldText, true, false,
- "", string.Empty)) +
- " | ");
- summary.Append("
");
- }
- else
- {
- summary.Append("");
- summary.Append("| " +
- p.PropertyType.Name + " | ");
- summary.Append("" + newText + " | ");
- summary.Append("
");
- }
- summary.Append(
- "| |
");
- }
-
- string protocol = GlobalSettings.UseSSL ? "https" : "http";
-
-
- string[] subjectVars = {
- HttpContext.Current.Request.ServerVariables["SERVER_NAME"] + ":" +
- HttpContext.Current.Request.Url.Port +
- IOHelper.ResolveUrl(SystemDirectories.Umbraco), ui.Text(action.Alias)
- ,
- documentObject.Text
- };
- string[] bodyVars = {
- mailingUser.Name, ui.Text(action.Alias), documentObject.Text, performingUser.Name,
- HttpContext.Current.Request.ServerVariables["SERVER_NAME"] + ":" +
- HttpContext.Current.Request.Url.Port +
- IOHelper.ResolveUrl(SystemDirectories.Umbraco),
- documentObject.Id.ToString(), summary.ToString(),
- String.Format("{2}://{0}/{1}",
- HttpContext.Current.Request.ServerVariables["SERVER_NAME"] + ":" +
- HttpContext.Current.Request.Url.Port,
- /*umbraco.library.NiceUrl(documentObject.Id))*/
- documentObject.Id + ".aspx",
- protocol)
- //TODO: PPH removed the niceURL reference... cms.dll cannot reference the presentation project...
- //TODO: This should be moved somewhere else..
- };
-
- // create the mail message
- var mail = new MailMessage(UmbracoConfig.For.UmbracoSettings().Content.NotificationEmailAddress, mailingUser.Email);
-
- // populate the message
- mail.Subject = ui.Text("notifications", "mailSubject", subjectVars, mailingUser);
- if (UmbracoConfig.For.UmbracoSettings().Content.DisableHtmlEmail)
- {
- mail.IsBodyHtml = false;
- mail.Body = ui.Text("notifications", "mailBody", bodyVars, mailingUser);
- }
- else
- {
- mail.IsBodyHtml = true;
- mail.Body =
- @"
-
-
-" +
- ui.Text("notifications", "mailBodyHtml", bodyVars, mailingUser) + "";
- }
-
- // nh, issue 30724. Due to hardcoded http strings in resource files, we need to check for https replacements here
- // adding the server name to make sure we don't replace external links
- if (GlobalSettings.UseSSL && string.IsNullOrEmpty(mail.Body) == false)
- {
- string serverName = HttpContext.Current.Request.ServerVariables["SERVER_NAME"];
- mail.Body = mail.Body.Replace(
- string.Format("http://{0}", serverName),
- string.Format("https://{0}", serverName));
- }
-
- // send it
- var sender = new SmtpClient();
- sender.Send(mail);
- }
-
- private static string ReplaceLinks(string text)
- {
- string domain = GlobalSettings.UseSSL ? "https://" : "http://";
- domain += HttpContext.Current.Request.ServerVariables["SERVER_NAME"] + ":" +
- HttpContext.Current.Request.Url.Port + "/";
- text = text.Replace("href=\"/", "href=\"" + domain);
- text = text.Replace("src=\"/", "src=\"" + domain);
- return text;
+ nService.SendNotifications(
+ pUser, documentObject.Content, action.Letter.ToString(CultureInfo.InvariantCulture), ui.Text(action.Alias),
+ new HttpContextWrapper(HttpContext.Current),
+ (user, strings) => ui.Text("notifications", "mailSubject", strings, mailingUser),
+ (user, strings) => UmbracoSettings.NotificationDisableHtmlEmail
+ ? ui.Text("notifications", "mailBody", strings, mailingUser)
+ : ui.Text("notifications", "mailBodyHtml", strings, mailingUser));
}
///
@@ -328,80 +209,5 @@ namespace umbraco.cms.businesslogic.workflow
MakeNew(user, node, c);
}
- ///
- /// Replaces the HTML symbols with the character equivalent.
- ///
- /// The old string.
- private static void ReplaceHtmlSymbols(ref string oldString)
- {
- oldString = oldString.Replace(" ", " ");
- oldString = oldString.Replace("’", "'");
- oldString = oldString.Replace("&", "&");
- oldString = oldString.Replace("“", "");
- oldString = oldString.Replace("”", "");
- oldString = oldString.Replace(""", "\"");
- }
-
- ///
- /// Compares the text.
- ///
- /// The old text.
- /// The new text.
- /// if set to true [display inserted text].
- /// if set to true [display deleted text].
- /// The inserted style.
- /// The deleted style.
- ///
- private static string CompareText(string oldText, string newText, bool displayInsertedText,
- bool displayDeletedText, string insertedStyle, string deletedStyle)
- {
- var sb = new StringBuilder();
- Diff.Item[] diffs = Diff.DiffText1(oldText, newText);
-
- int pos = 0;
- for (int n = 0; n < diffs.Length; n++)
- {
- Diff.Item it = diffs[n];
-
- // write unchanged chars
- while ((pos < it.StartB) && (pos < newText.Length))
- {
- sb.Append(newText[pos]);
- pos++;
- } // while
-
- // write deleted chars
- if (displayDeletedText && it.deletedA > 0)
- {
- sb.Append(deletedStyle);
- for (int m = 0; m < it.deletedA; m++)
- {
- sb.Append(oldText[it.StartA + m]);
- } // for
- sb.Append("");
- }
-
- // write inserted chars
- if (displayInsertedText && pos < it.StartB + it.insertedB)
- {
- sb.Append(insertedStyle);
- while (pos < it.StartB + it.insertedB)
- {
- sb.Append(newText[pos]);
- pos++;
- } // while
- sb.Append("");
- } // if
- } // while
-
- // write rest of unchanged chars
- while (pos < newText.Length)
- {
- sb.Append(newText[pos]);
- pos++;
- } // while
-
- return sb.ToString();
- }
}
}
\ No newline at end of file
diff --git a/src/umbraco.cms/umbraco.cms.csproj b/src/umbraco.cms/umbraco.cms.csproj
index 595e07b40d..ea9437e8a4 100644
--- a/src/umbraco.cms/umbraco.cms.csproj
+++ b/src/umbraco.cms/umbraco.cms.csproj
@@ -106,7 +106,7 @@
false
-
+
False
..\packages\ClientDependency.1.7.1.1\lib\ClientDependency.Core.dll
diff --git a/src/umbraco.controls/umbraco.controls.csproj b/src/umbraco.controls/umbraco.controls.csproj
index 9c3c80c1ac..abd0f53dce 100644
--- a/src/umbraco.controls/umbraco.controls.csproj
+++ b/src/umbraco.controls/umbraco.controls.csproj
@@ -68,7 +68,7 @@
false
-
+
False
..\packages\ClientDependency.1.7.1.1\lib\ClientDependency.Core.dll
diff --git a/src/umbraco.editorControls/umbraco.editorControls.csproj b/src/umbraco.editorControls/umbraco.editorControls.csproj
index 50aabbe197..865b574024 100644
--- a/src/umbraco.editorControls/umbraco.editorControls.csproj
+++ b/src/umbraco.editorControls/umbraco.editorControls.csproj
@@ -114,7 +114,7 @@
{651E1350-91B6-44B7-BD60-7207006D7003}
Umbraco.Web
-
+
False
..\packages\ClientDependency.1.7.1.1\lib\ClientDependency.Core.dll