/* Copyright 2005 Roger Martin, Tech Info Systems
Gallery Server Pro is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Gallery Server Pro is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using GalleryServerPro.Business.Interfaces;
using GalleryServerPro.Business.Properties;
using GalleryServerPro.ErrorHandler.CustomExceptions;
namespace GalleryServerPro.Business
{
/// <summary>
/// Provides general helper functions.
/// </summary>
public static class HelperFunctions
{
#region Private Fields
private static readonly string ENCRYPTION_KEY = GalleryServerPro.Configuration.ConfigManager.GetGalleryServerProConfigSection().Core.EncryptionKey; // Used in Encrypt/Decrypt methods
private static Microsoft.Practices.EnterpriseLibrary.Caching.CacheManager _cacheManager;
private static object _fileLock = new object(); // Used in ValidatePhysicalPathExistsAndIsReadWritable()
#endregion
#region Constructors
#endregion
#region Public Static Methods
/// <summary>
/// Returns true if the object is a valid System.Int32 value; otherwise returns false.
/// </summary>
/// <param name="value">The parameter to test whether it is a System.Int32.</param>
/// <returns>Returns true if the object is a valid System.Int32 value; otherwise returns false.</returns>
public static bool IsInt32(object value)
{
if (value == null)
return false;
int result;
return Int32.TryParse(value.ToString(), out result);
}
/// <summary>
/// Returns true if the object is a valid System.Boolean value; otherwise returns false.
/// </summary>
/// <param name="value">The parameter to test whether it is a System.Boolean value.</param>
/// <returns>Returns true if the object is a valid System.Boolean value; otherwise returns false.
/// </returns>
public static bool IsBoolean(object value)
{
//Returns true if value of object is bool; otherwise false
if (value == null)
return false;
try
{
System.Convert.ToBoolean(value.ToString(), CultureInfo.InvariantCulture);
return true;
}
catch (FormatException) { return false; }
}
/// <summary>
/// Returns true if the object is a valid System.Double value; otherwise returns false.
/// </summary>
/// <param name="value">The parameter to test whether it is a System.Double.</param>
/// <returns>Returns true if the object is a valid System.Double value; otherwise returns false.</returns>
public static bool IsDouble(object value)
{
//Returns true if the value of object is a double; otherwise false.
//NOT CURRENTLY USED. ONLY HERE BECAUSE IT *MIGHT* BE USEFUL
if (value == null)
return false;
try
{
System.Double.Parse(value.ToString(), System.Globalization.NumberStyles.Any, CultureInfo.CurrentCulture);
return true;
}
catch (FormatException) { return false; }
catch (OverflowException) { return false; }
}
/// <summary>
/// Returns true if the object is a valid System.DateTime object; otherwise returns false.
/// </summary>
/// <param name="value">The parameter to test whether it is a System.DateTime object.</param>
/// <returns>Returns true if the object is a valid System.DateTime object; otherwise returns false.</returns>
public static bool IsDateTime(object value)
{
// Returns true if the value of the object is a DateTime value; otherwise false
if (value == null)
return false;
try
{
System.DateTime.Parse(value.ToString(), CultureInfo.CurrentCulture);
return true;
}
catch (FormatException)
{
return false;
}
}
/// <summary>
/// Format the testValue parameter to so it data store-compatible. Specifically,
/// int.MinValue is replaced with 0. Use this method when updating or inserting
/// records in the database.
/// </summary>
/// <param name="testValue">The int to send to the database. int.MinValue is
/// replaced with 0.</param>
/// <returns>Returns the parameter value formatted as a value that can be persisted
/// to the data store.</returns>
public static int ToDBValue(int testValue)
{
return (testValue == int.MinValue ? 0 : testValue);
}
/// <summary>
/// Convert the specified object to System.DateTime. Use this object when retrieving
/// values from a database. If the object is of type System.TypeCode.DBNull,
/// DateTime.MinValue is returned.
/// </summary>
/// <param name="value">The object to convert to System.DateTime. An exception is thrown
/// if the object cannot be converted.</param>
/// <returns>Returns a System.DateTime value.</returns>
public static DateTime ToDateTime(object value)
{
return Convert.IsDBNull(value) ? DateTime.MinValue : Convert.ToDateTime(value, System.Globalization.NumberFormatInfo.CurrentInfo);
}
/// <summary>
/// Determines whether the specified string is a valid email address. This is determined by comparing the string
/// to a regular expression. The method does not determine that the email address actually exists.
/// </summary>
/// <param name="email">The string to validate as an email address.</param>
/// <returns>Returns true when the email parameter conforms to the expected format of an email address; otherwise
/// returns false.</returns>
public static bool IsValidEmail(string email)
{
if (String.IsNullOrEmpty(email))
return false;
else
{
string pattern = @"^[A-Za-z0-9_\-\.]+@(([A-Za-z0-9\-])+\.)+([A-Za-z\-])+$";
return System.Text.RegularExpressions.Regex.IsMatch(email, pattern);
}
}
/// <summary>
/// Ensure the specified string is a valid name for a directory within the specified path. Invalid
/// characters are removed and the existing directory is checked to see if it already has a child
/// directory with the requested name. If it does, the name is slightly altered to make it unique.
/// The name is shortened if its length exceeds the configuration setting DefaultAlbumDirectoryNameLength.
/// The clean, guaranteed safe directory name is returned. No directory is actually created in the
/// file system.
/// </summary>
/// <param name="dirPath">The path, including the parent directory, in which the specified name
/// should be checked for validity (e.g. C:\mediaobjects\2006\).</param>
/// <param name="dirName">The directory name to be validated against the directory path. It should
/// represent a proposed directory name and not an actual directory that already exists in the file
/// system.</param>
/// <returns>Returns a string that can be safely used as a directory name within the path dirPath.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1818:DoNotConcatenateStringsInsideLoops")]
public static string ValidateDirectoryName(string dirPath, string dirName)
{
#region Parameter validaton
if (dirPath == null)
throw new ArgumentNullException("dirPath");
if (dirName == null)
throw new ArgumentNullException("dirName");
if (string.IsNullOrEmpty(dirPath) || string.IsNullOrEmpty(dirName))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.HelperFunctions_ValidateDirectoryName_Ex_Msg, dirPath, dirName));
}
// Test 1: Remove any characters that are not valid for directory names on the operating system.
string newDirName = HelperFunctions.RemoveInvalidDirectoryNameCharacters(dirName);
// If we end up with an empty string, resort to the default value.
if (newDirName.Length == 0)
newDirName = GalleryServerPro.Configuration.ConfigManager.GetGalleryServerProConfigSection().Core.DefaultAlbumDirectoryName;
// Test 2: Verify length is less than our max allowed length.
int maxLength = GalleryServerPro.Configuration.ConfigManager.GetGalleryServerProConfigSection().Core.DefaultAlbumDirectoryNameLength;
if (newDirName.Length > maxLength)
{
newDirName = newDirName.Substring(0, maxLength);
}
// Test 3: If the name ends in a period, delete it. This is to handle a 8.3 DOS filename compatibility issue where most/all
// trailing periods and spaces are stripped from file and folder names by Windows, a holdover from the transition from 8.3
// filenames where the dot is not stored but implied. If we did not do this, then Windows would store the directory without
// the trailing period, but Gallery Server would think it was still there. See bug # #90 for more info.
newDirName = newDirName.TrimEnd(new char[] { '.' });
#endregion
// Test 3: Check to make sure the parent directory (specified in dirPath) doesn't contain a directory with
// the new directory name (newDirName). If it does, keep altering the name until we come up with a unique one.
string newSuffix = string.Empty;
int counter = 1;
while (System.IO.Directory.Exists(System.IO.Path.Combine(dirPath, newDirName)))
{
// The parent directory already contains a child directory with our new name. We need to strip off the
// previous suffix if we added one (e.g. (1), (2), etc), generate a new suffix, and try again.
if (newSuffix.Length > 0)
{
// Remove the previous suffix we appended. Don't remove anything if this is the first time going
// through this loop (indicated by newSuffix.Length = 0).
newDirName = newDirName.Remove(newDirName.Length - newSuffix.Length);
}
// Generate the new suffix to append to the filename (e.g. "(3)")
newSuffix = string.Format(CultureInfo.InvariantCulture, "({0})", counter);
int newTotalLength = newDirName.Length + newSuffix.Length;
if (newTotalLength > maxLength)
{
// Our new name is going to be longer than our allowed max length. Remove just enough
// characters from newDirName so that the new length is equal to the max length.
int numCharactersToRemove = newTotalLength - maxLength;
newDirName = newDirName.Remove(newDirName.Length - numCharactersToRemove);
}
// Append the suffix. Place at the end for a directory.
newDirName += newSuffix;
counter++;
}
return newDirName;
}
/// <summary>
/// Ensure the specified string is a valid name for a file within the specified path. Invalid
/// characters are removed and the existing directory is checked to see if it already has a file
/// with the requested name. If it does, the name is slightly altered to make it unique.
/// The clean, guaranteed safe filename is returned. No file is actually created in the file system.
/// </summary>
/// <param name="dirPath">The path, including the parent directory, in which the specified name
/// should be checked for validity (e.g. C:\mediaobjects\2006\).</param>
/// <param name="fileName">The filename to be validated against the directory path. It should
/// represent a proposed filename and not an actual file that already exists in the file system.</param>
/// <returns>Returns a string that can be safely used as a filename within the path dirPath.</returns>
public static string ValidateFileName(string dirPath, string fileName)
{
#region Parameter validation
if (dirPath == null)
throw new ArgumentNullException("dirPath");
if (fileName == null)
throw new ArgumentNullException("fileName");
if (string.IsNullOrEmpty(dirPath) || string.IsNullOrEmpty(fileName))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.HelperFunctions_ValidateFileName_Ex_Msg1, dirPath, fileName));
}
if (!(Path.HasExtension(fileName)))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.HelperFunctions_ValidateFileName_Ex_Msg2, fileName));
}
#endregion
// Test 1: Remove any characters that are not valid for directory names on the operating system.
string newFilename = HelperFunctions.RemoveInvalidFileNameCharacters(fileName);
// It is very unlikely that the above method stripped every character from the filename, because the filenames
// should always come from existing files that are uploaded or added. But just in case it does, set a default.
if (newFilename.Length == 0)
newFilename = "DefaultFilename";
// Test 2: Verify length is less than our max allowed length.
int maxLength = GalleryServerPro.Configuration.ConfigManager.GetGalleryServerProConfigSection().DataStore.MediaObjectFileNameLength;
if (newFilename.Length > maxLength)
{
newFilename = newFilename.Substring(0, maxLength);
}
// Test 3: Check to make sure the parent directory (specified in dirPath) doesn't contain a file with
// the new filename (newFilename). If it does, keep altering the name until we come up with a unique one.
string newSuffix = string.Empty;
int counter = 1;
while (System.IO.File.Exists(System.IO.Path.Combine(dirPath, newFilename)))
{
// The parent directory already contains a file with our new name. We need to strip off the
// previous suffix if we added one (e.g. (1), (2), etc), generate a new suffix, and try again.
if (newSuffix.Length > 0)
{
// Remove the previous suffix we appended. Don't remove anything if this is the first time going
// through this loop (indicated by newSuffix.Length = 0).
string newFilenameWithoutExtension = Path.GetFileNameWithoutExtension(newFilename); // e.g. if newFilename=puppy(1).jpg, get "puppy(1)"
int indexOfSuffixToRemove = newFilenameWithoutExtension.Length - newSuffix.Length;
string newFilenameWithoutExtensionAndSuffix = newFilenameWithoutExtension.Remove(indexOfSuffixToRemove); // e.g. "puppy"
newFilename = newFilenameWithoutExtensionAndSuffix + Path.GetExtension(newFilename); // e.g. puppy.jpg
}
// Generate the new suffix to append to the filename (e.g. "(3)")
newSuffix = string.Format(CultureInfo.InvariantCulture, "({0})", counter);
int newTotalLength = newFilename.Length + newSuffix.Length;
if (newTotalLength > maxLength)
{
// Our new name is going to be longer than our allowed max length. Remove just enough
// characters from newFilename so that the new length is equal to the max length.
string newFilenameWithoutExtension = Path.GetFileNameWithoutExtension(newFilename); // e.g. if newFilename=puppy.jpg, get "puppy"
int numCharactersToRemove = newTotalLength - maxLength;
newFilename = newFilename.Remove(newFilename.Length - numCharactersToRemove);
}
// Insert the suffix just before the ".".
newFilename = newFilename.Insert(newFilename.LastIndexOf(".", StringComparison.Ordinal), newSuffix);
counter++;
}
return newFilename;
}
/// <summary>
/// Removes all characters from the specified string that are invalid for a directory name
/// for the operating system. This function uses Path.GetInvalidPathChars() so it may remove
/// different characters under different operating systems, depending on the characters returned
/// from this .NET function.
/// </summary>
/// <param name="directoryName">A string representing a proposed directory name
/// that should have all invalid characters removed.</param>
/// <returns>Removes a clean version of the directoryName parameter that has all invalid
/// characters removed.</returns>
public static string RemoveInvalidDirectoryNameCharacters(string directoryName)
{
// Set up our array of invalid characters. Path.GetInvalidPathChars() does not include the wildcard
// characters *, ?, :, \, and /, so add them manually.
char[] invalidChars = new char[(Path.GetInvalidPathChars().Length + 5)];
Path.GetInvalidPathChars().CopyTo(invalidChars, 0);
invalidChars[invalidChars.Length - 5] = '?';
invalidChars[invalidChars.Length - 4] = '*';
invalidChars[invalidChars.Length - 3] = ':';
invalidChars[invalidChars.Length - 2] = '\\';
invalidChars[invalidChars.Length - 1] = '/';
// Strip out invalid characters that make the OS puke
return Regex.Replace(directoryName, "[" + Regex.Escape(new string(invalidChars)) + "]", String.Empty);
}
/// <summary>
/// Removes all characters from the specified string that are invalid for filenames
/// for the operating system. This function uses Path.GetInvalidFileNameChars() so it may remove
/// different characters under different operating systems, depending on the characters returned
/// from this .NET function.
/// </summary>
/// <param name="fileName">A string representing a proposed filename
/// that should have all invalid characters removed.</param>
/// <returns>Removes a clean version of the filename parameter that has all invalid
/// characters removed.</returns>
public static string RemoveInvalidFileNameCharacters(string fileName)
{
// Set up our array of invalid characters. Path.InvalidPathChars does not include the wildcard
// characters *, ?, and also :, \, /, <, and >, so add them manually.
char[] invalidChars = new char[(Path.GetInvalidFileNameChars().Length + 7)];
Path.GetInvalidPathChars().CopyTo(invalidChars, 0);
invalidChars[invalidChars.Length - 7] = '>';
invalidChars[invalidChars.Length - 6] = '<';
invalidChars[invalidChars.Length - 5] = '?';
invalidChars[invalidChars.Length - 4] = '*';
invalidChars[invalidChars.Length - 3] = ':';
invalidChars[invalidChars.Length - 2] = '\\';
invalidChars[invalidChars.Length - 1] = '/';
// Strip out invalid characters that make the OS puke
return Regex.Replace(fileName, "[" + Regex.Escape(new string(invalidChars)) + "]", String.Empty);
}
///// <summary>
///// Verify that the specified file or directory name can be saved to the specified directory. Invalid
///// characters are removed and the name is changed slightly if necessary to make it unique.
///// </summary>
///// <param name="DirectoryPath">The full path of the directory (e.g. C:\mypics\vacation)</param>
///// <param name="Name">The name to test for validity.</param>
///// <param name="NameType">A value indicating whether we are generating a unique name for a file
///// or a directory.</param>
///// <returns>Returns a filename guaranteed to be valid to save to the specified directory. If no
///// changes are required to make it valid, the return value will be the same as the Name parameter.</returns>
//public static string GenerateIOName(string DirectoryPath, string Name, td.IOType NameType)
//{
// // Verify that the directory or file name specified in Name can be saved to the directory specified
// // in DirectoryPath. The NameType enum specifies whether it's a directory or file. This method performs
// // two main checks: (1) Name does not contain invalid characters (they are stripped out if present)
// // (2) Name does not already exist in the directory. If it does, append an incrementally
// // increasing integer to the name until we get a unique name. For example, if the directory
// // "SummerVacation" already exists, try "SummerVacation(1)". If that exists, try "SummerVacation(2)",
// // and so on, until we come up with a name that doesn't exist.
// // This method returns a valid name.
// string newSuffix, newName;
// int counter = 1;
// // Set up our array of invalid characters. Path.InvalidPathChars does not include the wildcard
// // characters *, ?, :, \, and /, so add them manually.
// char[] invalidChars = new char[(Path.GetInvalidPathChars().Length + 5)];
// Path.GetInvalidPathChars().CopyTo(invalidChars, 0);
// invalidChars[invalidChars.Length - 5] = '?';
// invalidChars[invalidChars.Length - 4] = '*';
// invalidChars[invalidChars.Length - 3] = ':';
// invalidChars[invalidChars.Length - 2] = '\\';
// invalidChars[invalidChars.Length - 1] = '/';
// // Strip out invalid characters that make the OS puke
// newName = Regex.Replace(Name, "[" + Regex.Escape (new string(invalidChars)) + "]", String.Empty);
// // If the above action stripped all characters out of the directory name, then create a default name.
// if (newName.Length == 0)
// newName = "DefaultName";
// // Check to make sure the parent directory (specified in DirectoryPath) doesn't contain a directory with
// // the name stored in DirectoryName. If it does, keep altering the name until we come up with a unique one.
// int originalLength = newName.Length;
// newSuffix = "";
// while ((Directory.Exists(Path.Combine(DirectoryPath, newName))) || (File.Exists(Path.Combine(DirectoryPath, newName))))
// {
// if (newSuffix.Length > 0)
// {
// // Remove the previous suffix we appended. Don't remove anything if this is the first time going
// // through this loop (indicated by newSuffix.Length = 0).
// if (NameType == td.IOType.Directory)
// newName = newName.Remove(originalLength, newName.Length - originalLength);
// else if (NameType == td.IOType.File)
// newName = newName.Remove(newName.LastIndexOf(".") - newSuffix.Length, newSuffix.Length);
// }
// newSuffix = "(" + counter.ToString() + ")";
// // Append the suffix. Place at the end for a directory, or just before the extension for a file.
// if (NameType == td.IOType.Directory)
// newName += newSuffix;
// else if (NameType == td.IOType.File)
// newName = newName.Insert(newName.LastIndexOf("."), newSuffix);
// counter++;
// }
// return newName;
//}
/// <summary>
/// Generate a hash key for the specified file. The hash key is generated from the file name and
/// its creation timestamp. The hash key is not guaranteed to be unique among media objects, since multiple
/// objects may have the same file name and creation timestamp.
/// </summary>
/// <param name="originalFile">The file for which a hash key is to be generated.</param>
/// <returns>Returns a hash key based on the file name and its creation timestamp.</returns>
public static string GetHashKey(FileSystemInfo originalFile)
{
// Return the hash key for the specified file. The hash key is generated from these
// 2 properties of a file: file name and its creation timestamp.
if (originalFile == null)
throw new ArgumentNullException("originalFile");
string input;
byte[] hashinput, hashoutput;
// Create string consisting of the file name and its creation timestamp.
input = originalFile.Name + originalFile.CreationTimeUtc.ToString(System.Globalization.DateTimeFormatInfo.InvariantInfo);
using (System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider())
{
hashinput = convertToByteArray(input);
hashoutput = md5.ComputeHash(hashinput);
}
return BitConverter.ToString(hashoutput);
}
/// <summary>
/// Generate a hash key for the specified file that is guaranteed to be unique among the media objects in the
/// data store. If an existing record with this hash key is found, update the creation date to the current
/// timestamp until a unique hash key is generated (repeating if necessary). The hash key is generated from the
/// file name and its creation timestamp.
/// </summary>
/// <param name="originalFile">The file for which a hash key is to be generated.</param>
/// <returns>Returns a hash key based on the file name and its creation timestamp.</returns>
public static string GetHashKeyUnique(FileInfo originalFile)
{
System.Collections.Specialized.StringCollection allHashKeys = MediaObjectHashKeys.Instance.HashKeys;
if (originalFile == null)
throw new ArgumentNullException("originalFile");
FileInfo fileForHashKey = originalFile;
string hashKey;
while (true)
{
hashKey = GetHashKey(fileForHashKey);
if (!allHashKeys.Contains(hashKey))
{
// We have a unique hash key, so we can break.
break;
}
// Update the creation date so, when we regenerate the hash key, it will be different (and hopefully unique).
fileForHashKey.CreationTimeUtc = DateTime.Now.ToUniversalTime();
}
System.Diagnostics.Debug.Assert(!allHashKeys.Contains(hashKey), string.Format(CultureInfo.CurrentCulture, "The singleton MediaObjectsHashKeys.Instance already contains the hash key {0}.", hashKey));
allHashKeys.Add(hashKey);
return hashKey;
}
/// <summary>
/// Return the number of occurrences of the character in the input string.
/// </summary>
/// <param name="input">The string to test.</param>
/// <param name="delimiter">The character to search for.</param>
/// <returns>The number of occurrences of the character in the input string.</returns>
public static int CountDelimiter(string input, char delimiter)
{
int count = 0;
if (input == null)
return count;
foreach (char ch in input)
{
if (ch == delimiter)
{
count++;
}
}
return count;
}
/// <summary>
/// Parse the specified string and return a valid System.Drawing.Color. The color may be specified as a
/// Hex value (e.g. "#336699", "#369"), an RGB color value (e.g. "(100,100,100)"), or one of the
/// System.Drawing.KnownColor enumeration values ("Crimson", "Maroon"). An ArgumentOutOfRangeException
/// is thrown if a color cannot be parsed from the parameter.
/// </summary>
/// <param name="colorValue">A string representing the desired color. The color may be specified as a
/// Hex value (e.g. "#336699", "#369"), an RGB color value (e.g. "(100,100,100)"), or one of the
/// System.Drawing.KnownColor enumeration values ("Crimson", "Maroon").</param>
/// <returns>Returns a System.Drawing.Color struct that matches the color specified in the parameter.</returns>
/// <exception cref="System.ArgumentNullException">Thrown when the color parameter is null.</exception>
/// <exception cref="System.ArgumentOutOfRangeException">Thrown when the color parameter cannot be converted into a known color.</exception>
public static System.Drawing.Color GetColor(string colorValue)
{
if (colorValue == null)
throw new ArgumentNullException("colorValue");
// #336699; (100, 100, 100); WhiteSmoke
string hexPattern = @"^\#[0-9A-Fa-f]{3}$|^\#[0-9A-Fa-f]{6}$";
string rgbPattern = @"^\(\d{1,3},\d{1,3},\d{1,3}\)$";
string namePattern = "^[A-Za-z]+$";
colorValue = colorValue.Replace(" ", string.Empty); // Remove all white space
System.Drawing.Color myColor;
Regex regExHex = new Regex(hexPattern);
Regex regExRgb = new Regex(rgbPattern);
Regex regExName = new Regex(namePattern);
if (regExHex.IsMatch(colorValue))
{
// Color is specified as Hex. Parse.
// If specified in 4-digit shorthand (e.g. #369), expand to full 7 digits (e.g. #336699).
if (colorValue.Length == 4)
{
colorValue = colorValue.Insert(1, colorValue.Substring(1, 1));
colorValue = colorValue.Insert(3, colorValue.Substring(3, 1));
colorValue = colorValue.Insert(5, colorValue.Substring(5, 1));
}
myColor = System.Drawing.ColorTranslator.FromHtml(colorValue.ToUpper(CultureInfo.InvariantCulture));
}
else if (regExRgb.IsMatch(colorValue))
{
// Color is specified as RGB. Parse.
string colorVal = colorValue;
// Strip the opening and closing parentheses.
colorVal = colorVal.TrimStart(new char[] { '(' });
colorVal = colorVal.TrimEnd(new char[] { ')' });
// First verify each value is a number from 0-255. (The reg ex matched 0-999).
string[] rgbStringValues = colorVal.Split(new char[] { ',' });
// Convert to integers
int[] rgbValues = new int[3];
for (int i = 0; i < rgbStringValues.Length; i++)
{
rgbValues[i] = Int32.Parse(rgbStringValues[i], CultureInfo.InvariantCulture);
if ((rgbValues[i] < 0) || (rgbValues[i] > 255))
throw new ArgumentOutOfRangeException(string.Format(CultureInfo.CurrentCulture, "The color {0} does not represent a valid RGB color.", colorValue));
}
myColor = System.Drawing.Color.FromArgb(rgbValues[0], rgbValues[1], rgbValues[2]);
}
else if (regExName.IsMatch(colorValue))
{
// Color is specified as a name. Parse.
myColor = System.Drawing.Color.FromName(colorValue);
if ((myColor.A == 0) && (myColor.R == 0) && (myColor.G == 0) && (myColor.B == 0))
throw new ArgumentOutOfRangeException(string.Format(CultureInfo.CurrentCulture, "The color {0} does not represent a color known to the .NET Framework.", colorValue));
}
else
{
throw new ArgumentOutOfRangeException(string.Format(CultureInfo.CurrentCulture, "The color {0} does not represent a valid color.", colorValue));
}
return myColor;
}
/// <summary>
/// Encrypt the specified string using the System.Security.Cryptography.TripleDESCryptoServiceProvider cryptographic
/// service provider. The secret key used in the encryption is specified in the encryptionKey configuration setting.
/// The encrypted string can be decrypted to its original string using the Decrypt function in this class.
/// </summary>
/// <param name="plainText">A plain text string to be encrypted. If the value is null or empty, the return value is
/// equal to String.Empty.</param>
/// <returns>Returns an encrypted version of the plainText parameter.</returns>
public static string Encrypt(string plainText)
{
if (String.IsNullOrEmpty(plainText))
return String.Empty;
// This method (and the Decrypt method) inspired from Code Project.
// http://www.codeproject.com/useritems/Cryptography.asp
byte[] stringToEncryptArray = System.Text.Encoding.UTF8.GetBytes(plainText);
System.Security.Cryptography.TripleDESCryptoServiceProvider tdes = new System.Security.Cryptography.TripleDESCryptoServiceProvider();
// Set the secret key for the tripleDES algorithm
byte[] keyArray;
keyArray = System.Text.Encoding.UTF8.GetBytes(ENCRYPTION_KEY);
tdes.Key = keyArray;
// Mode of operation. there are other 4 modes. We choose ECB (Electronic code Book)
tdes.Mode = System.Security.Cryptography.CipherMode.ECB;
//padding mode(if any extra byte added)
tdes.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
// Transform the specified region of bytes array to resultArray
System.Security.Cryptography.ICryptoTransform cTransform = tdes.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(stringToEncryptArray, 0, stringToEncryptArray.Length);
// Release resources held by TripleDes Encryptor
tdes.Clear();
// Return the encrypted data into unreadable string format
return Convert.ToBase64String(resultArray);
}
/// <summary>
/// Decrypt the specified string using the System.Security.Cryptography.TripleDESCryptoServiceProvider cryptographic
/// service provider. The secret key used in the decryption is specified in the encryptionKey configuration setting.
/// </summary>
/// <param name="encryptedText">A string to be decrypted. The encrypted string should have been encrypted using the
/// Encrypt function in this class. If the value is null or empty, the return value is equal to String.Empty.</param>
/// <returns>Returns the original, unencrypted string contained in the encryptedText parameter.</returns>
public static string Decrypt(string encryptedText)
{
if (String.IsNullOrEmpty(encryptedText))
return String.Empty;
// Get the byte code of the string
byte[] toEncryptArray = Convert.FromBase64String(encryptedText);
System.Security.Cryptography.TripleDESCryptoServiceProvider tdes = new System.Security.Cryptography.TripleDESCryptoServiceProvider();
// Set the secret key for the tripleDES algorithm.
tdes.Key = System.Text.Encoding.UTF8.GetBytes(ENCRYPTION_KEY);
// Mode of operation. there are other 4 modes. We choose ECB(Electronic code Book)
tdes.Mode = System.Security.Cryptography.CipherMode.ECB;
// Padding mode(if any extra byte added)
tdes.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
System.Security.Cryptography.ICryptoTransform cTransform = tdes.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
// Release resources held by TripleDes Encryptor
tdes.Clear();
// Return the Clear decrypted TEXT
return System.Text.Encoding.UTF8.GetString(resultArray);
}
/// <summary>
/// Determine the type of the gallery object (album, image, video, etc) specified by the ID. The object must exist
/// in the data store. If no gallery object is found, or a media object (image, video, etc) is found but
/// the file extension does not correspond to a supported MIME type by Gallery Server,
/// GalleryObjectType.Unknown is returned.
/// </summary>
/// <param name="id">An integer representing a gallery object that exists in the data store (album, video,
/// image, etc).</param>
/// <returns>Returns a GalleryObjectType enum indicating the type of gallery object specified by ID.</returns>
public static GalleryObjectType DetermineGalleryObjectType(int id)
{
if (id == int.MinValue)
return GalleryObjectType.Unknown;
#region Is ID a media object?
GalleryObjectType goType = DetermineMediaObjectType(id);
#endregion
#region Is ID an album?
if (goType == GalleryObjectType.Unknown)
{
// The ID does not represent a known MediaObject. Check to see if it's an album.
IDataReader dr = null;
try
{
dr = Factory.GetDataProvider().Album_GetDataReaderAlbumById(id);
while (dr.Read())
{
// If we get here, we found an album.
goType = GalleryObjectType.Album;
break;
}
}
finally
{
if (dr != null)
{
dr.Close();
dr = null;
}
}
}
#endregion
// If ID is not a media object or album that exists in the data store, return GalleryObjectType.Unknown.
return goType;
}
/// <overloads>Determine the type of the media object (image, video, audio, generic, etc) specified by the parameter(s).
/// This method returns GalleryObjectType.Unknown if no matching MIME type can be found. Guaranteed to not
/// return null.</overloads>
/// <summary>
/// Determine the type of the media object (image, video, audio, generic, etc) based on its ID.
/// This method returns GalleryObjectType.Unknown if no matching MIME type can be found. Guaranteed to not
/// return null.
/// </summary>
/// <param name="mediaObjectId">An integer representing a media object that exists in the data store. If no
/// matching media object is found, an InvalidMediaObjectException is thrown. (this will occur when no
/// matching record exists in the data store, or the ID actually represents an album ID). If a media object
/// is found, but no MIME type is declared in the configuration file that matches the file's extension,
/// GalleryObjectType.Unknown is returned.</param>
/// <returns>Returns a GalleryObjectType enum indicating the type of media object specified by the
/// mediaObjectId parameter. Guaranteed to not return null.</returns>
/// <remarks>Use this method for existing objects that have previously been added to the data store. </remarks>
/// <exception cref="GalleryServerPro.ErrorHandler.CustomExceptions.InvalidMediaObjectException">Thrown
/// when the mediaObjectId parameter does not represent an existing media object in the data store.</exception>
public static GalleryObjectType DetermineMediaObjectType(int mediaObjectId)
{
GalleryObjectType goType = GalleryObjectType.Unknown;
IMimeType mimeType = null;
int originalWidth = 0;
int originalHeight = 0;
bool hasExternalContent = false;
bool foundMediaObject = false;
using (IDataReader dr = Factory.GetDataProvider().MediaObject_GetDataReaderMediaObjectById(mediaObjectId))
{
while (dr.Read())
{
foundMediaObject = true;
string originalFilename = dr["OriginalFilename"].ToString();
originalWidth = Convert.ToInt32(dr["OriginalWidth"]);
originalHeight = Convert.ToInt32(dr["OriginalHeight"]);
mimeType = MimeType.LoadInstanceByFilePath(originalFilename);
hasExternalContent = (dr["ExternalHtmlSource"].ToString().Length > 0);
break;
}
}
if (hasExternalContent)
{
goType = GalleryObjectType.External;
}
else if (mimeType != null)
{
switch (mimeType.TypeCategory)
{
case MimeTypeCategory.Image:
// If no width or height has been assigned to the object, then it must be an image that can't be loaded into the Bitmap class,
// so assign these to the Generic object instead.
if ((originalWidth > int.MinValue) && (originalHeight > int.MinValue))
goType = GalleryObjectType.Image;
else
goType = GalleryObjectType.Generic;
break;
case MimeTypeCategory.Video: goType = GalleryObjectType.Video; break;
case MimeTypeCategory.Audio: goType = GalleryObjectType.Audio; break;
case MimeTypeCategory.Other: goType = GalleryObjectType.Generic; break;
default: throw new System.ComponentModel.InvalidEnumArgumentException(String.Format(CultureInfo.CurrentCulture, "HelperFunctions.DetermineMediaObjectType() encountered a MimeTypeCategory enumeration it does not recognize. The method may need to be updated. (Unrecognized MimeTypeCategory enumeration: MimeTypeCategory.{0})", mimeType.TypeCategory.ToString()));
}
}
else if (foundMediaObject)
{
// We have a media object but we can't tell its MIME type from the file extension (the extension probably isn't
// listed in galleryserverpro.config. Default to a Generic object.
goType = GalleryObjectType.Generic;
}
return goType;
}
/// <summary>
/// Determine the type of the media object (image, video, audio, generic, etc) based on the file's extension.
/// This method returns GalleryObjectType.Unknown if no matching MIME type can be found. Guaranteed to not
/// return null.
/// </summary>
/// <param name="fileName">A filename from which to determine its media object type. This is done by comparing
/// its file extension to the list of extensions known to Gallery Server. If the file extension
/// does not correspond to a known MIME type, GalleryObjectType.Unknown is returned.</param>
/// <returns>Returns a GalleryObjectType enum indicating the type of media object specified by the
/// filename parameter. Guaranteed to not return null.</returns>
public static GalleryObjectType DetermineMediaObjectType(string fileName)
{
GalleryObjectType goType = GalleryObjectType.Unknown;
IMimeType mimeType = MimeType.LoadInstanceByFilePath(fileName);
if (mimeType != null)
{
switch (mimeType.TypeCategory)
{
case MimeTypeCategory.Image: goType = GalleryObjectType.Image; break;
case MimeTypeCategory.Video: goType = GalleryObjectType.Video; break;
case MimeTypeCategory.Audio: goType = GalleryObjectType.Audio; break;
case MimeTypeCategory.Other: goType = GalleryObjectType.Generic; break;
default: throw new System.ComponentModel.InvalidEnumArgumentException(String.Format(CultureInfo.CurrentCulture, "HelperFunctions.DetermineMediaObjectType() encountered a MimeTypeCategory enumeration it does not recognize. The method may need to be updated. (Unrecognized MimeTypeCategory enumeration: MimeTypeCategory.{0})", mimeType.TypeCategory.ToString()));
}
}
return goType;
}
/// <summary>
/// Determine the type of the media object (image, video, audio, generic, external etc) based on whether there is
/// external HTML specified or the file's extension and the previously determined media object's width and height.
/// This method returns GalleryObjectType.Unknown if <paramref name="externalHtmlSource"/> is null or empty and no matching MIME
/// type can be found for <paramref name="fileName"/>. Guaranteed to not return null. This overload is intended to be invoked
/// when instantiating an existing media object.
/// </summary>
/// <param name="fileName">A filename from which to determine its media object type. This is done by comparing
/// its file extension to the list of extensions known to Gallery Server. If the file extension
/// does not correspond to a known MIME type, GalleryObjectType.Unknown is returned.</param>
/// <param name="originalWidth">The width, in pixels, of the original version of the file. This value is typically
/// populated from the OriginalWidth column in the table gs_MediaObject.</param>
/// <param name="originalHeight">The height, in pixels, of the original version of the file. This value is typically
/// populated from the OriginalHeight column in the table gs_MediaObject.</param>
/// <param name="externalHtmlSource">The HTML that defines an externally stored media object, such as one hosted at
/// YouTube or Silverlight.live.com.</param>
/// <returns>
/// Returns a GalleryObjectType enum indicating the type of media object. Guaranteed to not return null.
/// </returns>
public static GalleryObjectType DetermineMediaObjectType(string fileName, int originalWidth, int originalHeight, string externalHtmlSource)
{
GalleryObjectType goType = GalleryObjectType.Unknown;
if (!String.IsNullOrEmpty(externalHtmlSource))
{
goType = GalleryObjectType.External;
}
else
{
IMimeType mimeType = MimeType.LoadInstanceByFilePath(fileName);
if (mimeType != null)
{
switch (mimeType.TypeCategory)
{
case MimeTypeCategory.Image:
// If no width or height has been assigned to the object, then it must be an image that can't be loaded into the Bitmap class,
// so assign to the Generic object instead.
if ((originalWidth > int.MinValue) && (originalHeight > int.MinValue))
goType = GalleryObjectType.Image;
else
goType = GalleryObjectType.Generic;
break;
case MimeTypeCategory.Video: goType = GalleryObjectType.Video; break;
case MimeTypeCategory.Audio: goType = GalleryObjectType.Audio; break;
case MimeTypeCategory.Other: goType = GalleryObjectType.Generic; break;
default: throw new System.ComponentModel.InvalidEnumArgumentException(String.Format(CultureInfo.CurrentCulture, "HelperFunctions.DetermineMediaObjectType() encountered a MimeTypeCategory enumeration it does not recognize. The method may need to be updated. (Unrecognized MimeTypeCategory enumeration: MimeTypeCategory.{0})", mimeType.TypeCategory.ToString()));
}
}
}
return goType;
}
/// <summary>
/// Return gallery objects that match the specified search string and for which the specified user has authorization
/// to view. A gallery object is considered a match when all search terms are found in the relevant fields.
/// For albums, the title and summary fields are searched. For media objects, the title, original filename,
/// and metadata are searched. The contents of documents are not searched (e.g. the text of a Word or PDF file).
/// If no matches are found, an empty collection is returned. If the userIsAuthenticated parameter is true, only those
/// objects for which the user has authorization are returned. If userIsAuthenticated=false (i.e. the user is anonymous),
/// only non-private matching objects are returned.
/// </summary>
/// <param name="searchText">A space or comma-delimited string of search terms. Double quotes (") may be used
/// to combine more than one word into a single search term. Example: cat "0 step" Mom will search for all
/// objects that contain the strings "cat", "0 step", and "Mom".</param>
/// <param name="roles">A collection of Gallery Server roles to which the currently logged-on user belongs.
/// This parameter is ignored when userIsAuthenticated=false.</param>
/// <param name="userIsAuthenticated">A value indicating whether the current user is logged on. If true, the
/// roles parameter should contain the names of the roles for the current user. If userIsAuthenticated=true and
/// the roles parameter is either null or an empty collection, this method returns an empty collection.</param>
/// <returns>Returns a GalleryObjectCollection containing the matching items. This may include albums and media
/// objects from different albums.</returns>
public static IGalleryObjectCollection SearchGallery(string searchText, IGalleryServerRoleCollection roles, bool userIsAuthenticated)
{
string[] searchTerms = ParseSearchText(searchText);
List<int> matchingAlbumIds;
List<int> matchingMediaObjectIds;
Factory.GetDataProvider().SearchGallery(searchTerms, out matchingAlbumIds, out matchingMediaObjectIds);
IGalleryObjectCollection galleryObjects = new GalleryObjectCollection();
matchingAlbumIds.ForEach(delegate(int albumId)
{
IGalleryObject album = Factory.LoadAlbumInstance(albumId, false);
if (SecurityManager.IsUserAuthorized(SecurityActions.ViewAlbumOrMediaObject, roles, albumId, userIsAuthenticated, album.IsPrivate))
{
galleryObjects.Add(album); // All security checks OK. Add to collection.
}
});
matchingMediaObjectIds.ForEach(delegate(int mediaObjectId)
{
IGalleryObject mediaObject = Factory.LoadMediaObjectInstance(mediaObjectId);
if (SecurityManager.IsUserAuthorized(SecurityActions.ViewAlbumOrMediaObject, roles, mediaObject.Parent.Id, userIsAuthenticated, mediaObject.IsPrivate))
{
galleryObjects.Add(mediaObject); // User is authorized to view this media object.
}
});
return galleryObjects;
}
/// <summary>
/// Remove all items from cache. This includes media objects, albums, and gallery server roles.
/// </summary>
public static void PurgeCache()
{
#if DEBUG
TechInfoSystems.TracingTools.Tools.StartingMethod();
#endif
CacheManager.Remove(CacheItem.Albums.ToString());
CacheManager.Remove(CacheItem.MediaObjects.ToString());
CacheManager.Remove(CacheItem.GalleryServerRoles.ToString());
}
/// <summary>
/// Parse the albumPhysicalPath parameter to find the portion that refers to album folders below the root album, then
/// append this portion to the alternatePhysicalPath parameter and return the computed string. If alternatePhysicalPath is
/// null or empty, then return albumPhysicalPath. This is useful when mapping an album's physical location
/// to the physical location within the thumbnail and/or optimized image cache directory. For example, if an album is located
/// at C:\mypics\album1\album2, the media object root directory is at C:\mypics (specified by the mediaObjectPath configuration
/// setting), and the thumbnail directory is specified to be C:\thumbnailCache (the thumbnailPath configuration setting),
/// then return C:\thumbnailCache\album1\album2.
/// </summary>
/// <param name="albumPhysicalPath">The full physical path to an existing album. An exception is thrown if the directory is not
/// a child directory of the root media object directory (AppSetting.Instance.MediaObjectPhysicalPath). Ex: C:\mypics\album1\album2</param>
/// <param name="alternatePhysicalPath">The full physical path to a directory on the hard drive. This is typically (always?)
/// the path to either the thumbnail or optimized cache (refer to thumbnailPath and optimized configuration setting). Ex: C:\thumbnailCache
/// This parameter is optional. If not specified, the method returns the albumPhysicalPath parameter without modification.</param>
/// <returns>Returns the alternatePhysicalPath parameter with the album directory path appended. Ex: C:\thumbnailCache\album1\album2
/// If hte alternatePhysicalPath parameter is not specified, the method returns the albumPhysicalPath parameter without modification.</returns>
public static string MapAlbumDirectoryStructureToAlternateDirectory(string albumPhysicalPath, string alternatePhysicalPath)
{
if (String.IsNullOrEmpty(alternatePhysicalPath))
{
return albumPhysicalPath;
}
string moPath = AppSetting.Instance.MediaObjectPhysicalPath;
if (!albumPhysicalPath.StartsWith(moPath, StringComparison.OrdinalIgnoreCase))
throw new BusinessException(String.Format(CultureInfo.CurrentCulture, "Expected this.Parent.FullPhysicalPathOnDisk (\"{0}\") to start with AppSetting.Instance.MediaObjectPhysicalPath (\"{1}\"), but it did not.", albumPhysicalPath, moPath));
string relativePath = albumPhysicalPath.Remove(0, moPath.Length).Trim(new char[] { System.IO.Path.DirectorySeparatorChar });
return System.IO.Path.Combine(alternatePhysicalPath, relativePath);
}
/// <summary>
/// Generate a full physical path, such as "C:\inetpub\wwwroot\galleryserverpro\myimages", based on the specified parameters.
/// If relativeOrFullPath is a relative path, such as "\myimages\", append it to the physicalAppPath and return. If
/// relativeOrFullPath is a full path, such as "C:\inetpub\wwwroot\galleryserverpro\myimages", ignore the physicalAppPath
/// and return the full path. In either case, this procedure guarantees that all directory separator characters are valid
/// for the current operating system and that there is no directory separator character after the final (innermost) directory.
/// Does not verify to ensure the directory exists or that it is writeable.
/// </summary>
/// <param name="physicalAppPath">The physical path of the currently executing application.</param>
/// <param name="relativeOrFullPath">The relative or full file path. Relative paths should be relative to the root of the
/// running application so that, when it is combined with physicalAppPath parameter, it creates a valid path.
/// Examples: "C:\inetpub\wwwroot\galleryserverpro\myimages\", "C:/inetpub/wwwroot/galleryserverpro/myimages",
/// "\myimages\", "\myimages", "myimages\", "myimages", "/myimages/", "/myimages"</param>
/// <returns>Returns a full physical path, without the trailing slash. For example:
/// "C:\inetpub\wwwroot\galleryserverpro\myimages"</returns>
public static string CalculateFullPath(string physicalAppPath, string relativeOrFullPath)
{
#region Validation
if (String.IsNullOrEmpty(relativeOrFullPath))
throw new ArgumentNullException("relativeOrFullPath");
if (String.IsNullOrEmpty(physicalAppPath))
throw new ArgumentNullException("physicalAppPath");
#endregion
string fullPhysicalPath = String.Empty;
// Delete any leading or trailing slashes, and ensure all slashes are the backward ones (\).
string modifiedMediaObjectPath = relativeOrFullPath.TrimStart(new char[] { '/', Path.DirectorySeparatorChar });
modifiedMediaObjectPath = modifiedMediaObjectPath.TrimEnd(new char[] { '/', Path.DirectorySeparatorChar }).Replace("/", Path.DirectorySeparatorChar.ToString());
if (IsRelativePath(modifiedMediaObjectPath))
{
fullPhysicalPath = Path.Combine(physicalAppPath, modifiedMediaObjectPath);
}
else
{
fullPhysicalPath = modifiedMediaObjectPath;
}
return fullPhysicalPath;
}
/// <summary>
/// Validates that the specified path exists and that it is writeable. If the path does not exist, we attempt to
/// create it. Once we know it exists, we write a tiny file to it and then delete it. If that passes, we know we
/// have sufficient read/write access for Gallery Server to read/write files to the directory.
/// </summary>
/// <param name="fullPhysicalPath">The full physical path to test (e.g. "C:\inetpub\wwwroot\galleryserverpro\myimages")</param>
/// <exception cref="GalleryServerPro.ErrorHandler.CustomExceptions.CannotWriteToDirectoryException">
/// Thrown when Gallery Server Pro is unable to write to, or delete from, the path <paramref name="fullPhysicalPath"/>.</exception>
public static void ValidatePhysicalPathExistsAndIsReadWritable(string fullPhysicalPath)
{
// Create directory if it does not exist.
try
{
if (!Directory.Exists(fullPhysicalPath))
{
Directory.CreateDirectory(fullPhysicalPath);
}
}
catch (Exception ex)
{
throw new GalleryServerPro.ErrorHandler.CustomExceptions.CannotWriteToDirectoryException(fullPhysicalPath, ex);
}
// Verify the directory is writeable.
string testFilePath = String.Empty;
try
{
lock (_fileLock)
{
string uniqueFileName = ValidateFileName(fullPhysicalPath, "test.config");
testFilePath = Path.Combine(fullPhysicalPath, uniqueFileName);
using (FileStream s = File.Create(testFilePath))
{
s.WriteByte(42);
}
}
}
catch (Exception ex)
{
throw new GalleryServerPro.ErrorHandler.CustomExceptions.CannotWriteToDirectoryException(fullPhysicalPath, ex);
}
finally
{
try
{
File.Delete(testFilePath);
}
catch (Exception ex)
{
throw new GalleryServerPro.ErrorHandler.CustomExceptions.CannotWriteToDirectoryException(fullPhysicalPath, ex);
}
}
}
/// <summary>
/// Determine whether the specified file can be added to Gallery Server Pro. This is determined by first looking at the
/// AllowUnspecifiedMimeTypes configuration setting, and returns true if this setting is true. If false, the method looks
/// up the MIME type for this file from the configuration file and returns the value of the allowAddToGallery attribute.
/// If there isn't a MIME type entry for this file and AllowUnspecifiedMimeTypes = false, this method returns false.
/// </summary>
/// <param name="fileName">A name of a file that includes the extension.</param>
/// <returns>Returns true if the file can be added to Gallery Server Pro; otherwise returns false.</returns>
public static bool IsFileAuthorizedForAddingToGallery(string fileName)
{
if (GalleryServerPro.Configuration.ConfigManager.GetGalleryServerProConfigSection().Core.AllowUnspecifiedMimeTypes)
return true;
IMimeType mimeType = MimeType.LoadInstanceByFilePath(fileName);
if ((mimeType != null) && mimeType.AllowAddToGallery)
return true;
else
return false;
}
/// <summary>
/// Update the audit fields of the gallery object. This should be invoked before saving any gallery object within this
/// class library. Class libraries that use this library are responsible for updating the audit fields themselves.
/// The audit fields are: CreatedByUsername, DateAdded, LastModifiedByUsername, DateLastModified
/// </summary>
/// <param name="galleryObject">The gallery object whose audit fields are to be updated.</param>
/// <param name="userName">The user name of the currently logged on user.</param>
public static void UpdateAuditFields(IGalleryObject galleryObject, string userName)
{
DateTime currentTimestamp = DateTime.Now;
if (galleryObject.IsNew)
{
galleryObject.CreatedByUserName = userName;
galleryObject.DateAdded = currentTimestamp;
}
if (galleryObject.HasChanges)
{
galleryObject.LastModifiedByUserName = userName;
galleryObject.DateLastModified = currentTimestamp;
}
}
/// <summary>
/// Begins a new database transaction. All subsequent database actions occur within the context of this transaction.
/// Use <see cref="CommitTransaction"/> to commit this transaction or <see cref="RollbackTransaction" /> to abort it. If a transaction
/// is already in progress, then this method returns without any action, which preserves the original transaction.
/// <note type="caution">The SQLite data provider supports this method, but the SQL Server data provider does not. The
/// primary reason for this is the SQL Server provider was written first without transactions in mind, but SQLite
/// encounters serious performance degradation unless transactions are used, so transaction support was added.</note>
/// </summary>
/// <remarks>Transactions are supported only when the client is a web application.This is because the
/// transaction is stored in the HTTP context Items property. If the client is not a web application, then
/// System.Web.HttpContext.Current is null. When this happens, this method returns without taking any action.</remarks>
public static void BeginTransaction()
{
Factory.GetDataProvider().BeginTransaction();
}
/// <summary>
/// Commits the current transaction, if one exists. A transaction is created with the <see cref="BeginTransaction"/> method.
/// If there is not an existing transaction, no action is taken. If this method is called when a datareader is open, the
/// actual commit is delayed until all datareaders are disposed.
/// <note type="caution">The SQLite data provider supports this method, but the SQL Server data provider does not. The
/// primary reason for this is the SQL Server provider was written first without transactions in mind, but SQLite
/// encounters serious performance degradation unless transactions are used, so transaction support was added.</note>
/// </summary>
/// <remarks>Transactions are supported only when the client is a web application.This is because the
/// transaction is stored in the HTTP context Items property. If the client is not a web application, then
/// System.Web.HttpContext.Current is null. When this happens, this method returns without taking any action.</remarks>
public static void RollbackTransaction()
{
Factory.GetDataProvider().RollbackTransaction();
}
/// <summary>
/// Aborts the current transaction, if one exists. A transaction is created with the <see cref="BeginTransaction"/> method.
/// If there is not an existing transaction, no action is taken.
/// <note type="caution">The SQLite data provider supports this method, but the SQL Server data provider does not. The
/// primary reason for this is the SQL Server provider was written first without transactions in mind, but SQLite
/// encounters serious performance degradation unless transactions are used, so transaction support was added.</note>
/// </summary>
/// <remarks>Transactions are supported only when the client is a web application.This is because the
/// transaction is stored in the HTTP context Items property. If the client is not a web application, then
/// System.Web.HttpContext.Current is null. When this happens, this method returns without taking any action.</remarks>
public static void CommitTransaction()
{
Factory.GetDataProvider().CommitTransaction();
}
/// <summary>
/// Exports the Gallery Server Pro data in the current database to an XML file at the location specified by the <paramref name="filePath"/>
/// parameter. Does not export the actual media files; they must be copied manually with a utility such as Windows Explorer. This method
/// does not make any changes to the database tables or the files in the media objects directory.
/// </summary>
/// <param name="filePath">The full file path specifying where the XML file will be written to. If a file with the same name already
/// exists, it will first be deleted. Example: "D:\mybackups\GalleryServerBackup_2008-06-22_141336.xml".</param>
/// <param name="exportMembershipData">If set to <c>true</c>, user accounts and other membership data will be exported.</param>
/// <param name="exportGalleryData">If set to <c>true</c>, albums, media objects, and other gallery data will be exported.</param>
public static void ExportGalleryData(string filePath, bool exportMembershipData, bool exportGalleryData)
{
Factory.GetDataProvider().ExportGalleryData(filePath, exportMembershipData, exportGalleryData);
}
/// <summary>
/// Imports the Gallery Server Pro data into the current database, overwriting any existing data. Does not import the actual media
/// files; they must be imported manually with a utility such as Windows Explorer. This method makes changes only to the database tables;
/// no files in the media objects directory are affected. If both the <paramref name="importMembershipData"/> and <paramref name="importGalleryData"/>
/// parameters are false, then no action is taken.
/// </summary>
/// <param name="filePath">The full file path to the XML file containing the data (e.g. "D:\mybackups\GalleryServerBackup_2008-06-22_141336.xml").</param>
/// <param name="importMembershipData">If set to <c>true</c>, user accounts and other membership data will be imported.
/// Current membership data will first be deleted.</param>
/// <param name="importGalleryData">If set to <c>true</c>, albums, media objects, and other gallery data will be imported.
/// Current gallery data will first be deleted.</param>
public static void ImportGalleryData(string filePath, bool importMembershipData, bool importGalleryData)
{
Factory.GetDataProvider().ImportGalleryData(filePath, importMembershipData, importGalleryData);
}
/// <summary>
/// Validates that the backup file specified in the <see cref="IBackupFile.FilePath" /> property of the <paramref name="backupFile"/>
/// parameter is valid and populates the remaining properties with information about the file.
/// </summary>
/// <param name="backupFile">An instance of <see cref="IBackupFile" /> that with only the <see cref="IBackupFile.FilePath" />
/// property assigned. The remaining properties should be uninitialized since they will be assigned in this method.</param>
public static void ValidateBackupFile(IBackupFile backupFile)
{
Factory.GetDataProvider().ValidateBackupFile(ref backupFile);
}
/// <summary>
/// Create and return a deep copy of the specified object. The copy is created by serializing the object to memory and
/// then deserializing it into a new object. Returns null if the specified parameter is null.
/// </summary>
/// <typeparam name="T">The type of object for which to make a deep copy.</typeparam>
/// <param name="obj">The object for which to make a deep copy. May be null.</param>
/// <returns>Returns a deep copy of the specified parameter, or null if the parameter is null.</returns>
/// <remarks>This method requires Full Trust.</remarks>
//public static T CloneObject<T>(T obj)
//{
// // Create a memory stream and a formatter.
// using (System.IO.MemoryStream ms = new System.IO.MemoryStream(1000))
// {
// BinaryFormatter bf = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
// // Serialize the object into the stream.
// bf.Serialize(ms, obj);
// // Position stream pointer back to first byte.
// ms.Seek(0, System.IO.SeekOrigin.Begin);
// // Deserialize into another object.
// return (T) bf.Deserialize(ms);
// }
//}
#endregion
#region Public Static Properties
public static Microsoft.Practices.EnterpriseLibrary.Caching.CacheManager CacheManager
{
get
{
if (_cacheManager == null)
{
_cacheManager = Microsoft.Practices.EnterpriseLibrary.Caching.CacheFactory.GetCacheManager();
}
return _cacheManager;
}
}
#endregion
#region Private Static Methods
private static byte[] convertToByteArray(string input)
{
//Convert the string to an array of bytes. Used by the getHashKey function.
char[] chararray;
chararray = input.ToCharArray();
byte[] bytearray = new byte[chararray.Length];
for (int counter = 0; counter < bytearray.Length; counter++)
bytearray[counter] = (byte)chararray[counter];
return bytearray;
}
private static string[] ParseSearchText(string searchText)
{
List<string> searchTermsList = new List<string>();
// Extract all terms contained in quotes.
while (true)
{
int startQuoteIndex = searchText.IndexOf('"');
if (startQuoteIndex < 0) break;
int endQuoteIndex = searchText.IndexOf('"', startQuoteIndex + 1);
if (endQuoteIndex > 0)
{
searchTermsList.Add(searchText.Substring(startQuoteIndex + 1, endQuoteIndex - startQuoteIndex - 1));
searchText = searchText.Remove(startQuoteIndex, endQuoteIndex - startQuoteIndex + 1);
}
else
{
// There is only one double quote. Let's get rid of it.
searchText = searchText.Remove(startQuoteIndex, 1);
}
}
string[] searchTerms = searchText.Split(new char[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string searchTerm in searchTerms)
{
searchTermsList.Add(searchTerm);
}
return searchTermsList.ToArray();
}
private static bool IsRelativePath(string modifiedMediaObjectPath)
{
return String.IsNullOrEmpty(Path.GetPathRoot(modifiedMediaObjectPath));
}
#endregion
}
}