From 4a27f27c0c56b1bf5dee0c0f7be53022523af06a Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Fri, 7 Sep 2018 13:24:15 +0100 Subject: [PATCH 01/13] Build 3.0.16.11, with memory usage logging. --- Doxyfile | 2 +- README.md | 2 +- SuiteCRMAddIn/Log4NetLogger.cs | 4 ++++ SuiteCRMAddIn/Properties/AssemblyInfo.cs | 2 +- SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl | 2 +- SuiteCRMClient/Properties/AssemblyInfo.cs | 2 +- 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Doxyfile b/Doxyfile index 7c437bcf..af21d315 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "SuiteCRM Outlook Add-in" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 3.0.16.0 +PROJECT_NUMBER = 3.0.16.11 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/README.md b/README.md index 31466738..95aa6734 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ### What's in this repository -SuiteCRM Outlook Plug-In v 3.0.16.0 +SuiteCRM Outlook Plug-In v 3.0.16.11 This repository has been created to allow community members to collaborate and contribute to the project. diff --git a/SuiteCRMAddIn/Log4NetLogger.cs b/SuiteCRMAddIn/Log4NetLogger.cs index 2d57df95..1f64c07f 100644 --- a/SuiteCRMAddIn/Log4NetLogger.cs +++ b/SuiteCRMAddIn/Log4NetLogger.cs @@ -147,6 +147,10 @@ public static Log4NetLogger FromFilePath(string area, string filePath, FuncPROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS##IDS_PROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS## ProductCode{3BFCFDAB-2396-46E0-A826-0F142CA288EB} ProductNameSuiteCRMAddIn - ProductVersion3.0.16.0 + ProductVersion3.0.16.11 ProgressType0install ProgressType1Installing ProgressType2installed diff --git a/SuiteCRMClient/Properties/AssemblyInfo.cs b/SuiteCRMClient/Properties/AssemblyInfo.cs index 902491d6..26b53bb2 100644 --- a/SuiteCRMClient/Properties/AssemblyInfo.cs +++ b/SuiteCRMClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.16.0")] +[assembly: AssemblyVersion("3.0.16.11")] [assembly: AssemblyFileVersion("1.0.0.0")] From 23b1418b4a71ad4d029cc1d2e89621a69a3de9e2 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Fri, 19 Oct 2018 15:04:24 +0100 Subject: [PATCH 02/13] Build 3.0.16.20: allow 'PLAIN' LDAP authentication --- Doxyfile | 2 +- README.md | 2 +- SuiteCRMAddIn/Dialogs/SettingsDialog.cs | 18 +++++++++--------- SuiteCRMAddIn/Properties/AssemblyInfo.cs | 2 +- SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl | 2 +- SuiteCRMClient/LDAPAuthenticationHelper.cs | 9 +++++++-- SuiteCRMClient/Properties/AssemblyInfo.cs | 2 +- 7 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Doxyfile b/Doxyfile index af21d315..57515513 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "SuiteCRM Outlook Add-in" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 3.0.16.11 +PROJECT_NUMBER = 3.0.16.20 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/README.md b/README.md index 95aa6734..d1c1b82a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ### What's in this repository -SuiteCRM Outlook Plug-In v 3.0.16.11 +SuiteCRM Outlook Plug-In v 3.0.16.20 This repository has been created to allow community members to collaborate and contribute to the project. diff --git a/SuiteCRMAddIn/Dialogs/SettingsDialog.cs b/SuiteCRMAddIn/Dialogs/SettingsDialog.cs index d7abf6c6..7e84ae2b 100644 --- a/SuiteCRMAddIn/Dialogs/SettingsDialog.cs +++ b/SuiteCRMAddIn/Dialogs/SettingsDialog.cs @@ -74,15 +74,15 @@ private bool ValidateDetails() return false; } - if (chkEnableLDAPAuthentication.Checked) - { - if (SafelyGetText(txtLDAPAuthenticationKey) == string.Empty) - { - MessageBox.Show("Please enter a valid LDAP authentication key"); - txtLDAPAuthenticationKey.Focus(); - return false; - } - } + //if (chkEnableLDAPAuthentication.Checked) + //{ + // if (SafelyGetText(txtLDAPAuthenticationKey) == string.Empty) + // { + // MessageBox.Show("Please enter a valid LDAP authentication key"); + // txtLDAPAuthenticationKey.Focus(); + // return false; + // } + //} return true; } diff --git a/SuiteCRMAddIn/Properties/AssemblyInfo.cs b/SuiteCRMAddIn/Properties/AssemblyInfo.cs index d312a894..49fb478a 100644 --- a/SuiteCRMAddIn/Properties/AssemblyInfo.cs +++ b/SuiteCRMAddIn/Properties/AssemblyInfo.cs @@ -33,6 +33,6 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.16.11")] +[assembly: AssemblyVersion("3.0.16.20")] [assembly: AssemblyFileVersion("3.0.1")] diff --git a/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl b/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl index 6a6f2ae1..7439e20e 100644 --- a/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl +++ b/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl @@ -4423,7 +4423,7 @@ RABlAGIAdQBnAAEARQB4AHAAcgBlAHMAcwA= PROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS##IDS_PROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS## ProductCode{3BFCFDAB-2396-46E0-A826-0F142CA288EB} ProductNameSuiteCRMAddIn - ProductVersion3.0.16.11 + ProductVersion3.0.16.20 ProgressType0install ProgressType1Installing ProgressType2installed diff --git a/SuiteCRMClient/LDAPAuthenticationHelper.cs b/SuiteCRMClient/LDAPAuthenticationHelper.cs index 3569e788..2cc1bd19 100644 --- a/SuiteCRMClient/LDAPAuthenticationHelper.cs +++ b/SuiteCRMClient/LDAPAuthenticationHelper.cs @@ -82,8 +82,13 @@ public string Authenticate() user_auth = new { user_name = username, - password = EncryptPassword(this.password, - ConstructEncryptionAlgorithm(this.key, this.initialisationVector)), + password = string.IsNullOrWhiteSpace(this.key) ? + this.password: + EncryptPassword(this.password, + ConstructEncryptionAlgorithm(this.key, this.initialisationVector)), + encryption = string.IsNullOrWhiteSpace(this.key) ? + "PLAIN" : + Boolean.TrueString, application_name = this.applicationName } }; diff --git a/SuiteCRMClient/Properties/AssemblyInfo.cs b/SuiteCRMClient/Properties/AssemblyInfo.cs index 26b53bb2..117f75e1 100644 --- a/SuiteCRMClient/Properties/AssemblyInfo.cs +++ b/SuiteCRMClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.16.11")] +[assembly: AssemblyVersion("3.0.16.20")] [assembly: AssemblyFileVersion("1.0.0.0")] From e79e3f0909c2f1586d7cfe895a193c358d1c2d1f Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Mon, 3 Dec 2018 12:02:35 +0000 Subject: [PATCH 03/13] 4509: Added special purpose exception, and handler for it. Validated that throwing the exception does not interfere with actually saving the item. There's more to this issue than this - if we aren't syncing, we cannot in principle check whether or not it's a valid CRM id (I think) and so should not. But that takes some redesign which I'm not up to today. --- Doxyfile | 2 +- README.md | 2 +- .../BusinessLogic/AppointmentsSynchroniser.cs | 9 +++- SuiteCRMAddIn/BusinessLogic/CrmId.cs | 42 +++++++-------- .../Exceptions/ActionDisabledException.cs | 39 ++++++++++---- .../Exceptions/DuplicateCrmIdException.cs | 34 +++++++++--- .../Exceptions/InvalidCrmIdException.cs | 52 +++++++++++++++++++ .../ProbableDuplicateItemException.cs | 24 ++++++++- .../UnexpectedSyncStateClassException.cs | 24 ++++++++- SuiteCRMAddIn/Properties/AssemblyInfo.cs | 2 +- SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl | 2 +- SuiteCRMClient/Properties/AssemblyInfo.cs | 2 +- 12 files changed, 188 insertions(+), 46 deletions(-) create mode 100644 SuiteCRMAddIn/Exceptions/InvalidCrmIdException.cs diff --git a/Doxyfile b/Doxyfile index 57515513..0a930d77 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "SuiteCRM Outlook Add-in" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 3.0.16.20 +PROJECT_NUMBER = 3.0.16.23 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/README.md b/README.md index d1c1b82a..16ca35ac 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ### What's in this repository -SuiteCRM Outlook Plug-In v 3.0.16.20 +SuiteCRM Outlook Plug-In v 3.0.16.23 This repository has been created to allow community members to collaborate and contribute to the project. diff --git a/SuiteCRMAddIn/BusinessLogic/AppointmentsSynchroniser.cs b/SuiteCRMAddIn/BusinessLogic/AppointmentsSynchroniser.cs index 7e705437..39a23249 100644 --- a/SuiteCRMAddIn/BusinessLogic/AppointmentsSynchroniser.cs +++ b/SuiteCRMAddIn/BusinessLogic/AppointmentsSynchroniser.cs @@ -190,7 +190,14 @@ protected override void SaveItem(Outlook.AppointmentItem olItem) try { olItem.Save(); - LogItemAction(olItem, "AppointmentSyncing.SaveItem, saved item"); + try + { + LogItemAction(olItem, "AppointmentSyncing.SaveItem, saved item"); + } + catch (InvalidCrmIdException) + { + Log.Debug($"AppointmentSyncing.SaveItem, saved item '{olItem.Subject}' {olItem.EntryID} (no valid CRM id)"); + } } catch (System.Exception any) { diff --git a/SuiteCRMAddIn/BusinessLogic/CrmId.cs b/SuiteCRMAddIn/BusinessLogic/CrmId.cs index 7890150f..c741a8cb 100644 --- a/SuiteCRMAddIn/BusinessLogic/CrmId.cs +++ b/SuiteCRMAddIn/BusinessLogic/CrmId.cs @@ -20,13 +20,15 @@ * * @author SalesAgility */ + +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using SuiteCRMAddIn.Exceptions; +using SuiteCRMAddIn.Properties; + namespace SuiteCRMAddIn.BusinessLogic { - using System; - using System.Collections.Generic; - using System.Runtime.CompilerServices; - using System.Text.RegularExpressions; - /// /// A validated CRM id. /// @@ -35,7 +37,7 @@ public class CrmId : IComparable public static readonly CrmId Empty = new CrmId(); private static readonly Regex Validator = - CrmIdValidationPolicy.GetValidationPattern(Properties.Settings.Default.CrmIdValidationPolicy); + CrmIdValidationPolicy.GetValidationPattern(Settings.Default.CrmIdValidationPolicy); private static readonly Dictionary Issued = new Dictionary(); @@ -53,11 +55,11 @@ private CrmId() } /// - /// Create a new instance of a CrmId with this id. + /// Create a new instance of a CrmId with this id. /// /// - /// This has to be public so that the JSON deserialiser can use it - but don't use it - /// otherwise + /// This has to be public so that the JSON deserialiser can use it - but don't use it + /// otherwise /// /// public CrmId(string id) @@ -69,8 +71,8 @@ public CrmId(string id) } else { - throw new TypeInitializationException(this.GetType().FullName, - new Exception($"'{id}' does not appear to be a valid CRM id.")); + throw new TypeInitializationException(GetType().FullName, + new InvalidCrmIdException($"'{id}' does not appear to be a valid CRM id.")); } } @@ -123,13 +125,13 @@ public bool IsValid() } /// - /// True if is false of this id. + /// True if is false of this id. /// /// The object which may or may not be a valid CRM id. - /// True if is false of this id. + /// True if is false of this id. public static bool IsInvalid(CrmId id) { - return !CrmId.IsValid(id); + return !IsValid(id); } public override bool Equals(object obj) @@ -143,29 +145,25 @@ public override int GetHashCode() } /// - /// Get the single CrmId instance for this value. + /// Get the single CrmId instance for this value. /// /// The value to seek. /// A CrmId instance /// if `value` does not appear to be a valid CRM id. public static CrmId Get(string value) { - return string.IsNullOrEmpty(value) ? - CrmId.Empty : - CrmId.Issued.ContainsKey(value) ? - CrmId.Issued[value] : - new CrmId(value); + return string.IsNullOrEmpty(value) ? Empty : Issued.ContainsKey(value) ? Issued[value] : new CrmId(value); } /// - /// Get the single CrmId instance for this value. + /// Get the single CrmId instance for this value. /// /// The value to seek. /// A CrmId instance /// if `value` does not appear to be a valid CRM id. public static CrmId Get(object value) { - return value == null ? CrmId.Empty : CrmId.Get(value.ToString()); + return value == null ? Empty : Get(value.ToString()); } } } \ No newline at end of file diff --git a/SuiteCRMAddIn/Exceptions/ActionDisabledException.cs b/SuiteCRMAddIn/Exceptions/ActionDisabledException.cs index 9e7da309..aefc087f 100644 --- a/SuiteCRMAddIn/Exceptions/ActionDisabledException.cs +++ b/SuiteCRMAddIn/Exceptions/ActionDisabledException.cs @@ -1,16 +1,35 @@ -namespace SuiteCRMAddIn.Exceptions -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - using System.Threading.Tasks; +/** + * Outlook integration for SuiteCRM. + * @package Outlook integration for SuiteCRM + * @copyright SalesAgility Ltd http://www.salesagility.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU LESSER GENERAL PUBLIC LICENCE as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENCE + * along with this program; if not, see http://www.gnu.org/licenses + * or write to the Free Software Foundation,Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * @author SalesAgility + */ +namespace SuiteCRMAddIn.Exceptions +{ /// - /// A mechanism for temporarily disabling an action. + /// A mechanism for temporarily disabling an action. /// public class ActionDisabledException : ActionFailedException { - public ActionDisabledException() : base("This action is dissabled") { } + public ActionDisabledException() : base("This action is dissabled") + { + } } -} +} \ No newline at end of file diff --git a/SuiteCRMAddIn/Exceptions/DuplicateCrmIdException.cs b/SuiteCRMAddIn/Exceptions/DuplicateCrmIdException.cs index 2c858449..13fd339a 100644 --- a/SuiteCRMAddIn/Exceptions/DuplicateCrmIdException.cs +++ b/SuiteCRMAddIn/Exceptions/DuplicateCrmIdException.cs @@ -1,14 +1,35 @@ -using SuiteCRMAddIn.BusinessLogic; -using SuiteCRMClient; -using System; -using System.Runtime.Serialization; +/** + * Outlook integration for SuiteCRM. + * @package Outlook integration for SuiteCRM + * @copyright SalesAgility Ltd http://www.salesagility.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU LESSER GENERAL PUBLIC LICENCE as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENCE + * along with this program; if not, see http://www.gnu.org/licenses + * or write to the Free Software Foundation,Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * @author SalesAgility + */ namespace SuiteCRMAddIn.Exceptions { + using System; + using System.Runtime.Serialization; + using SuiteCRMAddIn.BusinessLogic; + [Serializable] internal class DuplicateCrmIdException : Exception { - public DuplicateCrmIdException() { } @@ -17,7 +38,8 @@ public DuplicateCrmIdException(string message) : base(message) { } - public DuplicateCrmIdException(SyncState syncState, CrmId id) : base($"Shouldn't happen: more than one Outlook object with CRM id '{id}' ({syncState.Description})") + public DuplicateCrmIdException(SyncState syncState, CrmId id) : base( + $"Shouldn't happen: more than one Outlook object with CRM id '{id}' ({syncState.Description})") { } diff --git a/SuiteCRMAddIn/Exceptions/InvalidCrmIdException.cs b/SuiteCRMAddIn/Exceptions/InvalidCrmIdException.cs new file mode 100644 index 00000000..8b526cac --- /dev/null +++ b/SuiteCRMAddIn/Exceptions/InvalidCrmIdException.cs @@ -0,0 +1,52 @@ +/** + * Outlook integration for SuiteCRM. + * @package Outlook integration for SuiteCRM + * @copyright SalesAgility Ltd http://www.salesagility.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU LESSER GENERAL PUBLIC LICENCE as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENCE + * along with this program; if not, see http://www.gnu.org/licenses + * or write to the Free Software Foundation,Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * @author SalesAgility + */ + +using System; +using System.Runtime.Serialization; + +namespace SuiteCRMAddIn.Exceptions +{ + /// + /// An exception thrown if a supposed CRM id does not meet the expected pattern. + /// + /// + [Serializable] + internal class InvalidCrmIdException : Exception + { + public InvalidCrmIdException() + { + } + + public InvalidCrmIdException(string message) : base(message) + { + } + + public InvalidCrmIdException(string message, Exception innerException) : base(message, innerException) + { + } + + protected InvalidCrmIdException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/SuiteCRMAddIn/Exceptions/ProbableDuplicateItemException.cs b/SuiteCRMAddIn/Exceptions/ProbableDuplicateItemException.cs index 8813864a..28898b43 100644 --- a/SuiteCRMAddIn/Exceptions/ProbableDuplicateItemException.cs +++ b/SuiteCRMAddIn/Exceptions/ProbableDuplicateItemException.cs @@ -1,4 +1,26 @@ -namespace SuiteCRMAddIn.Exceptions +/** + * Outlook integration for SuiteCRM. + * @package Outlook integration for SuiteCRM + * @copyright SalesAgility Ltd http://www.salesagility.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU LESSER GENERAL PUBLIC LICENCE as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENCE + * along with this program; if not, see http://www.gnu.org/licenses + * or write to the Free Software Foundation,Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * @author SalesAgility + */ +namespace SuiteCRMAddIn.Exceptions { using System; using System.Runtime.Serialization; diff --git a/SuiteCRMAddIn/Exceptions/UnexpectedSyncStateClassException.cs b/SuiteCRMAddIn/Exceptions/UnexpectedSyncStateClassException.cs index 4306a201..67cc08e4 100644 --- a/SuiteCRMAddIn/Exceptions/UnexpectedSyncStateClassException.cs +++ b/SuiteCRMAddIn/Exceptions/UnexpectedSyncStateClassException.cs @@ -1,4 +1,26 @@ -namespace SuiteCRMAddIn.Exceptions +/** + * Outlook integration for SuiteCRM. + * @package Outlook integration for SuiteCRM + * @copyright SalesAgility Ltd http://www.salesagility.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU LESSER GENERAL PUBLIC LICENCE as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENCE + * along with this program; if not, see http://www.gnu.org/licenses + * or write to the Free Software Foundation,Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301 USA + * + * @author SalesAgility + */ +namespace SuiteCRMAddIn.Exceptions { using BusinessLogic; using System; diff --git a/SuiteCRMAddIn/Properties/AssemblyInfo.cs b/SuiteCRMAddIn/Properties/AssemblyInfo.cs index 49fb478a..3f3a3b61 100644 --- a/SuiteCRMAddIn/Properties/AssemblyInfo.cs +++ b/SuiteCRMAddIn/Properties/AssemblyInfo.cs @@ -33,6 +33,6 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.16.20")] +[assembly: AssemblyVersion("3.0.16.23")] [assembly: AssemblyFileVersion("3.0.1")] diff --git a/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl b/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl index 7439e20e..02fb42ab 100644 --- a/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl +++ b/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl @@ -4423,7 +4423,7 @@ RABlAGIAdQBnAAEARQB4AHAAcgBlAHMAcwA= PROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS##IDS_PROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS## ProductCode{3BFCFDAB-2396-46E0-A826-0F142CA288EB} ProductNameSuiteCRMAddIn - ProductVersion3.0.16.20 + ProductVersion3.0.16.23 ProgressType0install ProgressType1Installing ProgressType2installed diff --git a/SuiteCRMClient/Properties/AssemblyInfo.cs b/SuiteCRMClient/Properties/AssemblyInfo.cs index 117f75e1..9942adbd 100644 --- a/SuiteCRMClient/Properties/AssemblyInfo.cs +++ b/SuiteCRMClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.16.20")] +[assembly: AssemblyVersion("3.0.16.23")] [assembly: AssemblyFileVersion("1.0.0.0")] From fbedd96a692d81bba745b19fb814cb449580d31b Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Mon, 3 Dec 2018 12:06:01 +0000 Subject: [PATCH 04/13] 4509: Build 3.0.16.24 --- Doxyfile | 2 +- README.md | 2 +- SuiteCRMAddIn/Properties/AssemblyInfo.cs | 2 +- SuiteCRMAddIn/SuiteCRMAddIn.csproj | 1 + SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl | 2 +- SuiteCRMClient/Properties/AssemblyInfo.cs | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Doxyfile b/Doxyfile index 0a930d77..42a98535 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "SuiteCRM Outlook Add-in" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 3.0.16.23 +PROJECT_NUMBER = 3.0.16.24 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/README.md b/README.md index 16ca35ac..e8227fb2 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ### What's in this repository -SuiteCRM Outlook Plug-In v 3.0.16.23 +SuiteCRM Outlook Plug-In v 3.0.16.24 This repository has been created to allow community members to collaborate and contribute to the project. diff --git a/SuiteCRMAddIn/Properties/AssemblyInfo.cs b/SuiteCRMAddIn/Properties/AssemblyInfo.cs index 3f3a3b61..6a9f73be 100644 --- a/SuiteCRMAddIn/Properties/AssemblyInfo.cs +++ b/SuiteCRMAddIn/Properties/AssemblyInfo.cs @@ -33,6 +33,6 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.16.23")] +[assembly: AssemblyVersion("3.0.16.24")] [assembly: AssemblyFileVersion("3.0.1")] diff --git a/SuiteCRMAddIn/SuiteCRMAddIn.csproj b/SuiteCRMAddIn/SuiteCRMAddIn.csproj index 36758ba9..de1cffc7 100644 --- a/SuiteCRMAddIn/SuiteCRMAddIn.csproj +++ b/SuiteCRMAddIn/SuiteCRMAddIn.csproj @@ -213,6 +213,7 @@ + Form diff --git a/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl b/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl index 02fb42ab..e95858d2 100644 --- a/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl +++ b/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl @@ -4423,7 +4423,7 @@ RABlAGIAdQBnAAEARQB4AHAAcgBlAHMAcwA= PROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS##IDS_PROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS## ProductCode{3BFCFDAB-2396-46E0-A826-0F142CA288EB} ProductNameSuiteCRMAddIn - ProductVersion3.0.16.23 + ProductVersion3.0.16.24 ProgressType0install ProgressType1Installing ProgressType2installed diff --git a/SuiteCRMClient/Properties/AssemblyInfo.cs b/SuiteCRMClient/Properties/AssemblyInfo.cs index 9942adbd..19c94168 100644 --- a/SuiteCRMClient/Properties/AssemblyInfo.cs +++ b/SuiteCRMClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.16.23")] +[assembly: AssemblyVersion("3.0.16.24")] [assembly: AssemblyFileVersion("1.0.0.0")] From 9cb77ecc39515b97c0f4bfc95ddd4622a6925fae Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Thu, 6 Dec 2018 11:54:23 +0000 Subject: [PATCH 05/13] 4509: Concept of a disabled synchroniser. --- Doxyfile | 2 +- .../BusinessLogic/AppointmentsSynchroniser.cs | 6 +- .../BusinessLogic/CRMPermissionsCache.cs | 1 + .../BusinessLogic/ContactSynchroniser.cs | 2 +- SuiteCRMAddIn/BusinessLogic/Synchroniser.cs | 556 +++++++++--------- .../BusinessLogic/TaskSynchroniser.cs | 2 +- 6 files changed, 295 insertions(+), 274 deletions(-) diff --git a/Doxyfile b/Doxyfile index 42a98535..3a4fb719 100644 --- a/Doxyfile +++ b/Doxyfile @@ -51,7 +51,7 @@ PROJECT_BRIEF = "An outlook add-in which allows synchronisation with Su # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = ../SuiteCRMAddIn/Images/SuiteCRM.png +PROJECT_LOGO = C:/Users/Simon/Workspace/SuiteCRM-Outlook-Plugin/SuiteCRMAddIn/Images/SuiteCRM.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is diff --git a/SuiteCRMAddIn/BusinessLogic/AppointmentsSynchroniser.cs b/SuiteCRMAddIn/BusinessLogic/AppointmentsSynchroniser.cs index 39a23249..7c23dd18 100644 --- a/SuiteCRMAddIn/BusinessLogic/AppointmentsSynchroniser.cs +++ b/SuiteCRMAddIn/BusinessLogic/AppointmentsSynchroniser.cs @@ -516,7 +516,7 @@ private void DeleteFromCrm(Outlook.AppointmentItem olItem) /// when the add-in starts up; initialises the SyncState list. /// /// The folder to scan. - protected override void GetOutlookItems(Outlook.MAPIFolder appointmentsFolder) + protected override void LinkOutlookItems(Outlook.MAPIFolder appointmentsFolder) { try { @@ -537,11 +537,11 @@ protected override void GetOutlookItems(Outlook.MAPIFolder appointmentsFolder) /* The appointment probably already has the three magic properties * required for synchronisation; is that a proxy for believing that it * already exists in CRM? If so, is it reliable? */ - LogItemAction(olItem, "AppointmentSyncing.GetOutlookItems: Adding known item to queue"); + LogItemAction(olItem, "AppointmentSyncing.LinkOutlookItems: Adding known item to queue"); } else { - LogItemAction(olItem, "AppointmentSyncing.GetOutlookItems: Adding unknown item to queue"); + LogItemAction(olItem, "AppointmentSyncing.LinkOutlookItems: Adding unknown item to queue"); } SyncStateManager.Instance.GetOrCreateSyncState(olItem).SetPresentAtStartup(); diff --git a/SuiteCRMAddIn/BusinessLogic/CRMPermissionsCache.cs b/SuiteCRMAddIn/BusinessLogic/CRMPermissionsCache.cs index 33d6b8ac..ac77d629 100644 --- a/SuiteCRMAddIn/BusinessLogic/CRMPermissionsCache.cs +++ b/SuiteCRMAddIn/BusinessLogic/CRMPermissionsCache.cs @@ -383,6 +383,7 @@ internal override void PerformIteration() /// /// The type of outlook item for which I manage /// permissions (may be stored in more than one module). + /// The appropriate SyncState type for that Outlook item type. public class CRMPermissionsCache : CRMPermissionsCache where OutlookItemType : class where SyncStateType : SyncState diff --git a/SuiteCRMAddIn/BusinessLogic/ContactSynchroniser.cs b/SuiteCRMAddIn/BusinessLogic/ContactSynchroniser.cs index b006babb..d5219c5e 100644 --- a/SuiteCRMAddIn/BusinessLogic/ContactSynchroniser.cs +++ b/SuiteCRMAddIn/BusinessLogic/ContactSynchroniser.cs @@ -417,7 +417,7 @@ protected override void EnsureSynchronisationPropertyForOutlookItem(Outlook.Cont } - protected override void GetOutlookItems(Outlook.MAPIFolder taskFolder) + protected override void LinkOutlookItems(Outlook.MAPIFolder taskFolder) { try { diff --git a/SuiteCRMAddIn/BusinessLogic/Synchroniser.cs b/SuiteCRMAddIn/BusinessLogic/Synchroniser.cs index f42e2735..aa78f3fc 100644 --- a/SuiteCRMAddIn/BusinessLogic/Synchroniser.cs +++ b/SuiteCRMAddIn/BusinessLogic/Synchroniser.cs @@ -21,125 +21,136 @@ * @author SalesAgility */ +#region + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using Microsoft.Office.Interop.Outlook; +using Newtonsoft.Json; +using SuiteCRMAddIn.Daemon; +using SuiteCRMAddIn.Exceptions; +using SuiteCRMAddIn.Properties; +using SuiteCRMClient; +using SuiteCRMClient.Logging; +using SuiteCRMClient.RESTObjects; +using Exception = System.Exception; + +#endregion + namespace SuiteCRMAddIn.BusinessLogic { - using Daemon; - using Exceptions; - using Newtonsoft.Json; - using SuiteCRMClient; - using SuiteCRMClient.Logging; - using SuiteCRMClient.RESTObjects; - using System; - using System.Collections.Generic; - using System.Globalization; - using System.Linq; - using Outlook = Microsoft.Office.Interop.Outlook; - public abstract class Synchroniser : RepeatingProcess { public Synchroniser(string name, SyncContext context) : base(name, context.Log) { - this.Context = context; + Context = context; } - protected Outlook.Application Application => Context.Application; + protected Application Application => Context.Application; /// - /// The name of the default CRM module (record type) that this synchroniser synchronises. + /// The name of the default CRM module (record type) that this synchroniser synchronises. /// - public abstract string DefaultCrmModule - { - get; - } + public abstract string DefaultCrmModule { get; } /// - /// The direction(s) in which I sync + /// The direction(s) in which I sync /// public abstract SyncDirection.Direction Direction { get; } /// - /// The synchronisation context in which I operate. + /// The synchronisation context in which I operate. /// - protected SyncContext Context { get; private set; } + protected SyncContext Context { get; } /// - /// Get the Outlook folder in which my items are stored. + /// Get the Outlook folder in which my items are stored. /// - /// - public abstract Outlook.MAPIFolder GetDefaultFolder(); + /// the Outlook folder in which my items are stored + public abstract MAPIFolder GetDefaultFolder(); /// - /// Specialisation: get my Outlook items. + /// Specialisation: get my Outlook items. /// public override void PerformStartup() { - this.GetOutlookItems(this.GetDefaultFolder()); + LinkOutlookItems(GetDefaultFolder()); } - protected abstract void GetOutlookItems(Outlook.MAPIFolder folder); + /// + /// Links the outlook items in the specified folder into the items whose synchronisation states I track. + /// + /// the Outlook folder from which items should be taken. + protected abstract void LinkOutlookItems(MAPIFolder folder); + - protected abstract void SyncFolder(Outlook.MAPIFolder folder, string crmModule); + /// + /// Synchronise items in the specified folder with the specified SuiteCRM module. + /// + protected abstract void SyncFolder(MAPIFolder folder, string crmModule); } /// - /// Synchronise items of the class for which I am responsible. + /// Synchronise items of the class for which I am responsible. /// /// - /// It's arguable that specialisations of this class ought to be singletons, but currently they are not. + /// It's arguable that specialisations of this class ought to be singletons, but currently they are not. /// /// The class of item that I am responsible for synchronising. - /// An appropriate sync state type for my + /// An appropriate sync state type for my public abstract class Synchroniser : Synchroniser, IDisposable where OutlookItemType : class where SyncStateType : SyncState { /// - /// A cache for CRM premissions to prevent continually asking for them. + /// A cache for CRM premissions to prevent continually asking for them. /// protected readonly CRMPermissionsCache permissionsCache; + // Keep a reference to the COM object on which we have event handlers, otherwise + // when the reference is garbage-collected, the event-handlers are removed! + private Items _itemsCollection; + /// - /// A lock on the creation of new objects in Outlook. + /// A lock on the creation of new objects in Outlook. /// protected object creationLock = new object(); /// - /// It appears that CRM sends us back strings HTML escaped. + /// It appears that CRM sends us back strings HTML escaped. /// - protected JsonSerializerSettings deserialiseSettings = new JsonSerializerSettings() + protected JsonSerializerSettings DeserialiseSettings = new JsonSerializerSettings { StringEscapeHandling = StringEscapeHandling.EscapeHtml }; /// - /// A lock to prevent enqueueing the same new object twice in different - /// threads (unlikely, since it should always be in the VSTA_main thread, - /// but let's be paranoid). + /// A lock to prevent enqueueing the same new object twice in different + /// threads (unlikely, since it should always be in the VSTA_main thread, + /// but let's be paranoid). /// protected object enqueueingLock = new object(); /// - /// The prefix for the fetch query, used in FetchRecordsFromCrm, q.v. + /// The prefix for the fetch query, used in FetchRecordsFromCrm, q.v. /// protected string fetchQueryPrefix; private string folderName; - // Keep a reference to the COM object on which we have event handlers, otherwise - // when the reference is garbage-collected, the event-handlers are removed! - private Outlook.Items _itemsCollection = null; - /// - /// Construct a new instance of a synchroniser with this thread name and context. + /// Construct a new instance of a synchroniser with this thread name and context. /// /// The name of the thread I shall create. /// The context in which I shall work. - public Synchroniser(string threadName, SyncContext context) : base( threadName, context) + public Synchroniser(string threadName, SyncContext context) : base(threadName, context) { - this.InstallEventHandlers(); - this.AddSuiteCrmOutlookCategory(); - this.permissionsCache = new CRMPermissionsCache(this, context.Log); + InstallEventHandlers(); + AddSuiteCrmOutlookCategory(); + permissionsCache = new CRMPermissionsCache(this, context.Log); } public void Dispose() @@ -148,63 +159,83 @@ public void Dispose() } /// - /// Get a date stamp for midnight five days ago (why?). + /// Am I enabled? I.e., am I able either to import or to export? + /// + /// True if this synchroniser is enabled. + public bool IsEnabled() + { + return Globals.ThisAddIn.HasCrmUserSession && + (SyncDirection.AllowInbound(Direction) || + SyncDirection.AllowOutbound(Direction)); + } + + /// + /// Get a date stamp for midnight five days ago (why?). /// /// A date stamp for midnight five days ago. public DateTime GetStartDate() { - DateTime dtRet = DateTime.Now.AddDays(-5); + var dtRet = DateTime.Now.AddDays(-5); return new DateTime(dtRet.Year, dtRet.Month, dtRet.Day, 0, 0, 0); } + /// + /// Return a SQL fragment based on my start date + /// + /// public string GetStartDateString() { - return " AND [Start] >='" + GetStartDate().ToString("MM/dd/yyyy HH:mm") + "'"; + return $" AND [Start] >='{GetStartDate().ToString("MM/dd/yyyy HH:mm")}'"; } + /// + /// Prepare me for shutdown by removing my event handlers. + /// + /// Always zero. public override int PrepareShutdown() { - this.RemoveEventHandlers(); + RemoveEventHandlers(); return 0; } /// - /// Run a single iteration of the synchronisation process for the items for which I am responsible. + /// Run a single iteration of the synchronisation process for the items for which I am responsible. /// public virtual void SynchroniseAll() { - Log.Debug($"{this.GetType().Name} SynchroniseAll starting"); + Log.Debug($"{GetType().Name} SynchroniseAll starting"); - if (this.permissionsCache.HasExportAccess()) + if (permissionsCache.HasExportAccess()) { - Outlook.MAPIFolder folder = GetDefaultFolder(); + var folder = GetDefaultFolder(); - SyncFolder(folder, this.DefaultCrmModule); + SyncFolder(folder, DefaultCrmModule); } else { - Log.Debug($"{this.GetType().Name}.SynchroniseAll not synchronising {this.DefaultCrmModule} because export access is denied"); + Log.Debug( + $"{GetType().Name}.SynchroniseAll not synchronising {DefaultCrmModule} because export access is denied"); } - Log.Debug($"{this.GetType().Name} SynchroniseAll completed"); + Log.Debug($"{GetType().Name} SynchroniseAll completed"); } /// - /// Add the item implied by this SyncState, which may not exist in CRM, to CRM. + /// Add the item implied by this SyncState, which may not exist in CRM, to CRM. /// /// The sync state. /// The id of the entry added or updated. internal virtual CrmId AddOrUpdateItemFromOutlookToCrm(SyncState syncState) { - CrmId result = CrmId.Empty; + var result = CrmId.Empty; - if (this.ShouldAddOrUpdateItemFromOutlookToCrm(syncState.OutlookItem)) + if (ShouldAddOrUpdateItemFromOutlookToCrm(syncState.OutlookItem)) { - OutlookItemType olItem = syncState.OutlookItem; + var olItem = syncState.OutlookItem; try { - lock (this.enqueueingLock) + lock (enqueueingLock) { LogItemAction(olItem, "Synchroniser.AddOrUpdateItemFromOutlookToCrm, Despatching"); @@ -216,13 +247,15 @@ internal virtual CrmId AddOrUpdateItemFromOutlookToCrm(SyncState - /// Get the entry id of this Outlook item. + /// Get the entry id of this Outlook item. /// + /// + /// Outlook item classes do not inherit from a common base class, so generic client code cannot refer to + /// 'OutlookItem.EntryId'; hance this rather clumsy mechanism. + /// /// The Outlook item from which the entry id should be taken. /// the entry id of this Outlook item. internal abstract string GetOutlookEntryId(OutlookItemType olItem); /// - /// Return the sensitivity of this outlook item. + /// Return the sensitivity of this outlook item. /// /// - /// Outlook item classes do not inherit from a common base class, so generic client code cannot refer to 'OutlookItem.Sensitivity'. + /// Outlook item classes do not inherit from a common base class, so generic client code cannot refer to + /// 'OutlookItem.Sensitivity'; hance this rather clumsy mechanism. /// /// The outlook item whose sensitivity is required. /// the sensitivity of the item. - internal abstract Outlook.OlSensitivity GetSensitivity(OutlookItemType olItem); + internal abstract OlSensitivity GetSensitivity(OutlookItemType olItem); + internal IEnumerable GetSynchronisedItems() { - return SyncStateManager.Instance.GetSynchronisedItems(); ; + return IsEnabled() + ? SyncStateManager.Instance.GetSynchronisedItems() + : new List(); } /// - /// Deal with an item which used to exist in Outlook but which no longer does. - /// The default behaviour is to remove it from CRM. + /// Deal with an item which used to exist in Outlook but which no longer does. + /// The default behaviour is to remove it from CRM. /// /// The dangling syncState of the missing item. internal virtual void HandleItemMissingFromOutlook(SyncState syncState) { - this.RemoveFromCrm(syncState); - this.RemoveItemSyncState(syncState); + RemoveFromCrm(syncState); + RemoveItemSyncState(syncState); } /// - /// Log a message regarding this Outlook item, with detail of the item. + /// Log a message regarding this Outlook item, with detail of the item. /// /// The outlook item. /// The message to be logged. internal abstract void LogItemAction(OutlookItemType olItem, string message); /// - /// If I am currently configured to do so, synchronise the items for which I am - /// responsible once. + /// If I am currently configured to do so, synchronise the items for which I am + /// responsible once. /// internal override void PerformIteration() { - if (Globals.ThisAddIn.HasCrmUserSession) + if (IsEnabled()) { - if (SyncDirection.AllowInbound(this.Direction)) - { - this.SynchroniseAll(); - } + if (SyncDirection.AllowInbound(Direction)) + SynchroniseAll(); else - { - Log.Debug($"{this.GetType().Name}.SynchroniseAll not running because not enabled"); - } + Log.Debug($"{GetType().Name}.SynchroniseAll not running because not enabled"); - this.OtherIterationActions(); + OtherIterationActions(); } else { - Log.Debug($"{this.GetType().Name}.SynchroniseAll not running because no session"); + Log.Debug($"{GetType().Name}.SynchroniseAll not running because no session"); } } /// - /// Update a single item in the specified Outlook folder with changes from CRM. If the item - /// does not exist, create it. + /// Update a single item in the specified Outlook folder with changes from CRM. If the item + /// does not exist, create it. /// /// The folder to synchronise into. /// The CRM type of the candidate item. /// The candidate item from CRM. /// The synchronisation state of the item updated (if it was updated). - protected abstract SyncState AddOrUpdateItemFromCrmToOutlook(Outlook.MAPIFolder folder, string crmType, EntryValue crmItem); + protected abstract SyncState AddOrUpdateItemFromCrmToOutlook(MAPIFolder folder, string crmType, + EntryValue crmItem); /// - /// Update these items, which may or may not already exist in Outlook. + /// Update these items, which may or may not already exist in Outlook. /// /// - /// TODO: It would be much better if, rather than taking `untouched` as a mutable argument, - /// this method returned a list of items which weren't identified. + /// TODO: It would be much better if, rather than taking `untouched` as a mutable argument, + /// this method returned a list of items which weren't identified. /// /// The items to be synchronised. /// The outlook folder to synchronise into. - /// A list of sync states of existing items which have - /// not yet been synchronised; this list is modified (destructuvely changed) - /// by the action of this method. + /// + /// A list of sync states of existing items which have + /// not yet been synchronised; this list is modified (destructuvely changed) + /// by the action of this method. + /// /// The CRM record type ('module') to be fetched. protected virtual void AddOrUpdateItemsFromCrmToOutlook( IList crmItems, - Outlook.MAPIFolder folder, + MAPIFolder folder, HashSet> untouched, string crmType) { foreach (var crmItem in crmItems) - { try { if (ShouldAddOrUpdateItemFromCrmToOutlook(folder, crmType, crmItem)) @@ -364,7 +401,8 @@ protected virtual void AddOrUpdateItemsFromCrmToOutlook( * ideally not be sent, so we forcibly mark them as synced overriding the * normal flow of the state transition engine. */ state.SetSynced(true); - LogItemAction(state.OutlookItem, "Synchroniser.AddOrUpdateItemsFromCrmToOutlook, item removed from untouched"); + LogItemAction(state.OutlookItem, + "Synchroniser.AddOrUpdateItemsFromCrmToOutlook, item removed from untouched"); } } else @@ -375,44 +413,47 @@ protected virtual void AddOrUpdateItemsFromCrmToOutlook( } catch (Exception ex) { - ErrorHandler.Handle($"Failed while trying to add or update {this.DefaultCrmModule} from Outlook to CRM", ex); + ErrorHandler.Handle($"Failed while trying to add or update {DefaultCrmModule} from Outlook to CRM", + ex); } - } } /// - /// Construct a JSON packet representing this Outlook item, and despatch it to CRM. + /// Construct a JSON packet representing this Outlook item, and despatch it to CRM. /// /// - /// You'd think that with normal object oriented programming you could just implement this - /// method here, but because Outlook items are not really objects and don't have a common - /// superclass you can't. So it has to be implemented in subclasses. + /// You'd think that with normal object oriented programming you could just implement this + /// method here, but because Outlook items are not really objects and don't have a common + /// superclass you can't. So it has to be implemented in subclasses. /// /// The Outlook item. /// The CRM id of the object created or modified. protected abstract CrmId ConstructAndDespatchCrmItem(OutlookItemType olItem); /// - /// Every Outlook item which is to be synchronised must have a property SOModifiedDate, - /// a property SType, and a property SEntryId, referencing respectively the last time it - /// was modified, the type of CRM item it is to be synchronised with, and the id of the - /// CRM item it is to be synchronised with. + /// Every Outlook item which is to be synchronised must have a property SOModifiedDate, + /// a property SType, and a property SEntryId, referencing respectively the last time it + /// was modified, the type of CRM item it is to be synchronised with, and the id of the + /// CRM item it is to be synchronised with. /// /// The Outlook item. /// The value for the SOModifiedDate property. /// The value for the SType property (CRM module name). /// The value for the SEntryId property (CRM item id). - protected void EnsureSynchronisationPropertiesForOutlookItem(OutlookItemType olItem, string modifiedDate, string type, CrmId entryId) + protected void EnsureSynchronisationPropertiesForOutlookItem(OutlookItemType olItem, string modifiedDate, + string type, CrmId entryId) { try { - EnsureSynchronisationPropertyForOutlookItem(olItem, SyncStateManager.ModifiedDatePropertyName, modifiedDate); + EnsureSynchronisationPropertyForOutlookItem(olItem, SyncStateManager.ModifiedDatePropertyName, + modifiedDate); EnsureSynchronisationPropertyForOutlookItem(olItem, SyncStateManager.TypePropertyName, type); if (CrmId.IsValid(entryId)) { EnsureSynchronisationPropertyForOutlookItem(olItem, SyncStateManager.CrmIdPropertyName, entryId); - SyncStateManager.Instance.SetByCrmId(entryId, SyncStateManager.Instance.GetOrCreateSyncState(olItem)); + SyncStateManager.Instance.SetByCrmId(entryId, + SyncStateManager.Instance.GetOrCreateSyncState(olItem)); } } catch (Exception any) @@ -426,27 +467,28 @@ protected void EnsureSynchronisationPropertiesForOutlookItem(OutlookItemType olI } /// - /// Set up synchronisation properties for this outlook item from this CRM item, assuming my default CRM module. + /// Set up synchronisation properties for this outlook item from this CRM item, assuming my default CRM module. /// /// The Outlook item. /// The CRM item. protected virtual void EnsureSynchronisationPropertiesForOutlookItem(OutlookItemType olItem, EntryValue crmItem) { - this.EnsureSynchronisationPropertiesForOutlookItem( + EnsureSynchronisationPropertiesForOutlookItem( olItem, crmItem, - this.DefaultCrmModule); + DefaultCrmModule); } /// - /// Set up synchronisation properties for this outlook item from this CRM item, assuming my default CRM module. + /// Set up synchronisation properties for this outlook item from this CRM item, assuming my default CRM module. /// /// The Outlook item. /// The CRM item. /// The value for the SType property (CRM module name). - protected virtual void EnsureSynchronisationPropertiesForOutlookItem(OutlookItemType olItem, EntryValue crmItem, string type) + protected virtual void EnsureSynchronisationPropertiesForOutlookItem(OutlookItemType olItem, EntryValue crmItem, + string type) { - this.EnsureSynchronisationPropertiesForOutlookItem( + EnsureSynchronisationPropertiesForOutlookItem( olItem, crmItem.GetValueAsString("date_modified"), type, @@ -454,35 +496,38 @@ protected virtual void EnsureSynchronisationPropertiesForOutlookItem(OutlookItem } /// - /// Every Outlook item which is to be synchronised must have a property SOModifiedDate, - /// a property SType, and a property SEntryId, referencing respectively the last time it - /// was modified, the type of CRM item it is to be synchronised with, and the id of the - /// CRM item it is to be synchronised with. + /// Every Outlook item which is to be synchronised must have a property SOModifiedDate, + /// a property SType, and a property SEntryId, referencing respectively the last time it + /// was modified, the type of CRM item it is to be synchronised with, and the id of the + /// CRM item it is to be synchronised with. /// /// The Outlook item. /// The value for the SOModifiedDate property. /// The value for the SType property. /// The value for the SEntryId property. - protected void EnsureSynchronisationPropertiesForOutlookItem(OutlookItemType olItem, DateTime modifiedDate, string type, CrmId entryId) + protected void EnsureSynchronisationPropertiesForOutlookItem(OutlookItemType olItem, DateTime modifiedDate, + string type, CrmId entryId) { - this.EnsureSynchronisationPropertiesForOutlookItem(olItem, modifiedDate.ToString("yyyy-MM-dd HH:mm:ss"), type, entryId); + EnsureSynchronisationPropertiesForOutlookItem(olItem, modifiedDate.ToString("yyyy-MM-dd HH:mm:ss"), type, + entryId); } /// - /// Ensure that this Outlook item has a property of this name with this value. + /// Ensure that this Outlook item has a property of this name with this value. /// /// The Outlook item. /// The name. /// The value. - protected abstract void EnsureSynchronisationPropertyForOutlookItem(OutlookItemType olItem, string name, string value); + protected abstract void EnsureSynchronisationPropertyForOutlookItem(OutlookItemType olItem, string name, + string value); protected void EnsureSynchronisationPropertyForOutlookItem(OutlookItemType olItem, string name, CrmId value) { - this.EnsureSynchronisationPropertyForOutlookItem(olItem, name, value.ToString()); + EnsureSynchronisationPropertyForOutlookItem(olItem, name, value.ToString()); } /// - /// Find any existing Outlook items which appear to be identical to this CRM item. + /// Find any existing Outlook items which appear to be identical to this CRM item. /// /// The CRM item to match. /// A list of matching Outlook items. @@ -492,8 +537,9 @@ protected List> FindMatches(EntryValue crmItem) try { - result = SyncStateManager.Instance.GetSynchronisedItems>().Where(a => this.IsMatch(a.OutlookItem, crmItem)) - .ToList>(); + result = SyncStateManager.Instance.GetSynchronisedItems>() + .Where(a => IsMatch(a.OutlookItem, crmItem)) + .ToList(); } catch (Exception any) { @@ -505,32 +551,32 @@ protected List> FindMatches(EntryValue crmItem) } /// - /// Get the CRM entry id of this item, if it has one and is known. + /// Get the CRM entry id of this item, if it has one and is known. /// /// The item whose id is saught. /// The id, or null if it is not known. protected abstract CrmId GetCrmEntryId(OutlookItemType olItem); /// - /// Fetch the page of entries from this module starting at this offset. + /// Fetch the page of entries from this module starting at this offset. /// /// The offset into the resultset at which the page begins. /// A set of entries. protected virtual EntryList GetEntriesPage(int offset) { - return RestAPIWrapper.GetEntryList(this.DefaultCrmModule, - String.Format(fetchQueryPrefix, RestAPIWrapper.GetUserId()), - Properties.Settings.Default.SyncMaxRecords, "date_start DESC", offset, false, - RestAPIWrapper.GetSugarFields(this.DefaultCrmModule)); + return RestAPIWrapper.GetEntryList(DefaultCrmModule, + string.Format(fetchQueryPrefix, RestAPIWrapper.GetUserId()), + Settings.Default.SyncMaxRecords, "date_start DESC", offset, false, + RestAPIWrapper.GetSugarFields(DefaultCrmModule)); } /// - /// Check whether this synchroniser is allowed import access for its default CRM module. + /// Check whether this synchroniser is allowed import access for its default CRM module. /// /// true if this synchroniser is allowed import access for its default CRM module. protected bool HasImportAccess() { - return this.permissionsCache.HasImportAccess(this.DefaultCrmModule); + return permissionsCache.HasImportAccess(DefaultCrmModule); } protected virtual void InstallEventHandlers() @@ -548,10 +594,10 @@ protected virtual void InstallEventHandlers() } /// - /// Return true if this Outlook item appears to represent the same item as this CRM item. + /// Return true if this Outlook item appears to represent the same item as this CRM item. /// /// - /// Intended to help block howlaround. + /// Intended to help block howlaround. /// /// The Outlook item. /// The CRM item. @@ -598,16 +644,17 @@ protected void Items_ItemRemove() } /// - /// Fetch records in pages from CRM, and merge them into Outlook. + /// Fetch records in pages from CRM, and merge them into Outlook. /// /// The folder to be synchronised. /// The name of the CRM module to synchronise with. /// A list of all known Outlook items, from which those modified by this method are removed. - protected virtual IList MergeRecordsFromCrm(Outlook.MAPIFolder folder, string crmModule, HashSet> untouched) + protected virtual IList MergeRecordsFromCrm(MAPIFolder folder, string crmModule, + HashSet> untouched) { - int thisOffset = 0; // offset of current page of entries - int nextOffset = 0; // offset of the next page of entries, if any. - List result = new List(); + var thisOffset = 0; // offset of current page of entries + var nextOffset = 0; // offset of the next page of entries, if any. + var result = new List(); /* get candidates for syncrhonisation from SuiteCRM one page at a time */ do @@ -615,7 +662,7 @@ protected virtual IList MergeRecordsFromCrm(Outlook.MAPIFolder folde /* update the offset to the offset of the next page */ thisOffset = nextOffset; - EntryList entriesPage = GetEntriesPage(thisOffset); + var entriesPage = GetEntriesPage(thisOffset); /* get the offset of the next page */ nextOffset = entriesPage.next_offset; @@ -630,7 +677,7 @@ protected virtual IList MergeRecordsFromCrm(Outlook.MAPIFolder folde } /// - /// A hook to allow specialisations to do something additional to just syncing in their iterations. + /// A hook to allow specialisations to do something additional to just syncing in their iterations. /// protected virtual void OtherIterationActions() { @@ -638,7 +685,7 @@ protected virtual void OtherIterationActions() } /// - /// Entry point from event handler when an item is added in Outlook. + /// Entry point from event handler when an item is added in Outlook. /// /// Should always run in the 'VSTA_main' thread. /// Shouldn't happen here. @@ -646,10 +693,9 @@ protected virtual void OtherIterationActions() protected virtual void OutlookItemAdded(OutlookItemType olItem) { if (Globals.ThisAddIn.IsLicensed) - { try { - OutlookItemAdded(olItem, this); + OutlookItemAdded(olItem, this); } catch (Exception any) { @@ -658,19 +704,15 @@ protected virtual void OutlookItemAdded(OutlookItemType olItem) finally { if (olItem != null) - { SaveItem(olItem); - } } - } else - { - Log.Warn($"Synchroniser.OutlookItemAdded: item {this.GetOutlookEntryId(olItem)} not added because not licensed"); - } + Log.Warn( + $"Synchroniser.OutlookItemAdded: item {GetOutlookEntryId(olItem)} not added because not licensed"); } /// - /// #2246: Nasty workaround for the fact that Outlook 'Appointments' and 'Meetings' are actually the same class. + /// #2246: Nasty workaround for the fact that Outlook 'Appointments' and 'Meetings' are actually the same class. /// /// The type of sync state to use. /// The Outlook item which has been added. @@ -678,20 +720,19 @@ protected virtual void OutlookItemAdded(OutlookItemType olItem) protected void OutlookItemAdded(OutlookItemType olItem, Synchroniser synchroniser) where T : SyncState { - LogItemAction(olItem, $"{this.GetType().Name}.OutlookItemAdded: {this.GetOutlookEntryId(olItem)}"); + LogItemAction(olItem, $"{GetType().Name}.OutlookItemAdded: {GetOutlookEntryId(olItem)}"); { lock (enqueueingLock) { if (SyncStateManager.Instance.GetExistingSyncState(olItem) == null) { - T state = SyncStateManager.Instance.GetOrCreateSyncState(olItem) as T; + var state = SyncStateManager.Instance.GetOrCreateSyncState(olItem) as T; if (state != null) { - if (olItem != null && this.ShouldAddOrUpdateItemFromOutlookToCrm(olItem)) - { - DaemonWorker.Instance.AddTask(new TransmitNewAction(synchroniser, state)); - } + if (olItem != null && ShouldAddOrUpdateItemFromOutlookToCrm(olItem)) + DaemonWorker.Instance.AddTask( + new TransmitNewAction(synchroniser, state)); } else { @@ -700,46 +741,42 @@ protected void OutlookItemAdded(OutlookItemType olItem, Synchroniser - /// Entry point from event handler, called when an Outlook item of class AppointmentItem - /// is believed to have changed. + /// Entry point from event handler, called when an Outlook item of class AppointmentItem + /// is believed to have changed. /// /// The item which has changed. protected virtual void OutlookItemChanged(OutlookItemType olItem) { if (Globals.ThisAddIn.IsLicensed) - { try { - OutlookItemChanged(olItem, this); + OutlookItemChanged(olItem, this); } catch (BadStateTransition bst) { if (bst.From != TransmissionState.Transmitted) - { throw; - } /* couldn't set pending -> transmission is in progress */ } finally { - this.SaveItem(olItem); + SaveItem(olItem); } - } else - { - Log.Warn($"Synchroniser.OutlookItemAdded: item {this.GetOutlookEntryId(olItem)} not updated because not licensed"); - } + Log.Warn( + $"Synchroniser.OutlookItemAdded: item {GetOutlookEntryId(olItem)} not updated because not licensed"); } /// - /// #2246: Nasty workaround for the fact that Outlook 'Appointments' and 'Meetings' are actually the same class. + /// #2246: Nasty workaround for the fact that Outlook 'Appointments' and 'Meetings' are actually the same class. /// /// The type of sync state to use. /// The Outlook item which has been changed. @@ -747,49 +784,38 @@ protected virtual void OutlookItemChanged(OutlookItemType olItem) protected void OutlookItemChanged(OutlookItemType olItem, Synchroniser synchroniser) where T : SyncState { - LogItemAction(olItem, $"{this.GetType().Name}.OutlookItemChanged: {this.GetOutlookEntryId(olItem)}"); + LogItemAction(olItem, $"{GetType().Name}.OutlookItemChanged: {GetOutlookEntryId(olItem)}"); SyncState state = SyncStateManager.Instance.GetExistingSyncState(olItem); - T syncStateForItem = state as T; + var syncStateForItem = state as T; if (syncStateForItem != null) - { try { syncStateForItem.SetPending(); - if (this.ShouldPerformSyncNow(syncStateForItem)) - { - DaemonWorker.Instance.AddTask(new TransmitUpdateAction(synchroniser, syncStateForItem)); - } + if (ShouldPerformSyncNow(syncStateForItem)) + DaemonWorker.Instance.AddTask( + new TransmitUpdateAction(synchroniser, syncStateForItem)); else if (!syncStateForItem.ShouldSyncWithCrm) - { - this.RemoveFromCrm(syncStateForItem); - } + RemoveFromCrm(syncStateForItem); } catch (BadStateTransition bst) { if (bst.From != TransmissionState.Transmitted) - { throw; - } } - } else - { - /* we don't have a sync state for this item (presumably formerly private); - * that's OK, treat it as new */ OutlookItemAdded(olItem); - } } /// - /// Parse a date time object from a user property, assuming the ISO 8601 date-time - /// format but ommitting the 'T'. (why? I don't know. TODO: possibly fix). + /// Parse a date time object from a user property, assuming the ISO 8601 date-time + /// format but ommitting the 'T'. (why? I don't know. TODO: possibly fix). /// /// - /// If the expected format is not recognised, a second scan is attempted without a - /// specific format; if this fails, it fails silently and the current time is returned. + /// If the expected format is not recognised, a second scan is attempted without a + /// specific format; if this fails, it fails silently and the current time is returned. /// /// A property value believed to contain a date time string. /// A date time object. @@ -797,15 +823,14 @@ protected DateTime ParseDateTimeFromUserProperty(string propertyValue) { if (propertyValue == null) return default(DateTime); var modDateTime = DateTime.UtcNow; - if (!DateTime.TryParseExact(propertyValue, "yyyy-MM-dd HH:mm:ss", null, DateTimeStyles.None, out modDateTime)) - { + if (!DateTime.TryParseExact(propertyValue, "yyyy-MM-dd HH:mm:ss", null, DateTimeStyles.None, + out modDateTime)) DateTime.TryParse(propertyValue, out modDateTime); - } return modDateTime; } /// - /// Deal, in CRM, with items deleted in Outlook. + /// Deal, in CRM, with items deleted in Outlook. /// protected void RemoveDeletedItems() { @@ -814,8 +839,8 @@ protected void RemoveDeletedItems() foreach (var syncState in syncStatesCopy) { var shouldDeleteFromCrm = syncState.IsDeletedInOutlook || !syncState.ShouldSyncWithCrm; - if (shouldDeleteFromCrm) { RemoveFromCrm(syncState); } - if (syncState.IsDeletedInOutlook) { SyncStateManager.Instance.RemoveSyncState(syncState); } + if (shouldDeleteFromCrm) RemoveFromCrm(syncState); + if (syncState.IsDeletedInOutlook) SyncStateManager.Instance.RemoveSyncState(syncState); } } @@ -832,7 +857,7 @@ protected virtual void RemoveEventHandlers() } /// - /// Remove the item implied by this sync state from CRM. + /// Remove the item implied by this sync state from CRM. /// /// A sync state wrapping an item which has been deleted or marked private in Outlook. protected virtual void RemoveFromCrm(SyncState state) @@ -840,9 +865,9 @@ protected virtual void RemoveFromCrm(SyncState state) if (SyncDirection.AllowOutbound(Direction)) { var crmEntryId = state.CrmEntryId; - if (state.ExistedInCrm && this.permissionsCache.HasImportAccess(state.CrmType)) + if (state.ExistedInCrm && permissionsCache.HasImportAccess(state.CrmType)) { - NameValue[] data = new NameValue[2]; + var data = new NameValue[2]; data[0] = RestAPIWrapper.SetNameValuePair("id", crmEntryId); data[1] = RestAPIWrapper.SetNameValuePair("deleted", "1"); RestAPIWrapper.SetEntry(data, state.CrmType); @@ -853,63 +878,57 @@ protected virtual void RemoveFromCrm(SyncState state) } /// - /// Remove an outlook item and its associated sync state. + /// Remove an outlook item and its associated sync state. /// /// The sync state of the item to remove. protected void RemoveItemAndSyncState(SyncState syncState) { - this.LogItemAction(syncState.OutlookItem, "Synchroniser.RemoveItemAndSyncState, deleting item"); + LogItemAction(syncState.OutlookItem, "Synchroniser.RemoveItemAndSyncState, deleting item"); try { syncState.DeleteItem(); } catch (Exception ex) { - ErrorHandler.Handle($"Failed while trying to delete a {this.DefaultCrmModule} item", ex); + ErrorHandler.Handle($"Failed while trying to delete a {DefaultCrmModule} item", ex); } - this.RemoveItemSyncState(syncState); + RemoveItemSyncState(syncState); } /// - /// Remove an item from ItemsSyncState. + /// Remove an item from ItemsSyncState. /// /// The sync state of the item to remove. protected void RemoveItemSyncState(SyncState item) { - this.LogItemAction(item.OutlookItem, "Synchroniser.RemoveItemSyncState, removed item from queue"); + LogItemAction(item.OutlookItem, "Synchroniser.RemoveItemSyncState, removed item from queue"); SyncStateManager.Instance.RemoveSyncState(item); } /// - /// Given a list of items which exist in Outlook but are missing from CRM, resolve - /// how to handle them. + /// Given a list of items which exist in Outlook but are missing from CRM, resolve + /// how to handle them. /// /// The list of items to resolve. protected virtual void ResolveUnmatchedItems(IEnumerable> itemsToResolve) { foreach (var unresolved in itemsToResolve) - { switch (unresolved.TxState) { case TransmissionState.PendingDeletion: /* If it's to resolve and marked pending deletion, we delete it * (unresolved on two successive iterations): */ - this.RemoveItemAndSyncState(unresolved); + RemoveItemAndSyncState(unresolved); break; case TransmissionState.Synced: if (unresolved.ExistedInCrm) - { - /* if it's unresolved but it used to exist in CRM, it's probably been deleted from - * CRM. Mark it pending deletion and check again next iteration. */ unresolved.SetPendingDeletion(); - } break; case TransmissionState.Pending: case TransmissionState.PresentAtStartup: if (unresolved.ShouldSyncWithCrm) - { try { /* if it's unresolved, pending, and should be synced send it. */ @@ -920,12 +939,10 @@ protected virtual void ResolveUnmatchedItems(IEnumerable() - .Where(s => s.TxState == TransmissionState.PendingDeletion && - !itemsToResolve.Contains(s))) - { + .Where(s => s.TxState == TransmissionState.PendingDeletion && + !itemsToResolve.Contains(s))) /* finally, if there exists an item which had been marked pending deletion, but it has - * been found in CRM (i.e. not in unresolved), mark it as synced */ - ((SyncState)resolved).SetSynced(); - } + * been found in CRM (i.e. not in unresolved), mark it as synced */ + ((SyncState) resolved).SetSynced(); } /// - /// Save this item. + /// Save this item. /// /// - /// Because Outlook items are not proper objects, you cannot call the Save method of - /// an Outlook item without knowing its exact class explicitly. So there are what look - /// like redundant specialisations of this method; they aren't. + /// + /// Because Outlook items are not proper objects, you cannot call the Save method of + /// an Outlook item without knowing its exact class explicitly. So there are what look + /// like redundant specialisations of this method; they aren't. + /// + /// Note that we must be able to save an item whether or not the synchroniser is enabled. /// /// The item to save. protected abstract void SaveItem(OutlookItemType olItem); /// - /// Specialisations should return false if there's a good reason why we should - /// NOT sync this item. + /// Specialisations should return false if there's a good reason why we should + /// NOT sync this item. /// /// The folder to synchronise into. /// The CRM type of the candidate item. /// The candidate item from CRM. /// true - protected virtual bool ShouldAddOrUpdateItemFromCrmToOutlook(Outlook.MAPIFolder folder, string crmType, EntryValue crmItem) + protected virtual bool ShouldAddOrUpdateItemFromCrmToOutlook(MAPIFolder folder, string crmType, + EntryValue crmItem) { return true; } /// - /// Perform all the necessary checking before adding or updating an item on CRM. + /// Perform all the necessary checking before adding or updating an item on CRM. /// /// - /// TODO TODO TODO: This does NOT actually do all the checking. Checking is also - /// done in SyncState.ShouldSyncWithCRM, and possibly other places. Fix. + /// TODO TODO TODO: This does NOT actually do all the checking. Checking is also + /// done in SyncState.ShouldSyncWithCRM, and possibly other places. Fix. /// - /// The item we may seek to add or update, presumed to be of - /// my default item type. + /// + /// The item we may seek to add or update, presumed to be of + /// my default item type. + /// /// true if we may attempt to add or update that item. protected virtual bool ShouldAddOrUpdateItemFromOutlookToCrm(OutlookItemType olItem) { bool result; - string prefix = "Synchoniser.ShouldAddOrUpdateItemFromOutlookToCrm"; + var prefix = "Synchoniser.ShouldAddOrUpdateItemFromOutlookToCrm"; try { if (olItem == null) { - Log.Warn($"{prefix}: attempt to send null {this.DefaultCrmModule}?"); + Log.Warn($"{prefix}: attempt to send null to {DefaultCrmModule}?"); result = false; } else { if (SyncDirection.AllowOutbound(Direction)) { - if (this.permissionsCache.HasImportAccess(this.DefaultCrmModule)) + if (permissionsCache.HasImportAccess(DefaultCrmModule)) { - if (this.GetSensitivity(olItem) == Outlook.OlSensitivity.olNormal) + if (GetSensitivity(olItem) == OlSensitivity.olNormal) { result = true; } else { - Log.Info($"{prefix}: {this.DefaultCrmModule} not added to CRM because its sensitivity is not public."); + Log.Info( + $"{prefix}: {DefaultCrmModule} not added to CRM because its sensitivity is not public."); result = false; } } else { - Log.Info($"{prefix}: {this.DefaultCrmModule} not added to CRM because import access is not granted."); + Log.Info( + $"{prefix}: {DefaultCrmModule} not added to CRM because import access is not granted."); result = false; } } else { - Log.Info($"{prefix}: {this.DefaultCrmModule} not added to CRM because synchronisation is not enabled."); + Log.Info( + $"{prefix}: {DefaultCrmModule} not added to CRM because synchronisation is not enabled."); result = false; } } } catch (Exception any) { - ErrorHandler.Handle($"Unexpected failure while checking {this.DefaultCrmModule}.", any); + ErrorHandler.Handle($"Unexpected failure while checking {DefaultCrmModule}.", any); result = false; } @@ -1039,27 +1061,25 @@ protected virtual bool ShouldAddOrUpdateItemFromOutlookToCrm(OutlookItemType olI } /// - /// Should the item represented by this sync state be synchronised now? + /// Should the item represented by this sync state be synchronised now? /// /// The sync state under consideration. /// True if this synchroniser relates to the current tab and the timing logic is satisfied. protected bool ShouldPerformSyncNow(SyncState syncState) { - return (syncState.ShouldPerformSyncNow()); + return syncState.ShouldPerformSyncNow(); } /// - /// Add the magic 'SuiteCRM' category to the Outlook mapi namespace, if it does not - /// already exist. + /// Add the magic 'SuiteCRM' category to the Outlook mapi namespace, if it does not + /// already exist. /// private void AddSuiteCrmOutlookCategory() { - Outlook.NameSpace oNS = this.Application.GetNamespace("mapi"); + var oNS = Application.GetNamespace("mapi"); if (oNS.Categories["SuiteCRM"] == null) - { - oNS.Categories.Add("SuiteCRM", Outlook.OlCategoryColor.olCategoryColorGreen, - Outlook.OlCategoryShortcutKey.olCategoryShortcutKeyNone); - } + oNS.Categories.Add("SuiteCRM", OlCategoryColor.olCategoryColorGreen, + OlCategoryShortcutKey.olCategoryShortcutKeyNone); } } -} +} \ No newline at end of file diff --git a/SuiteCRMAddIn/BusinessLogic/TaskSynchroniser.cs b/SuiteCRMAddIn/BusinessLogic/TaskSynchroniser.cs index bd846b5e..672cade9 100644 --- a/SuiteCRMAddIn/BusinessLogic/TaskSynchroniser.cs +++ b/SuiteCRMAddIn/BusinessLogic/TaskSynchroniser.cs @@ -351,7 +351,7 @@ protected override CrmId ConstructAndDespatchCrmItem(Outlook.TaskItem olItem) } - protected override void GetOutlookItems(Outlook.MAPIFolder taskFolder) + protected override void LinkOutlookItems(Outlook.MAPIFolder taskFolder) { try { From 121bff1bd72177c335c8ae0cb9098edf6fb7108e Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Thu, 6 Dec 2018 12:34:44 +0000 Subject: [PATCH 06/13] 4509: build 3.0.16.26 Should be a good fix. --- Doxyfile | 2 +- README.md | 2 +- .../BusinessLogic/AppointmentsSynchroniser.cs | 677 +++++++++--------- .../BusinessLogic/ContactSynchroniser.cs | 4 +- .../BusinessLogic/TaskSynchroniser.cs | 4 +- SuiteCRMAddIn/Dialogs/ClearCrmIdsDialog.cs | 2 +- SuiteCRMAddIn/Properties/AssemblyInfo.cs | 2 +- SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl | 2 +- SuiteCRMClient/Properties/AssemblyInfo.cs | 2 +- 9 files changed, 334 insertions(+), 363 deletions(-) diff --git a/Doxyfile b/Doxyfile index 3a4fb719..c9a29e01 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "SuiteCRM Outlook Add-in" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 3.0.16.24 +PROJECT_NUMBER = 3.0.16.26 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/README.md b/README.md index e8227fb2..d080612f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ### What's in this repository -SuiteCRM Outlook Plug-In v 3.0.16.24 +SuiteCRM Outlook Plug-In v 3.0.16.26 This repository has been created to allow community members to collaborate and contribute to the project. diff --git a/SuiteCRMAddIn/BusinessLogic/AppointmentsSynchroniser.cs b/SuiteCRMAddIn/BusinessLogic/AppointmentsSynchroniser.cs index 7c23dd18..38b01280 100644 --- a/SuiteCRMAddIn/BusinessLogic/AppointmentsSynchroniser.cs +++ b/SuiteCRMAddIn/BusinessLogic/AppointmentsSynchroniser.cs @@ -22,42 +22,53 @@ */ +#region + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using Microsoft.Office.Interop.Outlook; +using SuiteCRMAddIn.Exceptions; +using SuiteCRMAddIn.Extensions; +using SuiteCRMAddIn.Properties; +using SuiteCRMAddIn.ProtoItems; +using SuiteCRMClient; +using SuiteCRMClient.Logging; +using SuiteCRMClient.RESTObjects; +using Exception = System.Exception; + +#endregion + namespace SuiteCRMAddIn.BusinessLogic { - using Exceptions; - using Extensions; - using ProtoItems; - using SuiteCRMClient; - using SuiteCRMClient.Logging; - using SuiteCRMClient.RESTObjects; - using System; - using System.Collections.Generic; - using System.Linq; - using System.Runtime.InteropServices; - using System.Text; - using Outlook = Microsoft.Office.Interop.Outlook; - /// - /// Handles the synchronisation of appointments between Outlook and CMS. + /// Handles the synchronisation of appointments between Outlook and CMS. /// - public abstract class AppointmentsSynchroniser : Synchroniser - where SyncStateType : SyncState + public abstract class AppointmentsSynchroniser : Synchroniser + where SyncStateType : SyncState { /// - /// The name of the organiser synchronisation property + /// The name of the organiser synchronisation property /// public const string OrganiserPropertyName = "SOrganiser"; /// - /// Microsoft Conferencing Add-in creates temporary items whose names begin - /// 'PLEASE IGNORE'. We should not sync these. + /// Microsoft Conferencing Add-in creates temporary items whose names begin + /// 'PLEASE IGNORE'. We should not sync these. /// public const string MSConfTmpSubjectPrefix = "PLEASE IGNORE"; /// - /// A cache of email addresses to CRM modules and identities + /// Prefix for meetings which have been canceled. /// - protected Dictionary> meetingRecipientsCache = + private const string CanceledPrefix = "CANCELED"; + + /// + /// A cache of email addresses to CRM modules and identities + /// + protected Dictionary> meetingRecipientsCache = new Dictionary>(); @@ -65,127 +76,113 @@ public AppointmentsSynchroniser(string name, SyncContext context) : base(name, context) { // TODO: Also need to fetch appointments to which the current user is invited. - this.fetchQueryPrefix = new StringBuilder("assigned_user_id = '{0}'") - .Append($" and date_start > '{string.Format("{0:yyyy-MM-dd HH:mm:ss}", GetStartDate())}' ") .ToString(); + fetchQueryPrefix = new StringBuilder("assigned_user_id = '{0}'") + .Append($" and date_start > '{string.Format("{0:yyyy-MM-dd HH:mm:ss}", GetStartDate())}' ").ToString(); } /// - /// Get the id of the record with the specified `smtpAddress` in the module with the specified `moduleName`. + /// Get the id of the record with the specified `smtpAddress` in the module with the specified `moduleName`. /// /// The SMTP email address to be sought. /// The name of the module in which to seek it. /// The corresponding id, if present, else the empty string. public CrmId GetInviteeIdBySmtpAddress(string smtpAddress, string moduleName) { - StringBuilder bob = new StringBuilder( $"({moduleName.ToLower()}.id in ") - .Append( $"(select eabr.bean_id from email_addr_bean_rel eabr ") - .Append( $"INNER JOIN email_addresses ea on eabr.email_address_id = ea.id ") - .Append( $"where eabr.bean_module = '{moduleName}' ") - .Append( $"and ea.email_address LIKE '%{RestAPIWrapper.MySqlEscape(smtpAddress)}%'))"); + var bob = new StringBuilder($"({moduleName.ToLower()}.id in ") + .Append($"(select eabr.bean_id from email_addr_bean_rel eabr ") + .Append($"INNER JOIN email_addresses ea on eabr.email_address_id = ea.id ") + .Append($"where eabr.bean_module = '{moduleName}' ") + .Append($"and ea.email_address LIKE '%{RestAPIWrapper.MySqlEscape(smtpAddress)}%'))"); - string query = bob.ToString(); + var query = bob.ToString(); Log.Debug($"AppointmentSyncing.GetID: query = `{query}`"); - string[] fields = { "id" }; - EntryList entries = RestAPIWrapper.GetEntryList(moduleName, query, Properties.Settings.Default.SyncMaxRecords, "date_entered DESC", 0, false, fields); + string[] fields = {"id"}; + var entries = RestAPIWrapper.GetEntryList(moduleName, query, Settings.Default.SyncMaxRecords, + "date_entered DESC", 0, false, fields); - return entries.result_count > 0 ? - CrmId.Get(RestAPIWrapper.GetValueByKey(entries.entry_list[0], "id")) : - CrmId.Empty; + return entries.result_count > 0 + ? CrmId.Get(RestAPIWrapper.GetValueByKey(entries.entry_list[0], "id")) + : CrmId.Empty; } - public override Outlook.MAPIFolder GetDefaultFolder() + public override MAPIFolder GetDefaultFolder() { - return Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar); + return Application.Session.GetDefaultFolder(OlDefaultFolders.olFolderCalendar); } /// - /// #2246: Discriminate between calls and meetings when adding and updating. + /// #2246: Discriminate between calls and meetings when adding and updating. /// - protected override void OutlookItemAdded(Outlook.AppointmentItem olItem) + protected override void OutlookItemAdded(AppointmentItem olItem) { if (Globals.ThisAddIn.IsLicensed) - { try { var crmId = olItem.GetCrmId(); if (CrmId.IsValid(crmId)) { - AppointmentSyncState existing = + var existing = SyncStateManager.Instance.GetExistingSyncState(string.Empty, crmId) as AppointmentSyncState; /* we have an existing item with the same CRM id: suspicious */ if (existing != null && existing.OutlookItem.GetVCalId() != crmId.ToString()) { /* OK, its GlobalAppointmentId is wrong, it must have come via sync. Delete it. */ - Log.Debug($"Apparent case of item synced from CRM and then received via email/vCal. CRM id is {crmId}. Deleting bad copy."); - this.RemoveItemAndSyncState(existing); + Log.Debug( + $"Apparent case of item synced from CRM and then received via email/vCal. CRM id is {crmId}. Deleting bad copy."); + RemoveItemAndSyncState(existing); } } Log.Debug($"OutlookItemAdded, CRM id = {crmId}; Outlook ID = {olItem.EntryID}"); if (olItem.IsCall()) - { - base.OutlookItemAdded(olItem, Globals.ThisAddIn.CallsSynchroniser); - } + base.OutlookItemAdded(olItem, Globals.ThisAddIn.CallsSynchroniser); else - { - base.OutlookItemAdded(olItem, Globals.ThisAddIn.MeetingsSynchroniser); - } + base.OutlookItemAdded(olItem, Globals.ThisAddIn.MeetingsSynchroniser); } finally { SaveItem(olItem); } - } else - { - Log.Warn($"Synchroniser.OutlookItemAdded: item {this.GetOutlookEntryId(olItem)} not added because not licensed"); - } + Log.Warn( + $"Synchroniser.OutlookItemAdded: item {GetOutlookEntryId(olItem)} not added because not licensed"); } /// - /// #2246: Discriminate between calls and meetings when adding and updating. + /// #2246: Discriminate between calls and meetings when adding and updating. /// - protected override void OutlookItemChanged(Outlook.AppointmentItem olItem) + protected override void OutlookItemChanged(AppointmentItem olItem) { if (Globals.ThisAddIn.IsLicensed) - { try { var crmId = olItem.GetCrmId(); Log.Debug($"OutlookItemChanged, CRM id = {crmId}; Outlook ID = {olItem.EntryID}"); if (olItem.IsCall()) - { - base.OutlookItemChanged(olItem, Globals.ThisAddIn.CallsSynchroniser); - } + base.OutlookItemChanged(olItem, Globals.ThisAddIn.CallsSynchroniser); else - { - base.OutlookItemChanged(olItem, Globals.ThisAddIn.MeetingsSynchroniser); - } + base.OutlookItemChanged(olItem, Globals.ThisAddIn.MeetingsSynchroniser); } catch (BadStateTransition bst) { if (bst.To != TransmissionState.Transmitted) - { Log.Warn("Bad state transition in OutlookItemChanged", bst); - } } finally { - this.SaveItem(olItem); + SaveItem(olItem); } - } else - { - Log.Warn($"Synchroniser.OutlookItemAdded: item {this.GetOutlookEntryId(olItem)} not updated because not licensed"); - } + Log.Warn( + $"Synchroniser.OutlookItemAdded: item {GetOutlookEntryId(olItem)} not updated because not licensed"); } - protected override void SaveItem(Outlook.AppointmentItem olItem) + protected override void SaveItem(AppointmentItem olItem) { try { @@ -196,10 +193,11 @@ protected override void SaveItem(Outlook.AppointmentItem olItem) } catch (InvalidCrmIdException) { - Log.Debug($"AppointmentSyncing.SaveItem, saved item '{olItem.Subject}' {olItem.EntryID} (no valid CRM id)"); + Log.Debug( + $"AppointmentSyncing.SaveItem, saved item '{olItem.Subject}' {olItem.EntryID} (no valid CRM id)"); } } - catch (System.Exception any) + catch (Exception any) { try { @@ -207,31 +205,28 @@ protected override void SaveItem(Outlook.AppointmentItem olItem) } catch (COMException comx) { - ErrorHandler.Handle("Failure while trying to save appointment, appointment has probably been deleted.", comx); + ErrorHandler.Handle( + "Failure while trying to save appointment, appointment has probably been deleted.", comx); } } } - /// - /// Prefix for meetings which have been canceled. - /// - private const string CanceledPrefix = "CANCELED"; - /// - /// Ensure that this Outlook item has a property of this name with this value. + /// Ensure that this Outlook item has a property of this name with this value. /// /// The Outlook item. /// The name. /// The value. - protected override void EnsureSynchronisationPropertyForOutlookItem(Outlook.AppointmentItem olItem, string name, string value) + protected override void EnsureSynchronisationPropertyForOutlookItem(AppointmentItem olItem, string name, + string value) { try { - Outlook.UserProperty olProperty = olItem.UserProperties[name] ?? olItem.UserProperties.Add(name, Outlook.OlUserPropertyType.olText); + var olProperty = olItem.UserProperties[name] ?? + olItem.UserProperties.Add(name, OlUserPropertyType.olText); if (!olProperty.Value.Equals(value)) - { try { if (string.IsNullOrEmpty(value)) @@ -241,18 +236,19 @@ protected override void EnsureSynchronisationPropertyForOutlookItem(Outlook.Appo else { olProperty.Value = value; - Log.Debug($"AppointmentSyncing.EnsureSynchronisationPropertyForOutlookItem: Set property {name} to value {value} on item {olItem.Subject}"); + Log.Debug( + $"AppointmentSyncing.EnsureSynchronisationPropertyForOutlookItem: Set property {name} to value {value} on item {olItem.Subject}"); } } catch (Exception any) { - ErrorHandler.Handle($"Failed to set property {name} to value {value} on item {olItem.Subject}", any); + ErrorHandler.Handle($"Failed to set property {name} to value {value} on item {olItem.Subject}", + any); } finally { - this.SaveItem(olItem); + SaveItem(olItem); } - } } catch (Exception any) { @@ -262,57 +258,57 @@ protected override void EnsureSynchronisationPropertyForOutlookItem(Outlook.Appo /// - /// If a meeting was created in another Outlook we should NOT sync it with CRM because if we do we'll create - /// duplicates. Only the Outlook which created it should sync it. + /// If a meeting was created in another Outlook we should NOT sync it with CRM because if we do we'll create + /// duplicates. Only the Outlook which created it should sync it. /// /// The folder to synchronise into. /// The CRM type of the candidate item. /// The candidate item from CRM. /// True if it's offered to us by CRM with its Outlook ID already populated. - protected override bool ShouldAddOrUpdateItemFromCrmToOutlook(Outlook.MAPIFolder folder, string crmType, EntryValue crmItem) + protected override bool ShouldAddOrUpdateItemFromCrmToOutlook(MAPIFolder folder, string crmType, + EntryValue crmItem) { var outlookId = crmItem.GetValueAsString("outlook_id"); /* we're good if it's a meeting... */ - bool result = crmType == this.DefaultCrmModule; + var result = crmType == DefaultCrmModule; /* provided it doesn't already have an Outlook id */ result &= string.IsNullOrWhiteSpace(outlookId); /* and we're also good if we've already got it */ - result |= (SyncStateManager.Instance.GetExistingSyncState(crmItem) != null); + result |= SyncStateManager.Instance.GetExistingSyncState(crmItem) != null; if (!result) - { - Log.Debug($"ShouldAddOrUpdateItemFromCrmToOutlook: not syncing meeting `{crmItem.GetValueAsString("name")}` as it appears to originate from another Outlook instance."); - } + Log.Debug( + $"ShouldAddOrUpdateItemFromCrmToOutlook: not syncing meeting `{crmItem.GetValueAsString("name")}` as it appears to originate from another Outlook instance."); return result; } /// - /// Add an item existing in CRM but not found in Outlook to Outlook. + /// Add an item existing in CRM but not found in Outlook to Outlook. /// /// - /// This method is disconcertingly different from equivalent methods in other synchronisers; - /// TODO: the differences ought to be thought about. + /// This method is disconcertingly different from equivalent methods in other synchronisers; + /// TODO: the differences ought to be thought about. /// - /// + /// /// The Outlook folder in which the item should be stored. /// The CRM type of the item from which values are to be taken. /// The CRM item from which values are to be taken. /// The state date/time of the item, adjusted for timezone. /// A sync state object for the new item. protected virtual SyncStateType AddNewItemFromCrmToOutlook( - Outlook.MAPIFolder appointmentsFolder, + MAPIFolder appointmentsFolder, string crmType, EntryValue crmItem, DateTime dateStart) { SyncStateType newState = null; - Outlook.AppointmentItem olItem = null; + AppointmentItem olItem = null; Log.Debug( - (string)string.Format( - $"{this.GetType().Name}.AddNewItemFromCrmToOutlook, entry id is '{crmItem.GetValueAsString("id")}', creating in Outlook.")); + string.Format( + $"{GetType().Name}.AddNewItemFromCrmToOutlook, entry id is '{crmItem.GetValueAsString("id")}', creating in Outlook.")); try { @@ -325,7 +321,7 @@ protected virtual SyncStateType AddNewItemFromCrmToOutlook( */ lock (enqueueingLock) { - olItem = appointmentsFolder.Items.Add(Outlook.OlItemType.olAppointmentItem); + olItem = appointmentsFolder.Items.Add(OlItemType.olAppointmentItem); olItem.Subject = crmItem.GetValueAsString("name"); olItem.Body = crmItem.GetValueAsString("description"); @@ -360,12 +356,12 @@ protected virtual SyncStateType AddNewItemFromCrmToOutlook( /// - /// Set this outlook item's duration, but also end time and location, from this CRM item. + /// Set this outlook item's duration, but also end time and location, from this CRM item. /// /// The type of the CRM item. /// The CRM item. /// The Outlook item. - protected void SetOutlookItemDuration(string crmType, EntryValue crmItem, Outlook.AppointmentItem olItem) + protected void SetOutlookItemDuration(string crmType, EntryValue crmItem, AppointmentItem olItem) { try { @@ -377,63 +373,58 @@ protected void SetOutlookItemDuration(string crmType, EntryValue crmItem, Outloo } finally { - this.SaveItem(olItem); + SaveItem(olItem); } } /// - /// Set this outlook item's duration from this CRM item. + /// Set this outlook item's duration from this CRM item. /// /// The CRM item. /// The Outlook item. - protected virtual void SetOutlookItemDuration(EntryValue crmItem, Outlook.AppointmentItem olItem) + protected virtual void SetOutlookItemDuration(EntryValue crmItem, AppointmentItem olItem) { int minutes = 0, hours = 0; if (!string.IsNullOrWhiteSpace(crmItem.GetValueAsString("duration_minutes"))) - { minutes = int.Parse(crmItem.GetValueAsString("duration_minutes")); - } if (!string.IsNullOrWhiteSpace(crmItem.GetValueAsString("duration_hours"))) - { hours = int.Parse(crmItem.GetValueAsString("duration_hours")); - } - int durationMinutes = minutes + hours * 60; + var durationMinutes = minutes + hours * 60; olItem.Duration = durationMinutes; } /// - /// Specialisation: in addition to the standard properties, meetings also require an organiser property. + /// Specialisation: in addition to the standard properties, meetings also require an organiser property. /// /// The Outlook item. /// The CRM item. /// The value for the SType property (CRM module name). - protected override void EnsureSynchronisationPropertiesForOutlookItem(Outlook.AppointmentItem olItem, EntryValue crmItem, string type) + protected override void EnsureSynchronisationPropertiesForOutlookItem(AppointmentItem olItem, + EntryValue crmItem, string type) { base.EnsureSynchronisationPropertiesForOutlookItem(olItem, crmItem, type); - if (this.DefaultCrmModule.Equals(type)) - { - this.EnsureSynchronisationPropertyForOutlookItem(olItem, OrganiserPropertyName, crmItem.GetValueAsString("assigned_user_id")); - } + if (DefaultCrmModule.Equals(type)) + EnsureSynchronisationPropertyForOutlookItem(olItem, OrganiserPropertyName, + crmItem.GetValueAsString("assigned_user_id")); } /// - /// Add the item implied by this SyncState, which may not exist in CRM, to CRM. + /// Add the item implied by this SyncState, which may not exist in CRM, to CRM. /// /// The sync state. /// The id of the entry added or updated. - internal override CrmId AddOrUpdateItemFromOutlookToCrm(SyncState syncState) + internal override CrmId AddOrUpdateItemFromOutlookToCrm(SyncState syncState) { - Outlook.AppointmentItem olItem = syncState.OutlookItem; + var olItem = syncState.OutlookItem; try { - CrmId result = CrmId.Empty; + var result = CrmId.Empty; - if (this.ShouldAddOrUpdateItemFromOutlookToCrm(olItem)) - { + if (ShouldAddOrUpdateItemFromOutlookToCrm(olItem)) if (ShouldDeleteFromCrm(olItem)) { LogItemAction(olItem, "AppointmentSyncing.AddOrUpdateItemFromOutlookToCrm: Deleting"); @@ -445,141 +436,124 @@ internal override CrmId AddOrUpdateItemFromOutlookToCrm(SyncState - /// Construct a JSON packet representing this Outlook item, and despatch it to CRM. + /// Construct a JSON packet representing this Outlook item, and despatch it to CRM. /// /// The Outlook item. /// The CRM id of the object created or modified. - protected override CrmId ConstructAndDespatchCrmItem(Outlook.AppointmentItem olItem) + protected override CrmId ConstructAndDespatchCrmItem(AppointmentItem olItem) { - return CrmId.Get(RestAPIWrapper.SetEntry(new ProtoAppointment(olItem).AsNameValues(), this.DefaultCrmModule)); + return CrmId.Get(RestAPIWrapper.SetEntry(new ProtoAppointment(olItem).AsNameValues(), + DefaultCrmModule)); } /// - /// Delete this Outlook item from CRM, and tidy up afterwards. + /// Delete this Outlook item from CRM, and tidy up afterwards. /// /// The Outlook item to delete. - private void DeleteFromCrm(Outlook.AppointmentItem olItem) + private void DeleteFromCrm(AppointmentItem olItem) { if (olItem != null) { /* Remove the magic properties */ RemoveSynchronisationPropertiesFromOutlookItem(olItem); - SyncState syncStateForItem = SyncStateManager.Instance.GetExistingSyncState(olItem); + var syncStateForItem = SyncStateManager.Instance.GetExistingSyncState(olItem); if (syncStateForItem != null) { - this.RemoveFromCrm(syncStateForItem); - this.RemoveItemSyncState(syncStateForItem); + RemoveFromCrm(syncStateForItem); + RemoveItemSyncState(syncStateForItem); } } } /// - /// Get all items in this appointments folder. Should be called just once (per folder?) - /// when the add-in starts up; initialises the SyncState list. + /// Get all items in this appointments folder. Should be called just once (per folder?) + /// when the add-in starts up; initialises the SyncState list. /// /// The folder to scan. - protected override void LinkOutlookItems(Outlook.MAPIFolder appointmentsFolder) + protected override void LinkOutlookItems(MAPIFolder appointmentsFolder) { try { - List deletionCandidates = new List(); - foreach (Outlook.AppointmentItem olItem in appointmentsFolder.Items) - { + var deletionCandidates = new List(); + foreach (AppointmentItem olItem in appointmentsFolder.Items) try { - if (olItem.Start >= this.GetStartDate()) + if (olItem.Start >= GetStartDate()) { - Outlook.UserProperty olPropertyModified = olItem.UserProperties[SyncStateManager.ModifiedDatePropertyName]; - Outlook.UserProperty olPropertyType = olItem.UserProperties[SyncStateManager.TypePropertyName]; - Outlook.UserProperty olPropertyEntryId = olItem.UserProperties[SyncStateManager.CrmIdPropertyName]; + var olPropertyModified = olItem.UserProperties[SyncStateManager.ModifiedDatePropertyName]; + var olPropertyType = olItem.UserProperties[SyncStateManager.TypePropertyName]; + var olPropertyEntryId = olItem.UserProperties[SyncStateManager.CrmIdPropertyName]; if (olPropertyModified != null && olPropertyType != null && olPropertyEntryId != null) - { - /* The appointment probably already has the three magic properties - * required for synchronisation; is that a proxy for believing that it - * already exists in CRM? If so, is it reliable? */ - LogItemAction(olItem, "AppointmentSyncing.LinkOutlookItems: Adding known item to queue"); - } + LogItemAction(olItem, + "AppointmentSyncing.LinkOutlookItems: Adding known item to queue"); else - { - LogItemAction(olItem, "AppointmentSyncing.LinkOutlookItems: Adding unknown item to queue"); - } + LogItemAction(olItem, + "AppointmentSyncing.LinkOutlookItems: Adding unknown item to queue"); SyncStateManager.Instance.GetOrCreateSyncState(olItem).SetPresentAtStartup(); } } - catch (ProbableDuplicateItemException) + catch (ProbableDuplicateItemException) { deletionCandidates.Add(olItem); } - } - + foreach (var toDelete in deletionCandidates) - { toDelete.Delete(); - } } catch (Exception ex) { - ErrorHandler.Handle($"Failed while trying to index {this.DefaultCrmModule}", ex); + ErrorHandler.Handle($"Failed while trying to index {DefaultCrmModule}", ex); } } /// - /// Log a message regarding this Outlook appointment. + /// Log a message regarding this Outlook appointment. /// /// The outlook item. /// The message to be logged. - internal override void LogItemAction(Outlook.AppointmentItem olItem, string message) + internal override void LogItemAction(AppointmentItem olItem, string message) { try { - CrmId crmId = olItem.GetCrmId(); - if (CrmId.IsInvalid(crmId)) { crmId = CrmId.Empty; } + var crmId = IsEnabled() ? olItem.GetCrmId() : CrmId.Empty; + if (CrmId.IsInvalid(crmId)) crmId = CrmId.Empty; - StringBuilder bob = new StringBuilder(); + var bob = new StringBuilder(); bob.Append($"{message}:\n\tOutlook Id : {olItem.EntryID}") .Append($"\n\tGlobal Id : {olItem.GlobalAppointmentID}") - .Append($"\n\tCRM Id : {crmId}") + .Append(this.IsEnabled() ? $"\n\tCRM Id : {crmId}" : string.Empty) .Append($"\n\tSubject : '{olItem.Subject}'") .Append($"\n\tSensitivity : {olItem.Sensitivity}") .Append($"\n\tStatus : {olItem.MeetingStatus}") @@ -589,10 +563,9 @@ internal override void LogItemAction(Outlook.AppointmentItem olItem, string mess .Append($"\n\tTxState : {SyncStateManager.Instance.GetExistingSyncState(olItem)?.TxState}") .Append($"\n\tRecipients :\n"); - foreach (Outlook.Recipient recipient in olItem.Recipients) - { - bob.Append($"\t\t{recipient.Name}: {recipient.GetSmtpAddress()} - ({recipient.MeetingResponseStatus})\n"); - } + foreach (Recipient recipient in olItem.Recipients) + bob.Append( + $"\t\t{recipient.Name}: {recipient.GetSmtpAddress()} - ({recipient.MeetingResponseStatus})\n"); Log.Info(bob.ToString()); } catch (COMException) @@ -603,22 +576,22 @@ internal override void LogItemAction(Outlook.AppointmentItem olItem, string mess /// - /// Update a single appointment in the specified Outlook folder with changes from CRM, but - /// only if its start date is fewer than five days in the past. + /// Update a single appointment in the specified Outlook folder with changes from CRM, but + /// only if its start date is fewer than five days in the past. /// /// The folder to synchronise into. /// The CRM type of the candidate item. /// The candidate item from CRM. /// The synchronisation state of the item updated (if it was updated). - protected override SyncState AddOrUpdateItemFromCrmToOutlook( - Outlook.MAPIFolder folder, + protected override SyncState AddOrUpdateItemFromCrmToOutlook( + MAPIFolder folder, string crmType, EntryValue crmItem) { - SyncState existing = SyncStateManager.Instance.GetExistingSyncState(crmItem); - SyncStateType result = existing as SyncStateType; + var existing = SyncStateManager.Instance.GetExistingSyncState(crmItem); + var result = existing as SyncStateType; - DateTime dateStart = crmItem.GetValueAsDateTime("date_start"); + var dateStart = crmItem.GetValueAsDateTime("date_start"); if (dateStart >= GetStartDate()) { @@ -626,7 +599,7 @@ internal override void LogItemAction(Outlook.AppointmentItem olItem, string mess if (existing == null) { /* check for howlaround */ - var matches = this.FindMatches(crmItem); + var matches = FindMatches(crmItem); if (matches.Count == 0) { @@ -644,13 +617,14 @@ internal override void LogItemAction(Outlook.AppointmentItem olItem, string mess { result.CrmEntryId = crmId; result.OutlookItem.SetCrmId(crmId); - this.UpdateExistingOutlookItemFromCrm(crmType, crmItem, dateStart, result); + UpdateExistingOutlookItemFromCrm(crmType, crmItem, dateStart, result); } } else { result = matches.ElementAt(0) as SyncStateType; - this.Log.Warn($"Howlaround detected? Appointment '{crmItem.GetValueAsString("name")}' offered with id {crmId}, expected {matches[0].CrmEntryId}, {matches.Count} duplicates"); + Log.Warn( + $"Howlaround detected? Appointment '{crmItem.GetValueAsString("name")}' offered with id {crmId}, expected {matches[0].CrmEntryId}, {matches.Count} duplicates"); } } } @@ -661,7 +635,7 @@ internal override void LogItemAction(Outlook.AppointmentItem olItem, string mess } else { - throw new UnexpectedSyncStateClassException($"{this.GetType().Name}", existing); + throw new UnexpectedSyncStateClassException($"{GetType().Name}", existing); } existing?.SaveItem(); @@ -670,152 +644,152 @@ internal override void LogItemAction(Outlook.AppointmentItem olItem, string mess return result; } - internal override void HandleItemMissingFromOutlook(SyncState syncState) + internal override void HandleItemMissingFromOutlook(SyncState syncState) { if (syncState.CrmType == MeetingsSynchroniser.CrmModule) { /* typically, when this method is called, the Outlook Item will already be invalid, and if it is not, * it may become invalid during the execution of this method. So this method CANNOT depend on any * values taken from the Outlook item. */ - EntryList entries = RestAPIWrapper.GetEntryList( + var entries = RestAPIWrapper.GetEntryList( syncState.CrmType, $"id = {syncState.CrmEntryId}", - Properties.Settings.Default.SyncMaxRecords, + Settings.Default.SyncMaxRecords, "date_entered DESC", 0, false, null); if (entries.entry_list.Any()) - { - this.HandleItemMissingFromOutlook(entries.entry_list[0], syncState, syncState.CrmType); - } + HandleItemMissingFromOutlook(entries.entry_list[0], syncState, syncState.CrmType); } } - /// - /// Sets up a CRM relationship to mimic an Outlook relationship + /// Sets up a CRM relationship to mimic an Outlook relationship /// /// The synchroniser tp forward to. /// The ID of the appointment. /// The outlook recipient representing the person to link with. /// the name of the module we're seeking to link with. /// True if a relationship was created. - protected CrmId SetCrmRelationshipFromOutlook(Synchroniser sync, CrmId meetingId, Outlook.Recipient recipient, string foreignModule) + protected CrmId SetCrmRelationshipFromOutlook(Synchroniser sync, CrmId meetingId, + Recipient recipient, string foreignModule) where T : class where S : SyncState { - CrmId foreignId = GetInviteeIdBySmtpAddress(recipient.GetSmtpAddress(), foreignModule); + var foreignId = GetInviteeIdBySmtpAddress(recipient.GetSmtpAddress(), foreignModule); return CrmId.IsValid(foreignId) && - SetCrmRelationshipFromOutlook(sync, meetingId, foreignModule, foreignId) ? - foreignId : - CrmId.Empty; + SetCrmRelationshipFromOutlook(sync, meetingId, foreignModule, foreignId) + ? foreignId + : CrmId.Empty; } /// - /// Sets up a CRM relationship to mimic an Outlook relationship + /// Sets up a CRM relationship to mimic an Outlook relationship /// /// the synchroniser to despatch to /// The meeting id. /// Address resolution data from the cache. /// True if a relationship was created. - protected bool SetCrmRelationshipFromOutlook(Synchroniser sync, CrmId meetingId, AddressResolutionData resolution) + protected bool SetCrmRelationshipFromOutlook(Synchroniser sync, CrmId meetingId, + AddressResolutionData resolution) where T : class where S : SyncState { - return this.SetCrmRelationshipFromOutlook(sync, meetingId, resolution.ModuleName, resolution.ModuleId); + return SetCrmRelationshipFromOutlook(sync, meetingId, resolution.ModuleName, resolution.ModuleId); } /// - /// Sets up a CRM relationship to mimic an Outlook relationship + /// Sets up a CRM relationship to mimic an Outlook relationship /// /// the synchroniser to despatch to. /// The ID of the meeting /// the name of the module we're seeking to link with. /// The id in the foreign module of the record we're linking to. /// True if a relationship was created. - protected bool SetCrmRelationshipFromOutlook(Synchroniser sync, CrmId meetingId, string foreignModule, CrmId foreignId) + protected bool SetCrmRelationshipFromOutlook(Synchroniser sync, CrmId meetingId, + string foreignModule, CrmId foreignId) where T : class where S : SyncState { return CrmId.IsValid(foreignId) && - RestAPIWrapper.SetRelationshipUnsafe(new SetRelationshipParams - { - module2 = sync.DefaultCrmModule, - module2_id = meetingId.ToString(), - module1 = foreignModule, - module1_id = foreignId.ToString() - }); + RestAPIWrapper.SetRelationshipUnsafe(new SetRelationshipParams + { + module2 = sync.DefaultCrmModule, + module2_id = meetingId.ToString(), + module1 = foreignModule, + module1_id = foreignId.ToString() + }); } /// - /// Override: we get notified of a removal, for a Meeting item, when the meeting is - /// cancelled. We do NOT want to remove such an item; instead, we want to update it. + /// Override: we get notified of a removal, for a Meeting item, when the meeting is + /// cancelled. We do NOT want to remove such an item; instead, we want to update it. /// /// protected override void RemoveFromCrm(SyncState state) { if (state.CrmType == MeetingsSynchroniser.CrmModule) - { - this.AddOrUpdateItemFromOutlookToCrm((SyncState)state); - } + AddOrUpdateItemFromOutlookToCrm((SyncState) state); else - { base.RemoveFromCrm(state); - } } /// - /// Typically, when handling an item missing from outlook, the outlook item is missing and so can't - /// be relied on; treat this record as representing the current, known state of the item. + /// Typically, when handling an item missing from outlook, the outlook item is missing and so can't + /// be relied on; treat this record as representing the current, known state of the item. /// /// A record fetched from CRM representing the current state of the item. /// The sync state representing the item. /// The name/key of the CRM module in which the item exists. - private void HandleItemMissingFromOutlook(EntryValue record, SyncState syncState, string crmModule) + private void HandleItemMissingFromOutlook(EntryValue record, SyncState syncState, + string crmModule) { try { - if (record.GetValueAsDateTime("date_start") > DateTime.Now && crmModule == MeetingsSynchroniser.CrmModule) + if (record.GetValueAsDateTime("date_start") > DateTime.Now && + crmModule == MeetingsSynchroniser.CrmModule) { /* meeting in the future: mark it as canceled, do not delete it */ record.GetBinding("status").value = "NotHeld"; - string description = record.GetValue("description").ToString(); - if (!description.StartsWith(AppointmentsSynchroniser.CanceledPrefix)) + var description = record.GetValue("description").ToString(); + if (!description.StartsWith(CanceledPrefix)) { - record.GetBinding("description").value = $"{AppointmentsSynchroniser.CanceledPrefix}: {description}"; + record.GetBinding("description").value = $"{CanceledPrefix}: {description}"; RestAPIWrapper.SetEntry(record.nameValueList, crmModule); } } else { /* meeting in the past: just delete it */ - this.RemoveFromCrm(syncState); - this.RemoveItemSyncState(syncState); + RemoveFromCrm(syncState); + RemoveItemSyncState(syncState); } } catch (Exception any) { /* what could possibly go wrong? */ - ErrorHandler.Handle($"Failed while attempting to handle item missing from Outlook; CRM Id is {syncState.CrmEntryId}", any); + ErrorHandler.Handle( + $"Failed while attempting to handle item missing from Outlook; CRM Id is {syncState.CrmEntryId}", + any); } } - protected override bool IsMatch(Outlook.AppointmentItem olItem, EntryValue crmItem) + protected override bool IsMatch(AppointmentItem olItem, EntryValue crmItem) { return olItem.Subject == crmItem.GetValueAsString("name") && crmItem.GetValueAsDateTime("date_start") == olItem.Start; } /// - /// Remove the synchronisation properties from this Outlook item. + /// Remove the synchronisation properties from this Outlook item. /// /// The Outlook item. - private static void RemoveSynchronisationPropertiesFromOutlookItem(Outlook.AppointmentItem olItem) + private static void RemoveSynchronisationPropertiesFromOutlookItem(AppointmentItem olItem) { RemoveSynchronisationPropertyFromOutlookItem(olItem, SyncStateManager.CrmIdPropertyName); RemoveSynchronisationPropertyFromOutlookItem(olItem, SyncStateManager.TypePropertyName); @@ -823,57 +797,54 @@ private static void RemoveSynchronisationPropertiesFromOutlookItem(Outlook.Appoi } /// - /// Ensure that this Outlook item does not have a property of this name. + /// Ensure that this Outlook item does not have a property of this name. /// /// The Outlook item. /// The name. - private static void RemoveSynchronisationPropertyFromOutlookItem(Outlook.AppointmentItem olItem, string name) + private static void RemoveSynchronisationPropertyFromOutlookItem(AppointmentItem olItem, string name) { - int found = 0; + var found = 0; /* typical Microsoft, you can only remove a user property by its 1-based number */ - for (int i = 1; i <= olItem.UserProperties.Count; i++) - { + for (var i = 1; i <= olItem.UserProperties.Count; i++) if (olItem.UserProperties[i].Name == name) { found = i; break; } - } if (found > 0) - { try { olItem.UserProperties.Remove(found); } catch (Exception any) { - Globals.ThisAddIn.Log.Warn($"Unexpected error in RemoveSynchronisationPropertyFromOutlookItem", any); + Globals.ThisAddIn.Log.Warn($"Unexpected error in RemoveSynchronisationPropertyFromOutlookItem", + any); } finally { olItem.Save(); } - } } /// - /// Set the meeting status of this `olItem` from this `crmItem`. + /// Set the meeting status of this `olItem` from this `crmItem`. /// /// The Outlook item to update. /// The CRM item to use as source. - protected abstract void SetMeetingStatus(Outlook.AppointmentItem olItem, EntryValue crmItem); + protected abstract void SetMeetingStatus(AppointmentItem olItem, EntryValue crmItem); /// - /// We should delete an item from CRM if it already exists in CRM, but it is now private. + /// We should delete an item from CRM if it already exists in CRM, but it is now private. /// /// The Outlook item /// true if the Outlook item should be deleted from CRM. - private bool ShouldDeleteFromCrm(Outlook.AppointmentItem olItem) + private bool ShouldDeleteFromCrm(AppointmentItem olItem) { - bool result = (CrmId.IsValid(olItem.GetCrmId()) && olItem.Sensitivity != Outlook.OlSensitivity.olNormal); + var result = CrmId.IsValid(olItem.GetCrmId()) && olItem.Sensitivity != OlSensitivity.olNormal; LogItemAction(olItem, $"ShouldDeleteFromCrm returning {result}"); @@ -881,109 +852,106 @@ private bool ShouldDeleteFromCrm(Outlook.AppointmentItem olItem) } /// - /// True if we should despatch this item to CRM, else false. + /// True if we should despatch this item to CRM, else false. /// /// /// true iff settings.SyncCalendar is true, the item is not null, and it is not private (normal sensitivity) - private bool ShouldDespatchToCrm(Outlook.AppointmentItem olItem) + private bool ShouldDespatchToCrm(AppointmentItem olItem) { var syncConfigured = SyncDirection.AllowOutbound(Direction); - string organiser = olItem.Organizer; + var organiser = olItem.Organizer; var currentUser = Application.Session.CurrentUser; var exchangeUser = currentUser.AddressEntry.GetExchangeUser(); - var currentUserName = exchangeUser == null ? - Application.Session.CurrentUser.Name: - exchangeUser.Name; - - return syncConfigured && - olItem.Sensitivity == Outlook.OlSensitivity.olNormal && - /* If there is a valid crmId it's arrived via CRM and is therefore safe to save to CRM; - * if the current user is the organiser, AND there's no valid CRM id, then it's a new one - * that the current user made, and we should save it to CRM. */ - (CrmId.IsInvalid(olItem.GetCrmId()) || currentUserName == organiser) && - /* Microsoft Conferencing Add-in creates temporary items with names which start - * 'PLEASE IGNORE' - we should not sync these. */ - !olItem.Subject.StartsWith(MSConfTmpSubjectPrefix); + var currentUserName = exchangeUser == null ? Application.Session.CurrentUser.Name : exchangeUser.Name; + + return syncConfigured && + olItem.Sensitivity == OlSensitivity.olNormal && + /* If there is a valid crmId it's arrived via CRM and is therefore safe to save to CRM; + * if the current user is the organiser, AND there's no valid CRM id, then it's a new one + * that the current user made, and we should save it to CRM. */ + (CrmId.IsInvalid(olItem.GetCrmId()) || currentUserName == organiser) && + /* Microsoft Conferencing Add-in creates temporary items with names which start + * 'PLEASE IGNORE' - we should not sync these. */ + !olItem.Subject.StartsWith(MSConfTmpSubjectPrefix); } /// - /// Synchronise items in the specified folder with the specified SuiteCRM module. + /// Synchronise items in the specified folder with the specified SuiteCRM module. /// /// - /// TODO: candidate for refactoring upwards, in concert with ContactSyncing.SyncFolder. + /// TODO: candidate for refactoring upwards, in concert with ContactSyncing.SyncFolder. /// /// The folder. /// The module. - protected override void SyncFolder(Outlook.MAPIFolder folder, string crmModule) + protected override void SyncFolder(MAPIFolder folder, string crmModule) { - Log.Debug($"{this.GetType().Name}.SyncFolder: '{crmModule}'"); + Log.Debug($"{GetType().Name}.SyncFolder: '{crmModule}'"); try { /* this.ItemsSyncState already contains items to be synced. */ - var untouched = new HashSet>(SyncStateManager.Instance.GetSynchronisedItems()); - IList records = MergeRecordsFromCrm(folder, crmModule, untouched); + var untouched = + new HashSet>(SyncStateManager.Instance + .GetSynchronisedItems()); + var records = MergeRecordsFromCrm(folder, crmModule, untouched); AddOrUpdateItemsFromCrmToOutlook(records, folder, untouched, crmModule); - EntryValue[] invited = RestAPIWrapper.GetRelationships("Users", + var invited = RestAPIWrapper.GetRelationships("Users", RestAPIWrapper.GetUserId(), crmModule.ToLower(), RestAPIWrapper.GetSugarFields(crmModule)); if (invited != null) - { AddOrUpdateItemsFromCrmToOutlook(invited, folder, untouched, crmModule); - } try { - this.ResolveUnmatchedItems(untouched); + ResolveUnmatchedItems(untouched); } catch (Exception ex) { - ErrorHandler.Handle($"Failed while synchronising {this.DefaultCrmModule}", ex); + ErrorHandler.Handle($"Failed while synchronising {DefaultCrmModule}", ex); } } catch (Exception ex) { - ErrorHandler.Handle($"Failed while synchronising {this.DefaultCrmModule}", ex); + ErrorHandler.Handle($"Failed while synchronising {DefaultCrmModule}", ex); } } /// - /// Update an existing Outlook item with values taken from a corresponding CRM item. Note that - /// this just overwrites all values in the Outlook item. + /// Update an existing Outlook item with values taken from a corresponding CRM item. Note that + /// this just overwrites all values in the Outlook item. /// /// The CRM type of the item from which values are to be taken. /// The CRM item from which values are to be taken. /// The state date/time of the item, adjusted for timezone. /// The outlook item assumed to correspond with the CRM item. /// An appropriate sync state. - private SyncState UpdateExistingOutlookItemFromCrm( - string crmType, - EntryValue crmItem, - DateTime dateStart, - SyncState syncState) + private SyncState UpdateExistingOutlookItemFromCrm( + string crmType, + EntryValue crmItem, + DateTime dateStart, + SyncState syncState) { LogItemAction(syncState.OutlookItem, "AppointmentSyncing.UpdateExistingOutlookItemFromCrm"); if (!syncState.IsDeletedInOutlook) { - Outlook.AppointmentItem olItem = syncState.OutlookItem; - Outlook.UserProperty olPropertyModifiedDate = olItem.UserProperties[SyncStateManager.ModifiedDatePropertyName]; + var olItem = syncState.OutlookItem; + var olPropertyModifiedDate = olItem.UserProperties[SyncStateManager.ModifiedDatePropertyName]; - if (olPropertyModifiedDate == null || olPropertyModifiedDate.Value != crmItem.GetValueAsString("date_modified")) - { + if (olPropertyModifiedDate == null || olPropertyModifiedDate.Value != + crmItem.GetValueAsString("date_modified")) try { olItem.Subject = crmItem.GetValueAsString("name"); olItem.Body = crmItem.GetValueAsString("description"); if (!string.IsNullOrWhiteSpace(crmItem.GetValueAsString("date_start"))) - { UpdateOutlookDetails(crmType, crmItem, dateStart, olItem); - } EnsureSynchronisationPropertiesForOutlookItem(olItem, crmItem, crmType); - LogItemAction(syncState.OutlookItem, "AppointmentSyncing.UpdateExistingOutlookItemFromCrm, item saved"); + LogItemAction(syncState.OutlookItem, + "AppointmentSyncing.UpdateExistingOutlookItemFromCrm, item saved"); } catch (Exception any) { @@ -991,23 +959,24 @@ protected override void SyncFolder(Outlook.MAPIFolder folder, string crmModule) } finally { - this.SaveItem(olItem); + SaveItem(olItem); } - } - syncState.OModifiedDate = DateTime.ParseExact(crmItem.GetValueAsString("date_modified"), "yyyy-MM-dd HH:mm:ss", null); + syncState.OModifiedDate = + DateTime.ParseExact(crmItem.GetValueAsString("date_modified"), "yyyy-MM-dd HH:mm:ss", null); } return syncState; } /// - /// Update this Outlook appointment's start and duration from this CRM object. + /// Update this Outlook appointment's start and duration from this CRM object. /// /// The CRM type of the item from which values are to be taken. /// The CRM item from which values are to be taken. /// The state date/time of the item, adjusted for timezone. /// The outlook item assumed to correspond with the CRM item. - protected virtual void UpdateOutlookDetails(string crmType, EntryValue crmItem, DateTime date_start, Outlook.AppointmentItem olItem) + protected virtual void UpdateOutlookDetails(string crmType, EntryValue crmItem, DateTime date_start, + AppointmentItem olItem) { try { @@ -1015,161 +984,163 @@ protected virtual void UpdateOutlookDetails(string crmType, EntryValue crmItem, var minutesString = crmItem.GetValueAsString("duration_minutes"); var hoursString = crmItem.GetValueAsString("duration_hours"); - int minutes = string.IsNullOrWhiteSpace(minutesString) ? 0 : int.Parse(minutesString); - int hours = string.IsNullOrWhiteSpace(hoursString) ? 0 : int.Parse(hoursString); + var minutes = string.IsNullOrWhiteSpace(minutesString) ? 0 : int.Parse(minutesString); + var hours = string.IsNullOrWhiteSpace(hoursString) ? 0 : int.Parse(hoursString); olItem.Duration = minutes + hours * 60; } finally { - this.SaveItem(olItem); + SaveItem(olItem); } } - internal override string GetOutlookEntryId(Outlook.AppointmentItem olItem) + internal override string GetOutlookEntryId(AppointmentItem olItem) { return olItem.EntryID; } - protected override CrmId GetCrmEntryId(Outlook.AppointmentItem olItem) + protected override CrmId GetCrmEntryId(AppointmentItem olItem) { return olItem.GetCrmId(); } /// - /// Return the sensitivity of this outlook item. + /// Return the sensitivity of this outlook item. /// /// - /// Outlook item classes do not inherit from a common base class, so generic client code cannot refer to 'OutlookItem.Sensitivity'. + /// Outlook item classes do not inherit from a common base class, so generic client code cannot refer to + /// 'OutlookItem.Sensitivity'. /// /// The outlook item whose sensitivity is required. /// the sensitivity of the item. - internal override Outlook.OlSensitivity GetSensitivity(Outlook.AppointmentItem item) + internal override OlSensitivity GetSensitivity(AppointmentItem item) { return item.Sensitivity; } /// - /// Add an address resolution composed from this module name and record to the cache. + /// Add an address resolution composed from this module name and record to the cache. /// /// The name of the module in which the record was found /// The record. protected void CacheAddressResolutionData(string moduleName, LinkRecord record) { CacheAddressResolutionData( - new AddressResolutionData(moduleName, + new AddressResolutionData(moduleName, record.data.AsDictionary())); } /// - /// Add this resolution to the cache. + /// Add this resolution to the cache. /// /// The resolution to add. protected void CacheAddressResolutionData(AddressResolutionData resolution) { List resolutions; - if (this.meetingRecipientsCache.ContainsKey(resolution.EmailAddress)) + if (meetingRecipientsCache.ContainsKey(resolution.EmailAddress)) { - resolutions = this.meetingRecipientsCache[resolution.EmailAddress]; + resolutions = meetingRecipientsCache[resolution.EmailAddress]; } else { resolutions = new List(); - this.meetingRecipientsCache[resolution.EmailAddress] = resolutions; + meetingRecipientsCache[resolution.EmailAddress] = resolutions; } if (!resolutions.Any(x => x.ModuleId == resolution.ModuleId && x.ModuleName == resolution.ModuleName)) - { resolutions.Add(resolution); - } - Log.Debug($"Successfully cached recipient {resolution.EmailAddress} => {resolution.ModuleName}, {resolution.ModuleId}."); + Log.Debug( + $"Successfully cached recipient {resolution.EmailAddress} => {resolution.ModuleName}, {resolution.ModuleId}."); } protected void CacheAddressResolutionData(EntryValue crmItem) { foreach (var list in crmItem.relationships.link_list) + foreach (var record in list.records) { - foreach (var record in list.records) + var data = record.data.AsDictionary(); + try { - var data = record.data.AsDictionary(); - try - { - this.CacheAddressResolutionData(list.name, record); - } - catch (TypeInitializationException tix) - { - ErrorHandler.Handle("Probable invalid CRM ID", tix); - } - catch (KeyNotFoundException kex) - { - ErrorHandler.Handle($"Email address '{record.data.GetValueAsString(AddressResolutionData.EmailAddressFieldName)}' not recognised while caching meeting recipients.", kex); - } + CacheAddressResolutionData(list.name, record); + } + catch (TypeInitializationException tix) + { + ErrorHandler.Handle("Probable invalid CRM ID", tix); + } + catch (KeyNotFoundException kex) + { + ErrorHandler.Handle( + $"Email address '{record.data.GetValueAsString(AddressResolutionData.EmailAddressFieldName)}' not recognised while caching meeting recipients.", + kex); } } } /// - /// Used for caching data for resolving email addresses to CRM records. + /// Used for caching data for resolving email addresses to CRM records. /// protected class AddressResolutionData { /// - /// Expected name in the input map of the email address field. + /// Expected name in the input map of the email address field. /// public const string EmailAddressFieldName = "email1"; /// - /// Expected name in the input map of the field containing the id in - /// the specified module. + /// Expected name in the input map of the field containing the id in + /// the specified module. /// public const string ModuleIdFieldName = "id"; /// - /// Expected name in the input map of the field containing an associated id in - /// the `Accounts` module, if any. + /// Expected name in the input map of the field containing an associated id in + /// the `Accounts` module, if any. /// public const string AccountIdFieldName = "account_id"; /// - /// The email address resolved by this data. + /// The id within the `Accounts` module of a related record, if any. /// - public readonly string EmailAddress; + private readonly object accountId; + /// - /// The name of the CRM module to which it resolves. + /// The email address resolved by this data. /// - public readonly string ModuleName; + public readonly string EmailAddress; + /// - /// The id within that module of the record to which it resolves. + /// The id within that module of the record to which it resolves. /// public readonly CrmId ModuleId; /// - /// The id within the `Accounts` module of a related record, if any. + /// The name of the CRM module to which it resolves. /// - private readonly object accountId; + public readonly string ModuleName; public AddressResolutionData(string moduleName, CrmId moduleId, string emailAddress) { - this.ModuleName = moduleName; - this.ModuleId = moduleId; - this.EmailAddress = emailAddress; + ModuleName = moduleName; + ModuleId = moduleId; + EmailAddress = emailAddress; } public AddressResolutionData(string moduleName, Dictionary data) { - this.ModuleName = moduleName; - this.ModuleId = CrmId.Get(data[ModuleIdFieldName]); - this.EmailAddress = data[EmailAddressFieldName]?.ToString(); + ModuleName = moduleName; + ModuleId = CrmId.Get(data[ModuleIdFieldName]); + EmailAddress = data[EmailAddressFieldName]?.ToString(); try { - this.accountId = data[AccountIdFieldName]?.ToString(); + accountId = data[AccountIdFieldName]?.ToString(); } catch (KeyNotFoundException) { @@ -1178,4 +1149,4 @@ public AddressResolutionData(string moduleName, Dictionary data) } } } -} +} \ No newline at end of file diff --git a/SuiteCRMAddIn/BusinessLogic/ContactSynchroniser.cs b/SuiteCRMAddIn/BusinessLogic/ContactSynchroniser.cs index d5219c5e..331f897a 100644 --- a/SuiteCRMAddIn/BusinessLogic/ContactSynchroniser.cs +++ b/SuiteCRMAddIn/BusinessLogic/ContactSynchroniser.cs @@ -241,12 +241,12 @@ internal override void LogItemAction(Outlook.ContactItem olItem, string message) { try { - CrmId crmId = olItem.GetCrmId(); + CrmId crmId = this.IsEnabled() ? olItem.GetCrmId() : CrmId.Empty; if (CrmId.IsInvalid(crmId)) { crmId = CrmId.Empty; } StringBuilder bob = new StringBuilder(); bob.Append($"{message}:\n\tOutlook Id : {olItem.EntryID}") - .Append($"\n\tCRM Id : {crmId}") + .Append(this.IsEnabled() ? $"\n\tCRM Id : {crmId}" : string.Empty) .Append($"\n\tFull name : '{olItem.FullName}'") .Append($"\n\tSensitivity : {olItem.Sensitivity}") .Append($"\n\tTxState : {SyncStateManager.Instance.GetExistingSyncState(olItem)?.TxState}"); diff --git a/SuiteCRMAddIn/BusinessLogic/TaskSynchroniser.cs b/SuiteCRMAddIn/BusinessLogic/TaskSynchroniser.cs index 672cade9..9c0e448a 100644 --- a/SuiteCRMAddIn/BusinessLogic/TaskSynchroniser.cs +++ b/SuiteCRMAddIn/BusinessLogic/TaskSynchroniser.cs @@ -146,12 +146,12 @@ internal override void LogItemAction(Outlook.TaskItem olItem, string message) { try { - CrmId crmId = olItem.GetCrmId(); + CrmId crmId = this.IsEnabled() ? olItem.GetCrmId() : CrmId.Empty; if (CrmId.IsInvalid(crmId)) { crmId = CrmId.Empty; } StringBuilder bob = new StringBuilder(); bob.Append($"{message}:\n\tOutlook Id : {olItem.EntryID}") - .Append($"\n\tCRM Id : {crmId}") + .Append(this.IsEnabled() ? $"\n\tCRM Id : {crmId}" : string.Empty) .Append($"\n\tSubject : '{olItem.Subject}'") .Append($"\n\tStatus : {olItem.Status}") .Append($"\n\tSensitivity : {olItem.Sensitivity}") diff --git a/SuiteCRMAddIn/Dialogs/ClearCrmIdsDialog.cs b/SuiteCRMAddIn/Dialogs/ClearCrmIdsDialog.cs index 851164d1..5ef1e40b 100644 --- a/SuiteCRMAddIn/Dialogs/ClearCrmIdsDialog.cs +++ b/SuiteCRMAddIn/Dialogs/ClearCrmIdsDialog.cs @@ -20,7 +20,7 @@ public partial class ClearCrmIdsDialog : Form /// static BackgroundWorker fred = new BackgroundWorker(); - private IEnumerable items = Globals.ThisAddIn.GetSynchronisableItems(); + private readonly IEnumerable items = Globals.ThisAddIn.GetSynchronisableItems(); /// /// The total number of items which may have to be cleared. diff --git a/SuiteCRMAddIn/Properties/AssemblyInfo.cs b/SuiteCRMAddIn/Properties/AssemblyInfo.cs index 6a9f73be..2251bee9 100644 --- a/SuiteCRMAddIn/Properties/AssemblyInfo.cs +++ b/SuiteCRMAddIn/Properties/AssemblyInfo.cs @@ -33,6 +33,6 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.16.24")] +[assembly: AssemblyVersion("3.0.16.26")] [assembly: AssemblyFileVersion("3.0.1")] diff --git a/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl b/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl index e95858d2..ac9d1f70 100644 --- a/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl +++ b/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl @@ -4423,7 +4423,7 @@ RABlAGIAdQBnAAEARQB4AHAAcgBlAHMAcwA= PROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS##IDS_PROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS## ProductCode{3BFCFDAB-2396-46E0-A826-0F142CA288EB} ProductNameSuiteCRMAddIn - ProductVersion3.0.16.24 + ProductVersion3.0.16.26 ProgressType0install ProgressType1Installing ProgressType2installed diff --git a/SuiteCRMClient/Properties/AssemblyInfo.cs b/SuiteCRMClient/Properties/AssemblyInfo.cs index 19c94168..a275d85f 100644 --- a/SuiteCRMClient/Properties/AssemblyInfo.cs +++ b/SuiteCRMClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.16.24")] +[assembly: AssemblyVersion("3.0.16.26")] [assembly: AssemblyFileVersion("1.0.0.0")] From 5429c4ad8d5286877a80d53acdcb9ad165d8d292 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Mon, 10 Dec 2018 13:05:42 +0000 Subject: [PATCH 07/13] #4635 Build 3.0.16.38, using .Net 4.6.1 --- Doxyfile | 2 +- README.md | 2 +- .../Dialogs/SettingsDialog.Designer.cs | 15 +++- SuiteCRMAddIn/Dialogs/SettingsDialog.cs | 73 +++++++++++++++++++ SuiteCRMAddIn/Properties/AssemblyInfo.cs | 2 +- SuiteCRMAddIn/Properties/Settings.Designer.cs | 2 +- SuiteCRMAddIn/SuiteCRMAddIn.csproj | 13 ++-- SuiteCRMAddIn/ThisAddIn.Designer.cs | 59 +++++---------- SuiteCRMAddIn/ThisAddIn.Designer.xml | 2 +- SuiteCRMAddIn/app.config | 22 +++--- SuiteCRMAddIn/packages.config | 8 +- SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl | 2 +- SuiteCRMAddInTests/SuiteCRMAddInTests.csproj | 3 +- SuiteCRMAddInTests/app.config | 10 +-- SuiteCRMAddInTests/packages.config | 2 +- SuiteCRMClient/Properties/AssemblyInfo.cs | 2 +- .../Properties/Settings.Designer.cs | 4 +- SuiteCRMClient/SuiteCRMClient.csproj | 9 ++- SuiteCRMClient/app.config | 18 ++--- SuiteCRMClient/packages.config | 4 +- 20 files changed, 159 insertions(+), 95 deletions(-) diff --git a/Doxyfile b/Doxyfile index c9a29e01..7d006555 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "SuiteCRM Outlook Add-in" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 3.0.16.26 +PROJECT_NUMBER = 3.0.16.38 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/README.md b/README.md index d080612f..614b9eb1 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ### What's in this repository -SuiteCRM Outlook Plug-In v 3.0.16.26 +SuiteCRM Outlook Plug-In v 3.0.16.38 This repository has been created to allow community members to collaborate and contribute to the project. diff --git a/SuiteCRMAddIn/Dialogs/SettingsDialog.Designer.cs b/SuiteCRMAddIn/Dialogs/SettingsDialog.Designer.cs index d524ca10..05771143 100644 --- a/SuiteCRMAddIn/Dialogs/SettingsDialog.Designer.cs +++ b/SuiteCRMAddIn/Dialogs/SettingsDialog.Designer.cs @@ -117,6 +117,7 @@ private void InitializeComponent() this.AddInTitleLabel = new System.Windows.Forms.Label(); this.btnCancel = new System.Windows.Forms.Button(); this.btnSave = new System.Windows.Forms.Button(); + this.dotNetVersionLabel = new System.Windows.Forms.Label(); this.tabPage3.SuspendLayout(); this.EmailArchiveAccountTabs.SuspendLayout(); this.tabPage2.SuspendLayout(); @@ -614,6 +615,7 @@ private void InitializeComponent() // // InformationTabPage // + this.InformationTabPage.Controls.Add(this.dotNetVersionLabel); this.InformationTabPage.Controls.Add(this.AddInVersionLabel); this.InformationTabPage.Controls.Add(this.groupBox4); this.InformationTabPage.Controls.Add(this.AddInTitleLabel); @@ -629,7 +631,7 @@ private void InitializeComponent() this.AddInVersionLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.AddInVersionLabel.Location = new System.Drawing.Point(13, 61); this.AddInVersionLabel.Name = "AddInVersionLabel"; - this.AddInVersionLabel.Size = new System.Drawing.Size(332, 25); + this.AddInVersionLabel.Size = new System.Drawing.Size(332, 16); this.AddInVersionLabel.TabIndex = 6; this.AddInVersionLabel.Text = "Version 0.0.0.0"; this.AddInVersionLabel.TextAlign = System.Drawing.ContentAlignment.TopCenter; @@ -777,6 +779,16 @@ private void InitializeComponent() this.btnSave.UseVisualStyleBackColor = true; this.btnSave.Click += new System.EventHandler(this.btnSave_Click); // + // dotNetVersionLabel + // + this.dotNetVersionLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.dotNetVersionLabel.Location = new System.Drawing.Point(13, 77); + this.dotNetVersionLabel.Name = "dotNetVersionLabel"; + this.dotNetVersionLabel.Size = new System.Drawing.Size(332, 16); + this.dotNetVersionLabel.TabIndex = 7; + this.dotNetVersionLabel.Text = ".Net version 0.0.0"; + this.dotNetVersionLabel.TextAlign = System.Drawing.ContentAlignment.TopCenter; + // // SettingsDialog // this.AcceptButton = this.btnSave; @@ -894,5 +906,6 @@ private void InitializeComponent() private System.Windows.Forms.ComboBox crmIdValidationSelector; private System.Windows.Forms.Label crmIdValidationLabel; private System.Windows.Forms.BindingSource policyBindingSource; + private System.Windows.Forms.Label dotNetVersionLabel; } } diff --git a/SuiteCRMAddIn/Dialogs/SettingsDialog.cs b/SuiteCRMAddIn/Dialogs/SettingsDialog.cs index 7e84ae2b..09f8aceb 100644 --- a/SuiteCRMAddIn/Dialogs/SettingsDialog.cs +++ b/SuiteCRMAddIn/Dialogs/SettingsDialog.cs @@ -24,6 +24,7 @@ namespace SuiteCRMAddIn.Dialogs { using BusinessLogic; using Microsoft.Office.Interop.Outlook; + using Microsoft.Win32; using SuiteCRMClient; using SuiteCRMClient.Logging; using System; @@ -95,6 +96,7 @@ private void frmSettings_Load(object sender, EventArgs e) { AddInTitleLabel.Text = ThisAddIn.AddInTitle; AddInVersionLabel.Text = "Version " + ThisAddIn.AddInVersion; + dotNetVersionLabel.Text = ".Net version " + CheckFor45DotVersion(Get45or451FromRegistry()); if (Globals.ThisAddIn.SuiteCRMUserSession == null) { @@ -115,6 +117,77 @@ private void frmSettings_Load(object sender, EventArgs e) } } + private static int Get45or451FromRegistry() + { + int result; + try + { + using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32) + .OpenSubKey("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\\")) + { + result = Convert.ToInt32(ndpKey.GetValue("Release")); + } + } + catch (Exception) + { + result = 0; + } + + return result; + } + + + +// Checking the version using >= will enable forward compatibility, +// however you should always compile your code on newer versions of +// the framework to ensure your app works the same. + private static string CheckFor45DotVersion(int releaseKey) + { + if (releaseKey >= 461808) + { + return "4.7.2"; + } + if (releaseKey >= 461308) + { + return "4.7.1"; + } + if (releaseKey >= 460798) + { + return "4.7"; + } + if (releaseKey >= 394802) + { + return "4.6.2"; + } + if (releaseKey >= 394254) + { + return "4.6.1"; + } + if (releaseKey >= 393295) + { + return "4.6"; + } + if (releaseKey >= 393273) + { + return "4.6 RC"; + } + if ((releaseKey >= 379893)) + { + return "4.5.2"; + } + if ((releaseKey >= 378675)) + { + return "4.5.1"; + } + if ((releaseKey >= 378389)) + { + return "4.5"; + } + // This line should never execute. A non-null release key should mean + // that 4.5 is installed. + return "No 4.5 version detected"; + } + private void LoadSettings() { if (Properties.Settings.Default.Host != string.Empty) diff --git a/SuiteCRMAddIn/Properties/AssemblyInfo.cs b/SuiteCRMAddIn/Properties/AssemblyInfo.cs index 2251bee9..0c0f1a4a 100644 --- a/SuiteCRMAddIn/Properties/AssemblyInfo.cs +++ b/SuiteCRMAddIn/Properties/AssemblyInfo.cs @@ -33,6 +33,6 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.16.26")] +[assembly: AssemblyVersion("3.0.16.38")] [assembly: AssemblyFileVersion("3.0.1")] diff --git a/SuiteCRMAddIn/Properties/Settings.Designer.cs b/SuiteCRMAddIn/Properties/Settings.Designer.cs index 9ddd9ee6..ea13180c 100644 --- a/SuiteCRMAddIn/Properties/Settings.Designer.cs +++ b/SuiteCRMAddIn/Properties/Settings.Designer.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 diff --git a/SuiteCRMAddIn/SuiteCRMAddIn.csproj b/SuiteCRMAddIn/SuiteCRMAddIn.csproj index de1cffc7..d4865790 100644 --- a/SuiteCRMAddIn/SuiteCRMAddIn.csproj +++ b/SuiteCRMAddIn/SuiteCRMAddIn.csproj @@ -1,6 +1,6 @@  - - + + - - - - - - - - - - - - - - ="10.0.30319" OR VSTORUNTIMEREDIST_R>="10.0.30319"]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + ="10.0.30319" OR VSTORUNTIMEREDIST_R>="10.0.30319"]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SuiteCRMAddInWixSetup/SuiteCRMAddInWixSetup.wixproj b/SuiteCRMAddInWixSetup/SuiteCRMAddInWixSetup.wixproj index aa390894..226f3b08 100644 --- a/SuiteCRMAddInWixSetup/SuiteCRMAddInWixSetup.wixproj +++ b/SuiteCRMAddInWixSetup/SuiteCRMAddInWixSetup.wixproj @@ -1,61 +1,61 @@ - - - - Debug - x86 - 3.10 - 03906f90-2afd-411d-b1d5-be9a934baf74 - 2.0 - SuiteCRMAddInSetup - Package - - - bin\$(Configuration)\ - obj\$(Configuration)\ - Debug;AddinFiles=..\SuiteCRMAddIn\bin\$(Configuration)\ - - - bin\$(Configuration)\ - obj\$(Configuration)\ - AddinFiles=..\SuiteCRMAddIn\bin\$(Configuration)\ - - - - - - - $(WixExtDir)\WixUtilExtension.dll - WixUtilExtension - - - $(WixExtDir)\WixUIExtension.dll - WixUIExtension - - - $(WixExtDir)\WixNetFxExtension.dll - WixNetFxExtension - - - - - - - - - - - - - - - - - - + + + + Debug + x86 + 3.10 + 03906f90-2afd-411d-b1d5-be9a934baf74 + 2.0 + SuiteCRMAddIn + Package + + + bin\$(Configuration)\ + obj\$(Configuration)\ + Debug;AddinFiles=..\SuiteCRMAddIn\bin\$(Configuration)\;ClientFiles=..\SuiteCRMClient\bin\$(Configuration)\ + + + bin\$(Configuration)\ + obj\$(Configuration)\ + AddinFiles=..\SuiteCRMAddIn\bin\$(Configuration)\;ClientFiles=..\SuiteCRMClient\bin\$(Configuration)\ + + + + + + + $(WixExtDir)\WixUtilExtension.dll + WixUtilExtension + + + $(WixExtDir)\WixUIExtension.dll + WixUIExtension + + + $(WixExtDir)\WixNetFxExtension.dll + WixNetFxExtension + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SuiteCRMClient/Properties/AssemblyInfo.cs b/SuiteCRMClient/Properties/AssemblyInfo.cs index 53424cae..b7436489 100644 --- a/SuiteCRMClient/Properties/AssemblyInfo.cs +++ b/SuiteCRMClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.16.39")] +[assembly: AssemblyVersion("3.0.16.45")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SuiteCRMOutlookAddIn.sln b/SuiteCRMOutlookAddIn.sln index bc36c925..fdcb8ffb 100644 --- a/SuiteCRMOutlookAddIn.sln +++ b/SuiteCRMOutlookAddIn.sln @@ -160,6 +160,34 @@ Global {245DBFF1-8518-4EC9-9AB4-E00392396485}.SingleImage|Mixed Platforms.Build.0 = Release|Any CPU {245DBFF1-8518-4EC9-9AB4-E00392396485}.SingleImage|x86.ActiveCfg = Release|Any CPU {245DBFF1-8518-4EC9-9AB4-E00392396485}.SingleImage|x86.Build.0 = Release|Any CPU + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.CD_ROM|Any CPU.ActiveCfg = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.CD_ROM|Any CPU.Build.0 = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.CD_ROM|Mixed Platforms.ActiveCfg = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.CD_ROM|Mixed Platforms.Build.0 = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.CD_ROM|x86.ActiveCfg = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.CD_ROM|x86.Build.0 = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.Debug|Any CPU.ActiveCfg = Debug|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.Debug|x86.ActiveCfg = Debug|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.Debug|x86.Build.0 = Debug|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.DVD-5|Any CPU.ActiveCfg = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.DVD-5|Any CPU.Build.0 = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.DVD-5|Mixed Platforms.ActiveCfg = Debug|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.DVD-5|Mixed Platforms.Build.0 = Debug|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.DVD-5|x86.ActiveCfg = Debug|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.DVD-5|x86.Build.0 = Debug|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.Release|Any CPU.ActiveCfg = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.Release|Mixed Platforms.Build.0 = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.Release|x86.ActiveCfg = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.Release|x86.Build.0 = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.SingleImage|Any CPU.ActiveCfg = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.SingleImage|Any CPU.Build.0 = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.SingleImage|Mixed Platforms.ActiveCfg = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.SingleImage|Mixed Platforms.Build.0 = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.SingleImage|x86.ActiveCfg = Release|x86 + {03906F90-2AFD-411D-B1D5-BE9A934BAF74}.SingleImage|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From b2f01392d861b728175ef4ebd7c863cc6f6933bb Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Fri, 21 Dec 2018 11:05:09 +0000 Subject: [PATCH 12/13] Build 3.0.16.47 Fixes merge conflicts --- Doxyfile | 2 +- README.md | 2 +- SuiteCRMAddIn/Properties/AssemblyInfo.cs | 2 +- SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl | 2 +- SuiteCRMAddInWixSetup/Product.wxs | 2 +- SuiteCRMClient/Properties/AssemblyInfo.cs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doxyfile b/Doxyfile index 1bd7934f..9e9596ff 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "SuiteCRM Outlook Add-in" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 3.0.16.45 +PROJECT_NUMBER = 3.0.16.47 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/README.md b/README.md index a4d43f08..b3ecb1ea 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ### What's in this repository -SuiteCRM Outlook Plug-In v 3.0.16.45 +SuiteCRM Outlook Plug-In v 3.0.16.47 This repository has been created to allow community members to collaborate and contribute to the project. diff --git a/SuiteCRMAddIn/Properties/AssemblyInfo.cs b/SuiteCRMAddIn/Properties/AssemblyInfo.cs index 25130358..662e9770 100644 --- a/SuiteCRMAddIn/Properties/AssemblyInfo.cs +++ b/SuiteCRMAddIn/Properties/AssemblyInfo.cs @@ -33,6 +33,6 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.16.45")] +[assembly: AssemblyVersion("3.0.16.47")] [assembly: AssemblyFileVersion("3.0.1")] diff --git a/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl b/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl index 2139d94f..31e33bf4 100644 --- a/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl +++ b/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl @@ -4423,7 +4423,7 @@ RABlAGIAdQBnAAEARQB4AHAAcgBlAHMAcwA= PROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS##IDS_PROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS## ProductCode{3BFCFDAB-2396-46E0-A826-0F142CA288EB} ProductNameSuiteCRMAddIn - ProductVersion3.0.16.45 + ProductVersion3.0.16.47 ProgressType0install ProgressType1Installing ProgressType2installed diff --git a/SuiteCRMAddInWixSetup/Product.wxs b/SuiteCRMAddInWixSetup/Product.wxs index 74be210e..fbf300dd 100644 --- a/SuiteCRMAddInWixSetup/Product.wxs +++ b/SuiteCRMAddInWixSetup/Product.wxs @@ -4,7 +4,7 @@ Id="A784C437-58CF-4495-BE4A-F77657600001" Name="SuiteCRMAddIn" Language="1033" - Version="3.0.16.45" + Version="3.0.16.47" Manufacturer="SalesAgility" UpgradeCode="F50E9CEB-D641-4FC6-8E16-483505C3455A"> diff --git a/SuiteCRMClient/Properties/AssemblyInfo.cs b/SuiteCRMClient/Properties/AssemblyInfo.cs index b7436489..12ff4861 100644 --- a/SuiteCRMClient/Properties/AssemblyInfo.cs +++ b/SuiteCRMClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.16.45")] +[assembly: AssemblyVersion("3.0.16.47")] [assembly: AssemblyFileVersion("1.0.0.0")] From 1a4afc0d78f097adcbd6c4a3193e3f95a10336b9 Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Fri, 21 Dec 2018 12:00:03 +0000 Subject: [PATCH 13/13] Build 3.0.16.57: fixed issues raised in code review --- Doxyfile | 4 ++-- README.md | 2 +- SuiteCRMAddIn/Dialogs/SettingsDialog.cs | 18 +++++++++--------- SuiteCRMAddIn/Properties/AssemblyInfo.cs | 2 +- SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl | 2 +- SuiteCRMAddInWixSetup/Product.wxs | 2 +- SuiteCRMClient/Properties/AssemblyInfo.cs | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Doxyfile b/Doxyfile index 9e9596ff..634366a0 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "SuiteCRM Outlook Add-in" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 3.0.16.47 +PROJECT_NUMBER = 3.0.16.51 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -51,7 +51,7 @@ PROJECT_BRIEF = "An outlook add-in which allows synchronisation with Su # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = C:/Users/Simon/Workspace/SuiteCRM-Outlook-Plugin/SuiteCRMAddIn/Images/SuiteCRM.png +PROJECT_LOGO = Images/SuiteCRM.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is diff --git a/README.md b/README.md index b3ecb1ea..e912e750 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ### What's in this repository -SuiteCRM Outlook Plug-In v 3.0.16.47 +SuiteCRM Outlook Plug-In v 3.0.16.51 This repository has been created to allow community members to collaborate and contribute to the project. diff --git a/SuiteCRMAddIn/Dialogs/SettingsDialog.cs b/SuiteCRMAddIn/Dialogs/SettingsDialog.cs index 09f8aceb..3082e49a 100644 --- a/SuiteCRMAddIn/Dialogs/SettingsDialog.cs +++ b/SuiteCRMAddIn/Dialogs/SettingsDialog.cs @@ -75,15 +75,15 @@ private bool ValidateDetails() return false; } - //if (chkEnableLDAPAuthentication.Checked) - //{ - // if (SafelyGetText(txtLDAPAuthenticationKey) == string.Empty) - // { - // MessageBox.Show("Please enter a valid LDAP authentication key"); - // txtLDAPAuthenticationKey.Focus(); - // return false; - // } - //} + if (chkEnableLDAPAuthentication.Checked) + { + if (SafelyGetText(txtLDAPAuthenticationKey) == string.Empty) + { + MessageBox.Show("Please enter a valid LDAP authentication key"); + txtLDAPAuthenticationKey.Focus(); + return false; + } + } return true; } diff --git a/SuiteCRMAddIn/Properties/AssemblyInfo.cs b/SuiteCRMAddIn/Properties/AssemblyInfo.cs index 662e9770..73d96494 100644 --- a/SuiteCRMAddIn/Properties/AssemblyInfo.cs +++ b/SuiteCRMAddIn/Properties/AssemblyInfo.cs @@ -33,6 +33,6 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.16.47")] +[assembly: AssemblyVersion("3.0.16.51")] [assembly: AssemblyFileVersion("3.0.1")] diff --git a/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl b/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl index 31e33bf4..14434a06 100644 --- a/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl +++ b/SuiteCRMAddInSetup/SuiteCRMAddInSetup.isl @@ -4423,7 +4423,7 @@ RABlAGIAdQBnAAEARQB4AHAAcgBlAHMAcwA= PROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS##IDS_PROGMSG_IIS_ROLLBACKWEBSERVICEEXTENSIONS## ProductCode{3BFCFDAB-2396-46E0-A826-0F142CA288EB} ProductNameSuiteCRMAddIn - ProductVersion3.0.16.47 + ProductVersion3.0.16.51 ProgressType0install ProgressType1Installing ProgressType2installed diff --git a/SuiteCRMAddInWixSetup/Product.wxs b/SuiteCRMAddInWixSetup/Product.wxs index fbf300dd..53ac0e6e 100644 --- a/SuiteCRMAddInWixSetup/Product.wxs +++ b/SuiteCRMAddInWixSetup/Product.wxs @@ -4,7 +4,7 @@ Id="A784C437-58CF-4495-BE4A-F77657600001" Name="SuiteCRMAddIn" Language="1033" - Version="3.0.16.47" + Version="3.0.16.51" Manufacturer="SalesAgility" UpgradeCode="F50E9CEB-D641-4FC6-8E16-483505C3455A"> diff --git a/SuiteCRMClient/Properties/AssemblyInfo.cs b/SuiteCRMClient/Properties/AssemblyInfo.cs index 12ff4861..5277ca48 100644 --- a/SuiteCRMClient/Properties/AssemblyInfo.cs +++ b/SuiteCRMClient/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.16.47")] +[assembly: AssemblyVersion("3.0.16.51")] [assembly: AssemblyFileVersion("1.0.0.0")]