/// <summary> /// Writes the exception together with some meta information to an <see cref="XmlWriter"/>. If that <see cref="XmlWriter"/> is /// null, a new instance of an <see cref="XmlWriter"/> is being created for writing into the file specified as the parameter /// <paramref name="exceptionReportFileName"/>. /// </summary> /// <remarks> /// While creating the exception file a start tag is being written for the root element. The calling method is /// responsible to write the corresponding closing tag in order to finish the file. /// </remarks> /// <param name="valueArray"> /// The value array working with while the exception has been thrown. /// </param> /// <param name="rowId"> /// The row id of the data row that caused the exception. /// </param> /// <param name="colId"> /// The col id of the data column that caused the exception. /// </param> /// <param name="newElement"> /// The element that is being processed while the exception did occure. /// </param> /// <param name="exceptionFile"> /// The <see cref="XmlWriter"/> for the exception file - if this element is NULL, a new file stream will be created. /// </param> /// <param name="exceptionReportFileName"> /// The exception report file name - in case of a null reference in the parameter <paramref name="exceptionFile"/> this file name will be used to create a new file stream for the XmlWriter. /// </param> /// <param name="ex"> /// The exception to be written to the file. /// </param> /// <returns> /// The instance of the <see cref="XmlWriter"/> that has been utilized to write the exception. /// </returns> private static XmlWriter WriteExceptionFile( string[,] valueArray, int rowId, int colId, StdElement newElement, XmlWriter exceptionFile, string exceptionReportFileName, Exception ex) { if (exceptionFile == null) { exceptionFile = XmlWriter.Create(File.AppendText(exceptionReportFileName)); if (exceptionFile != null) { exceptionFile.WriteStartDocument(true); exceptionFile.WriteStartElement("ExceptionReport"); } } if (exceptionFile != null) { exceptionFile.WriteStartElement("Exception"); exceptionFile.WriteAttributeString("PersonName", newElement.ToString()); exceptionFile.WriteAttributeString("Row", rowId.ToString(CultureInfo.InvariantCulture)); exceptionFile.WriteAttributeString("Column", colId.ToString(CultureInfo.InvariantCulture)); exceptionFile.WriteAttributeString("ExcelReference", colId.IndexToLetters() + rowId); exceptionFile.WriteElementString("CellValue", valueArray[rowId, colId]); exceptionFile.WriteElementString("Exception", ex.ToString()); exceptionFile.WriteEndElement(); } return(exceptionFile); }
/// <summary> /// Writes a single element to the list of elements /// </summary> /// <param name="list"> The list of elements the new element should be added to </param> /// <param name="element"> The new element that should be added </param> /// <param name="skipIfExisting"> If false: overwrites an existing element with the same id </param> /// <returns> True if writing was successfull, false if the entry has been skipped </returns> private static bool WriteElement(ICollection <StdElement> list, StdElement element, bool skipIfExisting) { var asContact = element as StdContact; StdElement listEntry; if (asContact != null) { listEntry = (from entry in list where entry.Id == element.Id || entry.ExternalIdentifier.Equals(asContact.ExternalIdentifier) select entry).FirstOrDefault(); } else { listEntry = (from entry in list where entry.Id == element.Id select entry).FirstOrDefault(); } if (listEntry != null) { if (skipIfExisting) { return(false); } list.Remove(listEntry); } list.Add(element); return(true); }
/// <summary> /// The match std contact. /// </summary> /// <param name="contact"> /// The contact. /// </param> /// <param name="baseline"> /// The baseline. /// </param> private static void MatchStdContact(StdElement contact, IEnumerable <StdElement> baseline) { if (contact == null) { return; } var targetId = contact.ExternalIdentifier; var corresponding = (from element in baseline where ((MatchingEntry)element).ProfileId.MatchesAny(targetId) select element). FirstOrDefault(); // if there is one with a matching profile id, // we overwrite the id if (corresponding == null) { return; } var sourceId = ((MatchingEntry)corresponding).ProfileId; foreach (var id in sourceId) { var key = id.Key; if (string.IsNullOrEmpty(targetId.GetProfileId(key))) { targetId.SetProfileId(key, id.Value); } } contact.Id = corresponding.Id; }
/// <summary> /// The write contact. /// </summary> /// <param name="con"> /// The con. /// </param> /// <param name="x"> /// The x. /// </param> /// <param name="definitions"> /// The definitions. /// </param> private static void WriteContact(SqlConnection con, StdElement x, List <ColumnDefinition> definitions) { var cmd = con.CreateCommand(); cmd.CommandText = "SELECT ContactID FROM Contact WHERE ContactID = @contactId'"; cmd.Parameters.AddWithValue("@contactId", x.Id); var ret = cmd.ExecuteScalar(); }
/// <summary> /// overrides the standard MergeMissingItem method to not read all outlook contacts, because /// that is not needed to add a new contact /// </summary> /// <param name="element"> /// element that should be merged into the outlook folder /// </param> /// <param name="clientFolderName"> /// outlook folder that should get the new contact /// </param> public override void MergeMissingItem(StdElement element, string clientFolderName) { var elements = new List <StdElement> { element }; this.WriteFullList(elements, clientFolderName, true); }
/// <summary> /// This method does NOT get all elements before adding the new element. It will only match the element by the Id /// </summary> /// <param name="element"> /// the element to add /// </param> /// <param name="clientFolderName"> /// the outlook folder to use /// </param> public override void AddItem(StdElement element, string clientFolderName) { var elements = new List <StdElement> { element }; this.WriteFullList(elements, clientFolderName, false); }
/// <summary> /// Overridable implementation of the process of writing a single element. In the /// default implementation this calls <see cref="GetAll"/>, WriteElement and /// <see cref="WriteRange"/> to write the element and performs logging calls. /// </summary> /// <param name="element"> The element to be added. </param> /// <param name="clientFolderName"> /// The information where inside the source the elements reside - /// This does not need to be a real "path", but need to be something that can be expressed as a string /// </param> public virtual void AddItem(StdElement element, string clientFolderName) { this.LogProcessingEvent(element, Resources.uiAddingElement); var data = this.GetAll(clientFolderName); WriteElement(data, element); this.WriteRange(data, clientFolderName); this.LogProcessingEvent(element, Resources.uiElementAdded); }
/// <summary> /// Implementation of the process of writing a single element and skipping this process if this /// element is already present. If the element does not exist, it will be added. If it does exist /// the element will not be added and not be overridden. /// </summary> /// <param name="element">The element to be added</param> /// <param name="clientFolderName"> /// The information where inside the source the elements reside - /// This does not need to be a real "path", but need to be something that can be expressed as a string /// </param> public virtual void MergeMissingItem(StdElement element, string clientFolderName) { this.LogProcessingEvent(element, Resources.uiAddingMissingElement); var data = this.GetAll(clientFolderName); var added = WriteElement(data, element, true); this.WriteRange(data, clientFolderName); this.LogProcessingEvent(element, added ? Resources.uiElementAdded : Resources.uiElementSkipped); }
/// <summary> /// logs an event by specifying the current element that is related to the event and a message about the current event /// </summary> /// <param name="stdItem"> /// the std-element this event corresponds to /// </param> /// <param name="message"> /// the message for this even (should describe what's happening in this step of execution) /// </param> protected void LogProcessingEvent(StdElement stdItem, string message) { if (this.ProcessingEvent != null) { this.ProcessingEvent( (object)stdItem ?? (object)this, new ProcessingEventArgs { Item = stdItem, Message = message }); } }
/// <summary> /// Initializes a new instance of the <see cref="Node"/> class. /// This ctor does create an element node from the ID and the <see cref="StdContact.GetFullName"/> /// or <see cref="StdElement.ToStringSimple"/> methods. /// </summary> /// <param name="element"> The element to convert. </param> public Node(StdElement element) { this.Id = element.Id.ToString("N"); var contact = element as StdContact; this.Label = contact != null ? contact.GetFullName() : element.ToStringSimple(); }
/// <summary> /// Initializes a new instance of the <see cref="MatchView"/> class. /// </summary> /// <param name="sourceElement"> /// The source element. /// </param> /// <param name="targetElement"> /// The target element. /// </param> public MatchView(StdElement sourceElement, StdElement targetElement) { var sourceContact = sourceElement as StdContact; var targetContact = targetElement as StdContact; this.ContactName = sourceContact != null?sourceContact.GetFullName() : sourceElement.ToString(); this.ContactNameMatch = targetContact != null?targetContact.GetFullName() : targetElement.ToString(); this.BaselineId = targetElement.Id; }
/// <summary> /// Initializes a new instance of the <see cref="MatchCandidateView"/> class. /// </summary> /// <param name="stdElement"> /// The std element. /// </param> public MatchCandidateView(StdElement stdElement) { this.Element = stdElement; var contact = stdElement as StdContact; if (contact != null) { this.ContactName = contact.GetFullName(); return; } this.ContactName = stdElement.ToString(); }
/// <summary> /// Converts a <see cref="StdContact"/> to an Oracle CRM on Demand <see cref="ContactData"/> /// </summary> /// <param name="element">The standard contact</param> /// <param name="addCustomAttributes"> a value specifying whether non-mapped properties should be added from the <see cref="StdContact.SourceSpecificAttributes"/></param> /// <returns>The converted data as a <see cref="ContactData"/></returns> internal static ContactData ToOracleContact(this StdElement element, bool addCustomAttributes) { var contact = element as StdContact; if (contact == null) { return(null); } var result = new ContactData { Id = contact.ExternalIdentifier[ProfileIdentifierType.OracleCrmOnDemandId], CreatedDate = contact.InternalSyncData.NewIfNull().DateOfCreation, CreatedDateSpecified = true, ModifiedDate = contact.InternalSyncData.NewIfNull().DateOfLastChange, ModifiedDateSpecified = true, Description = contact.AdditionalTextData, WorkPhone = contact.BusinessAddressPrimary.NewIfNull().Phone.NewIfNull().ToString().Replace("(", string.Empty).Replace(")", string.Empty), PrimaryCity = contact.BusinessAddressPrimary.NewIfNull().CityName, PrimaryZipCode = contact.BusinessAddressPrimary.NewIfNull().PostalCode, PrimaryCountry = contact.BusinessAddressPrimary.NewIfNull().CountryName, PrimaryAddress = contact.BusinessAddressPrimary.NewIfNull().StreetName, PrimaryProvince = contact.BusinessAddressPrimary.NewIfNull().StateName, HomePhone = contact.PersonalAddressPrimary.NewIfNull().Phone.NewIfNull().ToString().Replace("(", string.Empty).Replace(")", string.Empty), ContactEmail = contact.BusinessEmailPrimary, CellularPhone = contact.BusinessPhoneMobile.NewIfNull().ToString().Replace("(", string.Empty).Replace(")", string.Empty), JobTitle = contact.BusinessPosition, Department = contact.BusinessDepartment, AccountName = contact.BusinessCompanyName, DateofBirth = contact.DateOfBirth, DateofBirthSpecified = contact.DateOfBirth > DateTime.MinValue, ContactFirstName = contact.Name.NewIfNull().FirstName, MiddleName = contact.Name.NewIfNull().MiddleName, ContactLastName = contact.Name.NewIfNull().LastName, }; if (addCustomAttributes && contact.SourceSpecificAttributes != null) { // determine the prefix for the key var targetConnectorName = typeof(ContactClient).FullName; if (targetConnectorName == null) { return(result); } var startIndex = targetConnectorName.Length; // get all matching source properties and set the target // property + the corresponding "specified" property. (from x in contact.SourceSpecificAttributes where x.Key.StartsWith(targetConnectorName, StringComparison.OrdinalIgnoreCase) select x).ForEach(attribute => { var key = attribute.Key.Substring(startIndex); var keySpecified = key + "Specified"; Tools.SetPropertyValue(result, key, attribute.Value); Tools.SetPropertyValue(result, keySpecified, "true"); }); } return(result); }
/// <summary> /// log the events /// </summary> /// <param name="contactStdItem"> /// element, this entry belongs to /// </param> /// <param name="message"> /// the message for this even (should describe what's happening in this step of execution) /// </param> /// <param name="parameters"> /// parameters that will be inserted into the log-message /// </param> protected void LogProcessingEvent(StdElement contactStdItem, string message, params object[] parameters) { this.LogProcessingEvent(contactStdItem, string.Format(CultureInfo.CurrentCulture, message, parameters)); }
/// <summary> /// Sets a property inside an object /// </summary> /// <param name="stdElement"> The <see cref="StdElement"/> with the property to be set. </param> /// <param name="pathToProperty"> The path to the property to be set property. /// </param> <param name="newValue"> The new value. </param> private static void SetPropertyValue(StdElement stdElement, string pathToProperty, string newValue) { object propObject = stdElement; var propType = stdElement.GetType(); while (pathToProperty.Contains(".")) { var nextSeparator = pathToProperty.IndexOf(".", StringComparison.Ordinal); var propName = pathToProperty.Substring(0, nextSeparator); pathToProperty = pathToProperty.Substring(nextSeparator + 1); if (string.IsNullOrEmpty(propName)) { continue; } var member = propType.GetProperty(propName); propType = member.PropertyType; var destinObject = member.GetValue(propObject, null); if (destinObject == null) { destinObject = propType.GetConstructor(new Type[0]).Invoke(null); member.SetValue(propObject, destinObject, null); } propObject = destinObject; } var memberToSet = propType.GetProperty(pathToProperty); // we have to deal with special type data (int, datetime) that need to be // converted back from string - there is no automated cast in SetValue. var destinationType = memberToSet.PropertyType.Name; var destinationBaseType = memberToSet.PropertyType.BaseType; if (destinationBaseType == typeof(Enum)) { destinationType = "Enum"; } switch (destinationType) { case "Enum": memberToSet.SetValue(propObject, Enum.Parse(memberToSet.PropertyType, newValue, true), null); break; case "TimeSpan": memberToSet.SetValue(propObject, TimeSpan.Parse(newValue, CultureInfo.InvariantCulture), null); break; case "DateTime": memberToSet.SetValue(propObject, DateTime.Parse(newValue, CultureInfo.CurrentCulture), null); break; case "List`1": // TODO: Implement setting of List<> from string break; case "Int32": memberToSet.SetValue(propObject, Int32.Parse(newValue, CultureInfo.CurrentCulture), null); break; default: memberToSet.SetValue(propObject, newValue, null); break; } }
/// <summary> /// Writes a single element to the list of elements; overwrites an existing element with the same id /// </summary> /// <param name="list"> The list of elements the new element should be added to </param> /// <param name="element"> The new element that should be added </param> private static void WriteElement(ICollection <StdElement> list, StdElement element) { WriteElement(list, element, false); }
/// <summary> /// Implements the method to fill the contact with additional links to other contacts. /// </summary> /// <param name="contactToFill"> The contact to be filled. </param> /// <param name="baseline"> The baseline that does contain possible link targets. </param> /// <returns> the manipulated contact </returns> public override StdElement FillContacts(StdElement contactToFill, ICollection <MatchingEntry> baseline) { var contact = contactToFill as StdContact; const ProfileIdentifierType ProfileIdentifierType = ProfileIdentifierType.WerKenntWenUrl; const string ProfilePhpId = "/person/"; if (contact == null || !contact.ExternalIdentifier.ContainsKey(ProfileIdentifierType)) { return(contactToFill); } var profileIdInformation = contact.ExternalIdentifier[ProfileIdentifierType]; if (profileIdInformation == null || string.IsNullOrWhiteSpace(profileIdInformation.Id)) { return(contactToFill); } var offset = 0; var added = 0; while (true) { this.LogProcessingEvent("reading contacts ({0})", offset); this.HttpRequester.ContentCredentials = this; // get the contact list var url = string.Format( CultureInfo.InvariantCulture, "http://www.wer-kennt-wen.de/people/friends/{0}/sort/friends/0/0/{1}", profileIdInformation.Id.Replace(ProfilePhpId, string.Empty), offset); string profileContent; while (true) { profileContent = this.HttpRequester.GetContent(url, string.Format(CultureInfo.InvariantCulture, "Wkw-{0}", offset)); if (profileContent.Contains(@"id=""loginform""")) { if (!this.GetLogon()) { return(contactToFill); } continue; } if (profileContent.Contains(WkwCaptcha)) { this.ResolveCaptcha(); continue; } break; } var extracts = Regex.Matches(profileContent, @"\<a href=""/person/(?<profileId>[0-9a-zA-Z]*)""\>", RegexOptions.Singleline); // if there is no contact in list, we did reach the end if (extracts.Count < 3) { break; } // create a new instance of a list of references if there is none contact.Contacts = contact.Contacts ?? new List <ContactReference>(extracts.Count); foreach (Match extract in extracts) { var profileId = ProfilePhpId + extract.Groups["profileId"]; var stdId = (from x in baseline where x.ProfileId.GetProfileId(ProfileIdentifierType) == profileId select x.Id).FirstOrDefault(); // we ignore contacts we donn't know if (stdId == default(Guid)) { continue; } // lookup an existing entry in this contacts contact-list var contactInList = (from x in contact.Contacts where x.Target == stdId select x).FirstOrDefault(); if (contactInList == null) { // add a new one if no existing entry has been found contactInList = new ContactReference { Target = stdId }; contact.Contacts.Add(contactInList); added++; } // update the flag that this entry is a private contact // todo: private/business contact contactInList.IsPrivateContact = true; } Thread.Sleep(new Random().Next(230, 8789)); offset += 64; // extracts.Count; } this.LogProcessingEvent(contact, "{0} contacts found, {1} new added", offset, added); return(contactToFill); }
/// <summary> /// Implements the method to fill the contact with additional links to other contacts. /// </summary> /// <param name="contactToFill"> The contact to be filled. </param> /// <param name="baseline"> The baseline that does contain possible link targets. </param> /// <returns> the manipulated contact </returns> public virtual StdElement FillContacts(StdElement contactToFill, ICollection <MatchingEntry> baseline) { var contact = contactToFill as StdContact; var webSideParameters = this.WebSideParameters; var profileIdentifierType = webSideParameters.ProfileIdentifierType; this.personIdentifierFromContactsListExtractor = new Regex(webSideParameters.PersonIdentifierFromContactsListRegex, RegexOptions.Singleline); var personIdentifierExtractor = new Regex(webSideParameters.ProfileIdPartExtractor, RegexOptions.Singleline); if (contact == null || !contact.ExternalIdentifier.ContainsKey(profileIdentifierType)) { return(contactToFill); } var profileIdInformation = contact.ExternalIdentifier[profileIdentifierType]; if (profileIdInformation == null || string.IsNullOrWhiteSpace(profileIdInformation.Id)) { return(contactToFill); } var match = personIdentifierExtractor.Match(profileIdInformation.Id); if (match.Groups.Count == 0) { return(contactToFill); } var identifierPart = match.Groups[1]; var offset = 0; var added = 0; while (true) { this.LogProcessingEvent("reading contacts (from offset {0})", offset); this.HttpRequester.ContentCredentials = this; // get the contact list var url = string.Format( CultureInfo.InvariantCulture, webSideParameters.ContactListUrl, identifierPart, offset); var profileContent = this.HttpRequester.GetContent(url); var loginNeeded = webSideParameters.HttpDetectionStringLogOnNeeded.Where(profileContent.Contains).Count() > 0; if (loginNeeded) { this.LogProcessingEvent(contact, "log on needed"); if (!this.Logon()) { this.LogProcessingEvent(contact, "log on failed"); return(contactToFill); } profileContent = this.HttpRequester.GetContent(url); } var profileIds = this.ExtractProfileIdsFromFriendsList(profileIdInformation, profileContent); // if there is no contact in list, we did reach the end if (profileIds.Count == 0) { break; } // create a new instance of a list of references if there is none added = this.AddContactIdsToStdContact(contact, profileIds, baseline, added); this.LogProcessingEvent(contact, "{0} contacts found, {1} added.", profileIds.Count, added); this.LogProcessingEvent(contact, "sleeping some time to not being identifies as a bot..."); this.ThinkTime(); // todo: facebook uses a page size of 64, wer-kennt-wen offset += 64; // extracts.Count; } this.LogProcessingEvent(contact, "{0} contacts found, {1} new added", offset, added); return(contactToFill); }
/// <summary> /// Implements the interface to get more information - in this case the /// related contacts from the profile /// </summary> /// <param name="contactToFill">The contact to fill.</param> /// <param name="baseline"> The baseline.</param> /// <returns>the contact with more information</returns> public StdElement FillContacts(StdElement contactToFill, ICollection <MatchingEntry> baseline) { return(contactToFill); }